Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / Object.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-Object'>/**
19 </span> * @author Jacky Nguyen &lt;jacky@sencha.com&gt;
20  * @docauthor Jacky Nguyen &lt;jacky@sencha.com&gt;
21  * @class Ext.Object
22  *
23  * A collection of useful static methods to deal with objects
24  *
25  * @singleton
26  */
27
28 (function() {
29
30 var ExtObject = Ext.Object = {
31
32 <span id='Ext-Object-method-toQueryObjects'>    /**
33 </span>     * Convert a `name` - `value` pair to an array of objects with support for nested structures; useful to construct
34      * query strings. For example:
35
36     var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
37
38     // objects then equals:
39     [
40         { name: 'hobbies', value: 'reading' },
41         { name: 'hobbies', value: 'cooking' },
42         { name: 'hobbies', value: 'swimming' },
43     ];
44
45     var objects = Ext.Object.toQueryObjects('dateOfBirth', {
46         day: 3,
47         month: 8,
48         year: 1987,
49         extra: {
50             hour: 4
51             minute: 30
52         }
53     }, true); // Recursive
54
55     // objects then equals:
56     [
57         { name: 'dateOfBirth[day]', value: 3 },
58         { name: 'dateOfBirth[month]', value: 8 },
59         { name: 'dateOfBirth[year]', value: 1987 },
60         { name: 'dateOfBirth[extra][hour]', value: 4 },
61         { name: 'dateOfBirth[extra][minute]', value: 30 },
62     ];
63
64      * @param {String} name
65      * @param {Mixed} value
66      * @param {Boolean} recursive
67      * @markdown
68      */
69     toQueryObjects: function(name, value, recursive) {
70         var self = ExtObject.toQueryObjects,
71             objects = [],
72             i, ln;
73
74         if (Ext.isArray(value)) {
75             for (i = 0, ln = value.length; i &lt; ln; i++) {
76                 if (recursive) {
77                     objects = objects.concat(self(name + '[' + i + ']', value[i], true));
78                 }
79                 else {
80                     objects.push({
81                         name: name,
82                         value: value[i]
83                     });
84                 }
85             }
86         }
87         else if (Ext.isObject(value)) {
88             for (i in value) {
89                 if (value.hasOwnProperty(i)) {
90                     if (recursive) {
91                         objects = objects.concat(self(name + '[' + i + ']', value[i], true));
92                     }
93                     else {
94                         objects.push({
95                             name: name,
96                             value: value[i]
97                         });
98                     }
99                 }
100             }
101         }
102         else {
103             objects.push({
104                 name: name,
105                 value: value
106             });
107         }
108
109         return objects;
110     },
111
112 <span id='Ext-Object-method-toQueryString'>    /**
113 </span>     * Takes an object and converts it to an encoded query string
114
115 - Non-recursive:
116
117     Ext.Object.toQueryString({foo: 1, bar: 2}); // returns &quot;foo=1&amp;bar=2&quot;
118     Ext.Object.toQueryString({foo: null, bar: 2}); // returns &quot;foo=&amp;bar=2&quot;
119     Ext.Object.toQueryString({'some price': '$300'}); // returns &quot;some%20price=%24300&quot;
120     Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns &quot;date=%222011-01-01T00%3A00%3A00%22&quot;
121     Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns &quot;colors=red&amp;colors=green&amp;colors=blue&quot;
122
123 - Recursive:
124
125     Ext.Object.toQueryString({
126         username: 'Jacky',
127         dateOfBirth: {
128             day: 1,
129             month: 2,
130             year: 1911
131         },
132         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
133     }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
134               // username=Jacky
135               //    &amp;dateOfBirth[day]=1&amp;dateOfBirth[month]=2&amp;dateOfBirth[year]=1911
136               //    &amp;hobbies[0]=coding&amp;hobbies[1]=eating&amp;hobbies[2]=sleeping&amp;hobbies[3][0]=nested&amp;hobbies[3][1]=stuff
137
138      *
139      * @param {Object} object The object to encode
140      * @param {Boolean} recursive (optional) Whether or not to interpret the object in recursive format.
141      * (PHP / Ruby on Rails servers and similar). Defaults to false
142      * @return {String} queryString
143      * @markdown
144      */
145     toQueryString: function(object, recursive) {
146         var paramObjects = [],
147             params = [],
148             i, j, ln, paramObject, value;
149
150         for (i in object) {
151             if (object.hasOwnProperty(i)) {
152                 paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
153             }
154         }
155
156         for (j = 0, ln = paramObjects.length; j &lt; ln; j++) {
157             paramObject = paramObjects[j];
158             value = paramObject.value;
159
160             if (Ext.isEmpty(value)) {
161                 value = '';
162             }
163             else if (Ext.isDate(value)) {
164                 value = Ext.Date.toString(value);
165             }
166
167             params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
168         }
169
170         return params.join('&amp;');
171     },
172
173 <span id='Ext-Object-method-fromQueryString'>    /**
174 </span>     * Converts a query string back into an object.
175      *
176 - Non-recursive:
177
178     Ext.Object.fromQueryString(foo=1&amp;bar=2); // returns {foo: 1, bar: 2}
179     Ext.Object.fromQueryString(foo=&amp;bar=2); // returns {foo: null, bar: 2}
180     Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
181     Ext.Object.fromQueryString(colors=red&amp;colors=green&amp;colors=blue); // returns {colors: ['red', 'green', 'blue']}
182
183 - Recursive:
184
185     Ext.Object.fromQueryString(&quot;username=Jacky&amp;dateOfBirth[day]=1&amp;dateOfBirth[month]=2&amp;dateOfBirth[year]=1911&amp;hobbies[0]=coding&amp;hobbies[1]=eating&amp;hobbies[2]=sleeping&amp;hobbies[3][0]=nested&amp;hobbies[3][1]=stuff&quot;, true);
186
187     // returns
188     {
189         username: 'Jacky',
190         dateOfBirth: {
191             day: '1',
192             month: '2',
193             year: '1911'
194         },
195         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
196     }
197
198      * @param {String} queryString The query string to decode
199      * @param {Boolean} recursive (Optional) Whether or not to recursively decode the string. This format is supported by
200      * PHP / Ruby on Rails servers and similar. Defaults to false
201      * @return {Object}
202      */
203     fromQueryString: function(queryString, recursive) {
204         var parts = queryString.replace(/^\?/, '').split('&amp;'),
205             object = {},
206             temp, components, name, value, i, ln,
207             part, j, subLn, matchedKeys, matchedName,
208             keys, key, nextKey;
209
210         for (i = 0, ln = parts.length; i &lt; ln; i++) {
211             part = parts[i];
212
213             if (part.length &gt; 0) {
214                 components = part.split('=');
215                 name = decodeURIComponent(components[0]);
216                 value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
217
218                 if (!recursive) {
219                     if (object.hasOwnProperty(name)) {
220                         if (!Ext.isArray(object[name])) {
221                             object[name] = [object[name]];
222                         }
223
224                         object[name].push(value);
225                     }
226                     else {
227                         object[name] = value;
228                     }
229                 }
230                 else {
231                     matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
232                     matchedName = name.match(/^([^\[]+)/);
233
234                     //&lt;debug error&gt;
235                     if (!matchedName) {
236                         Ext.Error.raise({
237                             sourceClass: &quot;Ext.Object&quot;,
238                             sourceMethod: &quot;fromQueryString&quot;,
239                             queryString: queryString,
240                             recursive: recursive,
241                             msg: 'Malformed query string given, failed parsing name from &quot;' + part + '&quot;'
242                         });
243                     }
244                     //&lt;/debug&gt;
245
246                     name = matchedName[0];
247                     keys = [];
248
249                     if (matchedKeys === null) {
250                         object[name] = value;
251                         continue;
252                     }
253
254                     for (j = 0, subLn = matchedKeys.length; j &lt; subLn; j++) {
255                         key = matchedKeys[j];
256                         key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
257                         keys.push(key);
258                     }
259
260                     keys.unshift(name);
261
262                     temp = object;
263
264                     for (j = 0, subLn = keys.length; j &lt; subLn; j++) {
265                         key = keys[j];
266
267                         if (j === subLn - 1) {
268                             if (Ext.isArray(temp) &amp;&amp; key === '') {
269                                 temp.push(value);
270                             }
271                             else {
272                                 temp[key] = value;
273                             }
274                         }
275                         else {
276                             if (temp[key] === undefined || typeof temp[key] === 'string') {
277                                 nextKey = keys[j+1];
278
279                                 temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
280                             }
281
282                             temp = temp[key];
283                         }
284                     }
285                 }
286             }
287         }
288
289         return object;
290     },
291
292 <span id='Ext-Object-method-each'>    /**
293 </span>     * Iterate through an object and invoke the given callback function for each iteration. The iteration can be stop
294      * by returning `false` in the callback function. For example:
295
296     var person = {
297         name: 'Jacky'
298         hairColor: 'black'
299         loves: ['food', 'sleeping', 'wife']
300     };
301
302     Ext.Object.each(person, function(key, value, myself) {
303         console.log(key + &quot;:&quot; + value);
304
305         if (key === 'hairColor') {
306             return false; // stop the iteration
307         }
308     });
309
310      * @param {Object} object The object to iterate
311      * @param {Function} fn The callback function. Passed arguments for each iteration are:
312
313 - {String} `key`
314 - {Mixed} `value`
315 - {Object} `object` The object itself
316
317      * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
318      * @markdown
319      */
320     each: function(object, fn, scope) {
321         for (var property in object) {
322             if (object.hasOwnProperty(property)) {
323                 if (fn.call(scope || object, property, object[property], object) === false) {
324                     return;
325                 }
326             }
327         }
328     },
329
330 <span id='Ext-Object-method-merge'>    /**
331 </span>     * Merges any number of objects recursively without referencing them or their children.
332
333     var extjs = {
334         companyName: 'Ext JS',
335         products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
336         isSuperCool: true
337         office: {
338             size: 2000,
339             location: 'Palo Alto',
340             isFun: true
341         }
342     };
343
344     var newStuff = {
345         companyName: 'Sencha Inc.',
346         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
347         office: {
348             size: 40000,
349             location: 'Redwood City'
350         }
351     };
352
353     var sencha = Ext.Object.merge(extjs, newStuff);
354
355     // extjs and sencha then equals to
356     {
357         companyName: 'Sencha Inc.',
358         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
359         isSuperCool: true
360         office: {
361             size: 30000,
362             location: 'Redwood City'
363             isFun: true
364         }
365     }
366
367      * @param {Object} object,...
368      * @return {Object} merged The object that is created as a result of merging all the objects passed in.
369      * @markdown
370      */
371     merge: function(source, key, value) {
372         if (typeof key === 'string') {
373             if (value &amp;&amp; value.constructor === Object) {
374                 if (source[key] &amp;&amp; source[key].constructor === Object) {
375                     ExtObject.merge(source[key], value);
376                 }
377                 else {
378                     source[key] = Ext.clone(value);
379                 }
380             }
381             else {
382                 source[key] = value;
383             }
384
385             return source;
386         }
387
388         var i = 1,
389             ln = arguments.length,
390             object, property;
391
392         for (; i &lt; ln; i++) {
393             object = arguments[i];
394
395             for (property in object) {
396                 if (object.hasOwnProperty(property)) {
397                     ExtObject.merge(source, property, object[property]);
398                 }
399             }
400         }
401
402         return source;
403     },
404
405 <span id='Ext-Object-method-getKey'>    /**
406 </span>     * Returns the first matching key corresponding to the given value.
407      * If no matching value is found, null is returned.
408
409     var person = {
410         name: 'Jacky',
411         loves: 'food'
412     };
413
414     alert(Ext.Object.getKey(sencha, 'loves')); // alerts 'food'
415
416      * @param {Object} object
417      * @param {Object} value The value to find
418      * @markdown
419      */
420     getKey: function(object, value) {
421         for (var property in object) {
422             if (object.hasOwnProperty(property) &amp;&amp; object[property] === value) {
423                 return property;
424             }
425         }
426
427         return null;
428     },
429
430 <span id='Ext-Object-method-getValues'>    /**
431 </span>     * Gets all values of the given object as an array.
432
433     var values = Ext.Object.getValues({
434         name: 'Jacky',
435         loves: 'food'
436     }); // ['Jacky', 'food']
437
438      * @param {Object} object
439      * @return {Array} An array of values from the object
440      * @markdown
441      */
442     getValues: function(object) {
443         var values = [],
444             property;
445
446         for (property in object) {
447             if (object.hasOwnProperty(property)) {
448                 values.push(object[property]);
449             }
450         }
451
452         return values;
453     },
454
455 <span id='Ext-Object-method-getKeys'>    /**
456 </span>     * Gets all keys of the given object as an array.
457
458     var values = Ext.Object.getKeys({
459         name: 'Jacky',
460         loves: 'food'
461     }); // ['name', 'loves']
462
463      * @param {Object} object
464      * @return {Array} An array of keys from the object
465      * @method
466      */
467     getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
468         var keys = [],
469             property;
470
471         for (property in object) {
472             if (object.hasOwnProperty(property)) {
473                 keys.push(property);
474             }
475         }
476
477         return keys;
478     },
479
480 <span id='Ext-Object-method-getSize'>    /**
481 </span>     * Gets the total number of this object's own properties
482
483     var size = Ext.Object.getSize({
484         name: 'Jacky',
485         loves: 'food'
486     }); // size equals 2
487
488      * @param {Object} object
489      * @return {Number} size
490      * @markdown
491      */
492     getSize: function(object) {
493         var size = 0,
494             property;
495
496         for (property in object) {
497             if (object.hasOwnProperty(property)) {
498                 size++;
499             }
500         }
501
502         return size;
503     }
504 };
505
506
507 <span id='Ext-method-merge'>/**
508 </span> * A convenient alias method for {@link Ext.Object#merge}
509  *
510  * @member Ext
511  * @method merge
512  */
513 Ext.merge = Ext.Object.merge;
514
515 <span id='Ext-method-urlEncode'>/**
516 </span> * A convenient alias method for {@link Ext.Object#toQueryString}
517  *
518  * @member Ext
519  * @method urlEncode
520  * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString Ext.Object.toQueryString} instead
521  */
522 Ext.urlEncode = function() {
523     var args = Ext.Array.from(arguments),
524         prefix = '';
525
526     // Support for the old `pre` argument
527     if ((typeof args[1] === 'string')) {
528         prefix = args[1] + '&amp;';
529         args[1] = false;
530     }
531
532     return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
533 };
534
535 <span id='Ext-method-urlDecode'>/**
536 </span> * A convenient alias method for {@link Ext.Object#fromQueryString}
537  *
538  * @member Ext
539  * @method urlDecode
540  * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString Ext.Object.fromQueryString} instead
541  */
542 Ext.urlDecode = function() {
543     return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
544 };
545
546 })();
547 </pre>
548 </body>
549 </html>