1
+ // Nico Westerdale - 1/2004-7 - www.iconico.com
2
+
3
+ // Serializer.js
4
+
5
+ // TODO: error trapping
6
+ // TODO: Internt Explorer 4 doesn't support try-catch statements!
7
+
8
+
9
+ //Serializer object
10
+ function JSSerializer ( ) {
11
+ //properties
12
+ this . Data = null ; //this is the root for the internal SerialData object
13
+ //methods
14
+ this . Serialize = mtdSerialize ;
15
+ this . HasData = function ( ) { return this . Data ?true :false } ; //whether Data has been loaded into the Serializer
16
+ this . MaxDepth = null ;
17
+ this . CheckInfiniteLoops = true ;
18
+ //locals
19
+ var theSerializer = this ; //easier to reference later on
20
+ var currDepth = 0 ;
21
+
22
+ //TODO: Unchanged Prototype Data Exclusion
23
+ // Would be really nice to have an option to exclude the data that's in the prototype.
24
+ // This is a little tricky to accomplish so I'm going to leave it for v2.0
25
+ // You have to check prototype inheritance situations like this one:
26
+ // Monkey.prototype = new Ape();
27
+ // Monkey.prototype.constructor = Monkey;
28
+ // And to compund the problem, Ape could also inherit, so it needs to be recursive.
29
+ // This is further confused by properties being set in the prototypes too.
30
+
31
+ //TODO:
32
+ //this.GetJSDataSerialString <- this should be a JSON string - then write a method to seed data back in!
33
+ // also do this from XML, should be easy to write a simple parser etc.
34
+ //TODO: also make this into a Javascript HTML code colorizer = use CSS for the display
35
+
36
+
37
+ //serializes any Javascript object and returns a string
38
+ function mtdSerialize ( obj ) {
39
+ if ( IsSerializable ( 'SrliZe' , obj ) ) {
40
+ //Set root SerialData object to be the root object passed in to be serialized
41
+ // We give it the default name 'SrliZe'
42
+ this . Data = new SerialData ( 'SrliZe' , obj , null ) ;
43
+ //Start serializing entire tree
44
+ SerializeAll ( obj , this . Data ) ;
45
+ //Return true because we could serialize something
46
+ return true ;
47
+ //TODO: Should keep track of whether we could serialize the entire tree.
48
+ } else {
49
+ //Couldn't serialize anything
50
+ return false ;
51
+ }
52
+ }
53
+
54
+ //Private functions
55
+
56
+
57
+ //recursive serialization function
58
+ function SerializeAll ( obj , objParent ) {
59
+
60
+ currDepth ++ ;
61
+ //depth check
62
+ if ( ( theSerializer . MaxDepth == null ) || ( theSerializer . MaxDepth == '' ) || ( theSerializer . MaxDepth < 0 ) || ( currDepth <= theSerializer . MaxDepth ) ) {
63
+ var i ;
64
+ var objSerial ;
65
+ var blnDidForIn = false ;
66
+ //loop through items
67
+ try {
68
+ for ( i in obj ) {
69
+ SerializeItem ( i , obj , objParent ) ;
70
+ blnDidForIn = true ;
71
+ }
72
+ } catch ( e ) {
73
+ //some DOM container objects throw enumeration errors here, i.e. the extrnal object
74
+ }
75
+ //alternate enumeration for objects.
76
+ // Objects like the 'arguments' object need this type of enumeration
77
+ if ( ! blnDidForIn ) {
78
+ if ( obj ) {
79
+ if ( obj . length && ( GetExactType ( obj ) == 'Object' ) ) {
80
+ for ( var i = 0 ; i < obj . length ; i ++ ) {
81
+ SerializeItem ( i , obj , objParent ) ;
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ }
88
+ currDepth -- ;
89
+ }
90
+
91
+ //serializes an individual item
92
+ function SerializeItem ( i , obj , objParent ) {
93
+ //for now we're going to ignore non-serializable objects
94
+ if ( IsSerializable ( i , obj [ i ] ) ) {
95
+ //build the SerialData object to encapsulate this item
96
+ objSerial = new SerialData ( i , obj [ i ] , objParent ) ;
97
+ //assign this item to it's parent's Kids array
98
+ objParent . Kids [ objParent . Kids . length ] = objSerial ;
99
+ //check infinite loops
100
+ if ( theSerializer . CheckInfiniteLoops ) {
101
+ //save the actual object, this is used to check links
102
+ objSerial . RealObject = obj [ i ] ;
103
+ //TODO: Might want to delete these after serializing object is complete
104
+ //Add any links to ancestors
105
+ objSerial . Link = findSerialLink ( objSerial ) ;
106
+ }
107
+ //recurse down the object tree if container object and not a linked object
108
+ if ( ( IsContainerType ( obj [ i ] ) ) && ( objSerial . Link == null ) ) {
109
+ SerializeAll ( obj [ i ] , objSerial )
110
+ }
111
+ }
112
+ }
113
+
114
+ //returns an ancestor object if it's identical to this one
115
+ function findSerialLink ( objSerial ) {
116
+ //check parents to see if they are the same object as this
117
+ var obj = objSerial ;
118
+ blnDidCheck = false ;
119
+ try {
120
+ while ( ( obj . Parent != null ) && ( obj . Parent . RealObject != objSerial . RealObject ) ) {
121
+ blnDidCheck = true ;
122
+ obj = obj . Parent ;
123
+ }
124
+ } catch ( e ) {
125
+ return null ; //Some DOM objects throw errors when trying to equate obj.Parent.RealObject!
126
+ }
127
+ //return object
128
+ if ( blnDidCheck ) {
129
+ return obj . Parent ;
130
+ } else {
131
+ return null ;
132
+ }
133
+ }
134
+
135
+ //Returns the type of an object from the constructor as a string
136
+ function GetExactType ( obj ) {
137
+ try {
138
+ if ( obj . constructor ) {
139
+ var strType ;
140
+ strType = obj . constructor . toString ( ) . match ( / f u n c t i o n ( \w * ) / ) [ 1 ] ;
141
+ if ( strType . replace ( ' ' , '' ) == '' ) strType = 'n/a' ; //Mozilla needs this
142
+ if ( theSerializer . Types . UseObjectsForUserDefined && ! ( strType in oc ( [ 'Array' , 'Boolean' , 'Date' , 'Enumerator' , 'Error' , 'Function' , 'Number' , 'RegExp' , 'String' , 'VBArray' ] ) ) ) {
143
+ strType = 'Object' ;
144
+ }
145
+ return strType ;
146
+ } else {
147
+ return 'n/a' ;
148
+ }
149
+ } catch ( e ) {
150
+ return 'n/a' ;
151
+ }
152
+ }
153
+
154
+ //Object converter function
155
+ function oc ( a ) {
156
+ var o = { } ;
157
+ for ( var i = 0 ; i < a . length ; i ++ ) {
158
+ o [ a [ i ] ] = '' ;
159
+ }
160
+ return o ;
161
+ }
162
+
163
+ //Returns true if the javascript object can be expanded.
164
+ function IsContainerType ( obj ) {
165
+ try {
166
+ //return (GetExactType(obj) != 'Boolean' && GetExactType(obj) != 'Date' && GetExactType(obj) != 'Enumerator' && GetExactType(obj) != 'Function' && GetExactType(obj) != 'Number' && GetExactType(obj) != 'RegExp' && GetExactType(obj) != 'String' && GetExactType(obj) != 'VBArray' && GetExactType(obj) != null && GetExactType(obj) !== undefined && GetExactType(obj) != 'n/a')
167
+ return ( GetExactType ( obj ) != 'Boolean' && GetExactType ( obj ) != 'Date' && GetExactType ( obj ) != 'Enumerator' && GetExactType ( obj ) != 'Function' && GetExactType ( obj ) != 'Number' && GetExactType ( obj ) != 'RegExp' && GetExactType ( obj ) != 'String' && GetExactType ( obj ) != 'VBArray' && GetExactType ( obj ) != null && GetExactType ( obj ) !== undefined )
168
+ } catch ( e ) {
169
+ return false ;
170
+ }
171
+ }
172
+
173
+ //Returns true if the object can be serialized.
174
+ //Returns false if the object cannot
175
+ function IsSerializable ( strName , obj ) {
176
+ try {
177
+ //check Types to see what we should serialize
178
+ switch ( GetExactType ( obj ) ) {
179
+ case 'n/a' :
180
+ if ( obj == undefined ) {
181
+ return theSerializer . Types . UseUndefined ;
182
+ } else {
183
+ return theSerializer . Types . UseNull ;
184
+ }
185
+ break ;
186
+ case 'Array' : return theSerializer . Types . UseArray ; break ;
187
+ case 'Object' : return theSerializer . Types . UseObject ; break ;
188
+ case 'Boolean' : return theSerializer . Types . UseBoolean ; break ;
189
+ case 'Date' : return theSerializer . Types . UseDate ; break ;
190
+ case 'Enumerator' : return false ; break ; // - this can't ever be serialized!
191
+ case 'Error' : return theSerializer . Types . UseError ; break ;
192
+ case 'Function' :
193
+ if ( strName == 'constructor' ) {
194
+ //Check that this isn't the object's constructor, which we never serialize.
195
+ //This is only neccesary in Mozilla.
196
+ return false ;
197
+ } else {
198
+ return theSerializer . Types . UseFunction ;
199
+ }
200
+ break ;
201
+ case 'Number' : return theSerializer . Types . UseNumber ; break ;
202
+ case 'RegExp' : return theSerializer . Types . UseRegExp ; break ;
203
+ case 'String' : return theSerializer . Types . UseString ; break ;
204
+ case 'VBArray' : return false ; break ; // - this can't ever be serialized!
205
+ default : return theSerializer . Types . UseUserDefined ; break ;
206
+ }
207
+
208
+ } catch ( e ) {
209
+ return false ;
210
+ }
211
+ }
212
+
213
+ //Constructor
214
+ //The SerialData object is used internally by the serializer to maintain the object in it's hierarchy
215
+ //This object's properties (apart from Kids) are all meant to be read-only after it's constructed.
216
+ function SerialData ( strName , obj , objParent ) {
217
+ //properties
218
+ this . Name = strName ; //This is the name of the object or property or method.
219
+ //This is the value of the property. This can be of any type.
220
+ if ( obj != null ) {
221
+ try {
222
+ if ( obj . toString ) { //If we use a DOM object some nodes fail here, e.g. the namespaces collection
223
+ this . Value = obj . toString ( ) ; //We save the string representation of the object
224
+ }
225
+ } catch ( e ) { } //Some DOM objects throw errors on obj.toString!
226
+ } else {
227
+ this . Value = obj ; //This could be either null or undefined
228
+ }
229
+ //Used for checking infinite loops
230
+ this . RealObject = null ;
231
+ //the type of the object retrieved from using typeof()
232
+ this . Type = typeof ( obj ) ;
233
+ //the name of the constructor of the object
234
+ this . ExactType = GetExactType ( obj ) ;
235
+ //Whether the object is of a type that has kids
236
+ this . IsContainer = IsContainerType ( obj ) ;
237
+ //points to the parent SerialData object. Top level SerialData object will have null parent
238
+ this . Parent = objParent ;
239
+ //array of child SerialData objects
240
+ this . Kids = new Array ;
241
+ //link to an ancestor SerialData object, where appropriate
242
+ this . Link = null ;
243
+ }
244
+
245
+
246
+ }
247
+
248
+ JSSerializer . prototype . Prefs = new SerialPrefs ( ) ;
249
+
250
+ //Constructor
251
+ //The SerialPrefs object is used for output rendering preferences
252
+ // Different formatter objects may add properties to the SerialPrefs object
253
+ function SerialPrefs ( ) {
254
+ //properties
255
+ this . ShowLineBreaks = false ; //Whether to render line breaks in formatter output
256
+ this . SmartIndent = false ; //Whether to insert tabs in output based on hierarchy. Used by XML formatters mainly.
257
+ this . ShowTypes = false ; //Whether to show the data types in the output. Used by XML formatters mainly.
258
+ //TODO: this.ShowErrors = false; //Whether to show javascript errors or fail gracefully
259
+ }
260
+
261
+ JSSerializer . prototype . Types = new SerialTypes ( ) ;
262
+
263
+ //Constructor
264
+ //The SerialTypes object is used for runtime choices of which types of objects should be serialized
265
+ function SerialTypes ( ) {
266
+ //properties
267
+ this . UseNull = true ;
268
+ this . UseUndefined = true ;
269
+ this . UseArray = true ;
270
+ this . UseObject = true ;
271
+ this . UseBoolean = true ;
272
+ this . UseDate = true ;
273
+ this . UseError = true ;
274
+ this . UseFunction = true ;
275
+ this . UseNumber = true ;
276
+ this . UseRegExp = true ;
277
+ this . UseString = true ;
278
+ this . UseUserDefined = true ; //this will be for user defined objects
279
+ this . UseObjectsForUserDefined = false ;
280
+ }
0 commit comments