3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @author Jacky Nguyen <jacky@sencha.com>
17 * @docauthor Jacky Nguyen <jacky@sencha.com>
20 * A collection of useful static methods to deal with objects
27 var ExtObject = Ext.Object = {
30 * Convert a `name` - `value` pair to an array of objects with support for nested structures; useful to construct
31 * query strings. For example:
33 var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
35 // objects then equals:
37 { name: 'hobbies', value: 'reading' },
38 { name: 'hobbies', value: 'cooking' },
39 { name: 'hobbies', value: 'swimming' },
42 var objects = Ext.Object.toQueryObjects('dateOfBirth', {
50 }, true); // Recursive
52 // objects then equals:
54 { name: 'dateOfBirth[day]', value: 3 },
55 { name: 'dateOfBirth[month]', value: 8 },
56 { name: 'dateOfBirth[year]', value: 1987 },
57 { name: 'dateOfBirth[extra][hour]', value: 4 },
58 { name: 'dateOfBirth[extra][minute]', value: 30 },
61 * @param {String} name
62 * @param {Mixed} value
63 * @param {Boolean} recursive
66 toQueryObjects: function(name, value, recursive) {
67 var self = ExtObject.toQueryObjects,
71 if (Ext.isArray(value)) {
72 for (i = 0, ln = value.length; i < ln; i++) {
74 objects = objects.concat(self(name + '[' + i + ']', value[i], true));
84 else if (Ext.isObject(value)) {
86 if (value.hasOwnProperty(i)) {
88 objects = objects.concat(self(name + '[' + i + ']', value[i], true));
110 * Takes an object and converts it to an encoded query string
114 Ext.Object.toQueryString({foo: 1, bar: 2}); // returns "foo=1&bar=2"
115 Ext.Object.toQueryString({foo: null, bar: 2}); // returns "foo=&bar=2"
116 Ext.Object.toQueryString({'some price': '$300'}); // returns "some%20price=%24300"
117 Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns "date=%222011-01-01T00%3A00%3A00%22"
118 Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns "colors=red&colors=green&colors=blue"
122 Ext.Object.toQueryString({
129 hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
130 }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
132 // &dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911
133 // &hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff
136 * @param {Object} object The object to encode
137 * @param {Boolean} recursive (optional) Whether or not to interpret the object in recursive format.
138 * (PHP / Ruby on Rails servers and similar). Defaults to false
139 * @return {String} queryString
142 toQueryString: function(object, recursive) {
143 var paramObjects = [],
145 i, j, ln, paramObject, value;
148 if (object.hasOwnProperty(i)) {
149 paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
153 for (j = 0, ln = paramObjects.length; j < ln; j++) {
154 paramObject = paramObjects[j];
155 value = paramObject.value;
157 if (Ext.isEmpty(value)) {
160 else if (Ext.isDate(value)) {
161 value = Ext.Date.toString(value);
164 params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
167 return params.join('&');
171 * Converts a query string back into an object.
175 Ext.Object.fromQueryString(foo=1&bar=2); // returns {foo: 1, bar: 2}
176 Ext.Object.fromQueryString(foo=&bar=2); // returns {foo: null, bar: 2}
177 Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
178 Ext.Object.fromQueryString(colors=red&colors=green&colors=blue); // returns {colors: ['red', 'green', 'blue']}
182 Ext.Object.fromQueryString("username=Jacky&dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911&hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff", true);
192 hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
195 * @param {String} queryString The query string to decode
196 * @param {Boolean} recursive (Optional) Whether or not to recursively decode the string. This format is supported by
197 * PHP / Ruby on Rails servers and similar. Defaults to false
200 fromQueryString: function(queryString, recursive) {
201 var parts = queryString.replace(/^\?/, '').split('&'),
203 temp, components, name, value, i, ln,
204 part, j, subLn, matchedKeys, matchedName,
207 for (i = 0, ln = parts.length; i < ln; i++) {
210 if (part.length > 0) {
211 components = part.split('=');
212 name = decodeURIComponent(components[0]);
213 value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
216 if (object.hasOwnProperty(name)) {
217 if (!Ext.isArray(object[name])) {
218 object[name] = [object[name]];
221 object[name].push(value);
224 object[name] = value;
228 matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
229 matchedName = name.match(/^([^\[]+)/);
234 sourceClass: "Ext.Object",
235 sourceMethod: "fromQueryString",
236 queryString: queryString,
237 recursive: recursive,
238 msg: 'Malformed query string given, failed parsing name from "' + part + '"'
243 name = matchedName[0];
246 if (matchedKeys === null) {
247 object[name] = value;
251 for (j = 0, subLn = matchedKeys.length; j < subLn; j++) {
252 key = matchedKeys[j];
253 key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
261 for (j = 0, subLn = keys.length; j < subLn; j++) {
264 if (j === subLn - 1) {
265 if (Ext.isArray(temp) && key === '') {
273 if (temp[key] === undefined || typeof temp[key] === 'string') {
276 temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
290 * Iterate through an object and invoke the given callback function for each iteration. The iteration can be stop
291 * by returning `false` in the callback function. For example:
296 loves: ['food', 'sleeping', 'wife']
299 Ext.Object.each(person, function(key, value, myself) {
300 console.log(key + ":" + value);
302 if (key === 'hairColor') {
303 return false; // stop the iteration
307 * @param {Object} object The object to iterate
308 * @param {Function} fn The callback function. Passed arguments for each iteration are:
312 - {Object} `object` The object itself
314 * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
317 each: function(object, fn, scope) {
318 for (var property in object) {
319 if (object.hasOwnProperty(property)) {
320 if (fn.call(scope || object, property, object[property], object) === false) {
328 * Merges any number of objects recursively without referencing them or their children.
331 companyName: 'Ext JS',
332 products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
336 location: 'Palo Alto',
342 companyName: 'Sencha Inc.',
343 products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
346 location: 'Redwood City'
350 var sencha = Ext.Object.merge(extjs, newStuff);
352 // extjs and sencha then equals to
354 companyName: 'Sencha Inc.',
355 products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
359 location: 'Redwood City'
364 * @param {Object} object,...
365 * @return {Object} merged The object that is created as a result of merging all the objects passed in.
368 merge: function(source, key, value) {
369 if (typeof key === 'string') {
370 if (value && value.constructor === Object) {
371 if (source[key] && source[key].constructor === Object) {
372 ExtObject.merge(source[key], value);
375 source[key] = Ext.clone(value);
386 ln = arguments.length,
389 for (; i < ln; i++) {
390 object = arguments[i];
392 for (property in object) {
393 if (object.hasOwnProperty(property)) {
394 ExtObject.merge(source, property, object[property]);
403 * Returns the first matching key corresponding to the given value.
404 * If no matching value is found, null is returned.
411 alert(Ext.Object.getKey(sencha, 'loves')); // alerts 'food'
413 * @param {Object} object
414 * @param {Object} value The value to find
417 getKey: function(object, value) {
418 for (var property in object) {
419 if (object.hasOwnProperty(property) && object[property] === value) {
428 * Gets all values of the given object as an array.
430 var values = Ext.Object.getValues({
433 }); // ['Jacky', 'food']
435 * @param {Object} object
436 * @return {Array} An array of values from the object
439 getValues: function(object) {
443 for (property in object) {
444 if (object.hasOwnProperty(property)) {
445 values.push(object[property]);
453 * Gets all keys of the given object as an array.
455 var values = Ext.Object.getKeys({
458 }); // ['name', 'loves']
460 * @param {Object} object
461 * @return {Array} An array of keys from the object
464 getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
468 for (property in object) {
469 if (object.hasOwnProperty(property)) {
478 * Gets the total number of this object's own properties
480 var size = Ext.Object.getSize({
485 * @param {Object} object
486 * @return {Number} size
489 getSize: function(object) {
493 for (property in object) {
494 if (object.hasOwnProperty(property)) {
505 * A convenient alias method for {@link Ext.Object#merge}
510 Ext.merge = Ext.Object.merge;
513 * A convenient alias method for {@link Ext.Object#toQueryString}
517 * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString Ext.Object.toQueryString} instead
519 Ext.urlEncode = function() {
520 var args = Ext.Array.from(arguments),
523 // Support for the old `pre` argument
524 if ((typeof args[1] === 'string')) {
525 prefix = args[1] + '&';
529 return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
533 * A convenient alias method for {@link Ext.Object#fromQueryString}
537 * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString Ext.Object.fromQueryString} instead
539 Ext.urlDecode = function() {
540 return Ext.Object.fromQueryString.apply(Ext.Object, arguments);