Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Object2.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="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/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>     * Converts 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 {Object/Array} value
66      * @param {Boolean} [recursive=false] True to traverse object recursively
67      * @return {Array}
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      * @param {Object} object The object to encode
139      * @param {Boolean} [recursive=false] Whether or not to interpret the object in recursive format.
140      * (PHP / Ruby on Rails servers and similar).
141      * @return {String} queryString
142      */
143     toQueryString: function(object, recursive) {
144         var paramObjects = [],
145             params = [],
146             i, j, ln, paramObject, value;
147
148         for (i in object) {
149             if (object.hasOwnProperty(i)) {
150                 paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
151             }
152         }
153
154         for (j = 0, ln = paramObjects.length; j &lt; ln; j++) {
155             paramObject = paramObjects[j];
156             value = paramObject.value;
157
158             if (Ext.isEmpty(value)) {
159                 value = '';
160             }
161             else if (Ext.isDate(value)) {
162                 value = Ext.Date.toString(value);
163             }
164
165             params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
166         }
167
168         return params.join('&amp;');
169     },
170
171 <span id='Ext-Object-method-fromQueryString'>    /**
172 </span>     * Converts a query string back into an object.
173      *
174      * Non-recursive:
175      *
176      *     Ext.Object.fromQueryString(foo=1&amp;bar=2); // returns {foo: 1, bar: 2}
177      *     Ext.Object.fromQueryString(foo=&amp;bar=2); // returns {foo: null, bar: 2}
178      *     Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
179      *     Ext.Object.fromQueryString(colors=red&amp;colors=green&amp;colors=blue); // returns {colors: ['red', 'green', 'blue']}
180      *
181      * Recursive:
182      *
183      *       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);
184      *     // returns
185      *     {
186      *         username: 'Jacky',
187      *         dateOfBirth: {
188      *             day: '1',
189      *             month: '2',
190      *             year: '1911'
191      *         },
192      *         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
193      *     }
194      *
195      * @param {String} queryString The query string to decode
196      * @param {Boolean} [recursive=false] Whether or not to recursively decode the string. This format is supported by
197      * PHP / Ruby on Rails servers and similar.
198      * @return {Object}
199      */
200     fromQueryString: function(queryString, recursive) {
201         var parts = queryString.replace(/^\?/, '').split('&amp;'),
202             object = {},
203             temp, components, name, value, i, ln,
204             part, j, subLn, matchedKeys, matchedName,
205             keys, key, nextKey;
206
207         for (i = 0, ln = parts.length; i &lt; ln; i++) {
208             part = parts[i];
209
210             if (part.length &gt; 0) {
211                 components = part.split('=');
212                 name = decodeURIComponent(components[0]);
213                 value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
214
215                 if (!recursive) {
216                     if (object.hasOwnProperty(name)) {
217                         if (!Ext.isArray(object[name])) {
218                             object[name] = [object[name]];
219                         }
220
221                         object[name].push(value);
222                     }
223                     else {
224                         object[name] = value;
225                     }
226                 }
227                 else {
228                     matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
229                     matchedName = name.match(/^([^\[]+)/);
230
231                     //&lt;debug error&gt;
232                     if (!matchedName) {
233                         Ext.Error.raise({
234                             sourceClass: &quot;Ext.Object&quot;,
235                             sourceMethod: &quot;fromQueryString&quot;,
236                             queryString: queryString,
237                             recursive: recursive,
238                             msg: 'Malformed query string given, failed parsing name from &quot;' + part + '&quot;'
239                         });
240                     }
241                     //&lt;/debug&gt;
242
243                     name = matchedName[0];
244                     keys = [];
245
246                     if (matchedKeys === null) {
247                         object[name] = value;
248                         continue;
249                     }
250
251                     for (j = 0, subLn = matchedKeys.length; j &lt; subLn; j++) {
252                         key = matchedKeys[j];
253                         key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
254                         keys.push(key);
255                     }
256
257                     keys.unshift(name);
258
259                     temp = object;
260
261                     for (j = 0, subLn = keys.length; j &lt; subLn; j++) {
262                         key = keys[j];
263
264                         if (j === subLn - 1) {
265                             if (Ext.isArray(temp) &amp;&amp; key === '') {
266                                 temp.push(value);
267                             }
268                             else {
269                                 temp[key] = value;
270                             }
271                         }
272                         else {
273                             if (temp[key] === undefined || typeof temp[key] === 'string') {
274                                 nextKey = keys[j+1];
275
276                                 temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
277                             }
278
279                             temp = temp[key];
280                         }
281                     }
282                 }
283             }
284         }
285
286         return object;
287     },
288
289 <span id='Ext-Object-method-each'>    /**
290 </span>     * Iterates through an object and invokes the given callback function for each iteration.
291      * The iteration can be stopped by returning `false` in the callback function. For example:
292      *
293      *     var person = {
294      *         name: 'Jacky'
295      *         hairColor: 'black'
296      *         loves: ['food', 'sleeping', 'wife']
297      *     };
298      *
299      *     Ext.Object.each(person, function(key, value, myself) {
300      *         console.log(key + &quot;:&quot; + value);
301      *
302      *         if (key === 'hairColor') {
303      *             return false; // stop the iteration
304      *         }
305      *     });
306      *
307      * @param {Object} object The object to iterate
308      * @param {Function} fn The callback function.
309      * @param {String} fn.key
310      * @param {Object} fn.value
311      * @param {Object} fn.object The object itself
312      * @param {Object} [scope] The execution scope (`this`) of the callback function
313      */
314     each: function(object, fn, scope) {
315         for (var property in object) {
316             if (object.hasOwnProperty(property)) {
317                 if (fn.call(scope || object, property, object[property], object) === false) {
318                     return;
319                 }
320             }
321         }
322     },
323
324 <span id='Ext-Object-method-merge'>    /**
325 </span>     * Merges any number of objects recursively without referencing them or their children.
326      *
327      *     var extjs = {
328      *         companyName: 'Ext JS',
329      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
330      *         isSuperCool: true
331      *         office: {
332      *             size: 2000,
333      *             location: 'Palo Alto',
334      *             isFun: true
335      *         }
336      *     };
337      *
338      *     var newStuff = {
339      *         companyName: 'Sencha Inc.',
340      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
341      *         office: {
342      *             size: 40000,
343      *             location: 'Redwood City'
344      *         }
345      *     };
346      *
347      *     var sencha = Ext.Object.merge(extjs, newStuff);
348      *
349      *     // extjs and sencha then equals to
350      *     {
351      *         companyName: 'Sencha Inc.',
352      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
353      *         isSuperCool: true
354      *         office: {
355      *             size: 30000,
356      *             location: 'Redwood City'
357      *             isFun: true
358      *         }
359      *     }
360      *
361      * @param {Object...} object Any number of objects to merge.
362      * @return {Object} merged The object that is created as a result of merging all the objects passed in.
363      */
364     merge: function(source, key, value) {
365         if (typeof key === 'string') {
366             if (value &amp;&amp; value.constructor === Object) {
367                 if (source[key] &amp;&amp; source[key].constructor === Object) {
368                     ExtObject.merge(source[key], value);
369                 }
370                 else {
371                     source[key] = Ext.clone(value);
372                 }
373             }
374             else {
375                 source[key] = value;
376             }
377
378             return source;
379         }
380
381         var i = 1,
382             ln = arguments.length,
383             object, property;
384
385         for (; i &lt; ln; i++) {
386             object = arguments[i];
387
388             for (property in object) {
389                 if (object.hasOwnProperty(property)) {
390                     ExtObject.merge(source, property, object[property]);
391                 }
392             }
393         }
394
395         return source;
396     },
397
398 <span id='Ext-Object-method-getKey'>    /**
399 </span>     * Returns the first matching key corresponding to the given value.
400      * If no matching value is found, null is returned.
401      *
402      *     var person = {
403      *         name: 'Jacky',
404      *         loves: 'food'
405      *     };
406      *
407      *     alert(Ext.Object.getKey(person, 'food')); // alerts 'loves'
408      *
409      * @param {Object} object
410      * @param {Object} value The value to find
411      */
412     getKey: function(object, value) {
413         for (var property in object) {
414             if (object.hasOwnProperty(property) &amp;&amp; object[property] === value) {
415                 return property;
416             }
417         }
418
419         return null;
420     },
421
422 <span id='Ext-Object-method-getValues'>    /**
423 </span>     * Gets all values of the given object as an array.
424      *
425      *     var values = Ext.Object.getValues({
426      *         name: 'Jacky',
427      *         loves: 'food'
428      *     }); // ['Jacky', 'food']
429      *
430      * @param {Object} object
431      * @return {Array} An array of values from the object
432      */
433     getValues: function(object) {
434         var values = [],
435             property;
436
437         for (property in object) {
438             if (object.hasOwnProperty(property)) {
439                 values.push(object[property]);
440             }
441         }
442
443         return values;
444     },
445
446 <span id='Ext-Object-method-getKeys'>    /**
447 </span>     * Gets all keys of the given object as an array.
448      *
449      *     var values = Ext.Object.getKeys({
450      *         name: 'Jacky',
451      *         loves: 'food'
452      *     }); // ['name', 'loves']
453      *
454      * @param {Object} object
455      * @return {String[]} An array of keys from the object
456      * @method
457      */
458     getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
459         var keys = [],
460             property;
461
462         for (property in object) {
463             if (object.hasOwnProperty(property)) {
464                 keys.push(property);
465             }
466         }
467
468         return keys;
469     },
470
471 <span id='Ext-Object-method-getSize'>    /**
472 </span>     * Gets the total number of this object's own properties
473      *
474      *     var size = Ext.Object.getSize({
475      *         name: 'Jacky',
476      *         loves: 'food'
477      *     }); // size equals 2
478      *
479      * @param {Object} object
480      * @return {Number} size
481      */
482     getSize: function(object) {
483         var size = 0,
484             property;
485
486         for (property in object) {
487             if (object.hasOwnProperty(property)) {
488                 size++;
489             }
490         }
491
492         return size;
493     }
494 };
495
496
497 <span id='Ext-method-merge'>/**
498 </span> * A convenient alias method for {@link Ext.Object#merge}.
499  *
500  * @member Ext
501  * @method merge
502  * @alias Ext.Object#merge
503  */
504 Ext.merge = Ext.Object.merge;
505
506 <span id='Ext-method-urlEncode'>/**
507 </span> * Alias for {@link Ext.Object#toQueryString}.
508  *
509  * @member Ext
510  * @method urlEncode
511  * @alias Ext.Object#toQueryString
512  * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString} instead
513  */
514 Ext.urlEncode = function() {
515     var args = Ext.Array.from(arguments),
516         prefix = '';
517
518     // Support for the old `pre` argument
519     if ((typeof args[1] === 'string')) {
520         prefix = args[1] + '&amp;';
521         args[1] = false;
522     }
523
524     return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
525 };
526
527 <span id='Ext-method-urlDecode'>/**
528 </span> * Alias for {@link Ext.Object#fromQueryString}.
529  *
530  * @member Ext
531  * @method urlDecode
532  * @alias Ext.Object#fromQueryString
533  * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString} instead
534  */
535 Ext.urlDecode = function() {
536     return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
537 };
538
539 })();
540 </pre>
541 </body>
542 </html>