--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>The source code</title>
+ <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
+ <style type="text/css">
+ .highlight { display: block; background-color: #ddd; }
+ </style>
+ <script type="text/javascript">
+ function highlight() {
+ document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
+ }
+ </script>
+</head>
+<body onload="prettyPrint(); highlight();">
+ <pre class="prettyprint lang-js"><span id='Ext-Object'>/**
+</span> * @author Jacky Nguyen <jacky@sencha.com>
+ * @docauthor Jacky Nguyen <jacky@sencha.com>
+ * @class Ext.Object
+ *
+ * A collection of useful static methods to deal with objects.
+ *
+ * @singleton
+ */
+
+(function() {
+
+var ExtObject = Ext.Object = {
+
+<span id='Ext-Object-method-toQueryObjects'> /**
+</span> * Converts a `name` - `value` pair to an array of objects with support for nested structures. Useful to construct
+ * query strings. For example:
+ *
+ * var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
+ *
+ * // objects then equals:
+ * [
+ * { name: 'hobbies', value: 'reading' },
+ * { name: 'hobbies', value: 'cooking' },
+ * { name: 'hobbies', value: 'swimming' },
+ * ];
+ *
+ * var objects = Ext.Object.toQueryObjects('dateOfBirth', {
+ * day: 3,
+ * month: 8,
+ * year: 1987,
+ * extra: {
+ * hour: 4
+ * minute: 30
+ * }
+ * }, true); // Recursive
+ *
+ * // objects then equals:
+ * [
+ * { name: 'dateOfBirth[day]', value: 3 },
+ * { name: 'dateOfBirth[month]', value: 8 },
+ * { name: 'dateOfBirth[year]', value: 1987 },
+ * { name: 'dateOfBirth[extra][hour]', value: 4 },
+ * { name: 'dateOfBirth[extra][minute]', value: 30 },
+ * ];
+ *
+ * @param {String} name
+ * @param {Object/Array} value
+ * @param {Boolean} [recursive=false] True to traverse object recursively
+ * @return {Array}
+ */
+ toQueryObjects: function(name, value, recursive) {
+ var self = ExtObject.toQueryObjects,
+ objects = [],
+ i, ln;
+
+ if (Ext.isArray(value)) {
+ for (i = 0, ln = value.length; i < ln; i++) {
+ if (recursive) {
+ objects = objects.concat(self(name + '[' + i + ']', value[i], true));
+ }
+ else {
+ objects.push({
+ name: name,
+ value: value[i]
+ });
+ }
+ }
+ }
+ else if (Ext.isObject(value)) {
+ for (i in value) {
+ if (value.hasOwnProperty(i)) {
+ if (recursive) {
+ objects = objects.concat(self(name + '[' + i + ']', value[i], true));
+ }
+ else {
+ objects.push({
+ name: name,
+ value: value[i]
+ });
+ }
+ }
+ }
+ }
+ else {
+ objects.push({
+ name: name,
+ value: value
+ });
+ }
+
+ return objects;
+ },
+
+<span id='Ext-Object-method-toQueryString'> /**
+</span> * Takes an object and converts it to an encoded query string.
+ *
+ * Non-recursive:
+ *
+ * Ext.Object.toQueryString({foo: 1, bar: 2}); // returns "foo=1&bar=2"
+ * Ext.Object.toQueryString({foo: null, bar: 2}); // returns "foo=&bar=2"
+ * Ext.Object.toQueryString({'some price': '$300'}); // returns "some%20price=%24300"
+ * Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns "date=%222011-01-01T00%3A00%3A00%22"
+ * Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns "colors=red&colors=green&colors=blue"
+ *
+ * Recursive:
+ *
+ * Ext.Object.toQueryString({
+ * username: 'Jacky',
+ * dateOfBirth: {
+ * day: 1,
+ * month: 2,
+ * year: 1911
+ * },
+ * hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
+ * }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
+ * // 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
+ *
+ * @param {Object} object The object to encode
+ * @param {Boolean} [recursive=false] Whether or not to interpret the object in recursive format.
+ * (PHP / Ruby on Rails servers and similar).
+ * @return {String} queryString
+ */
+ toQueryString: function(object, recursive) {
+ var paramObjects = [],
+ params = [],
+ i, j, ln, paramObject, value;
+
+ for (i in object) {
+ if (object.hasOwnProperty(i)) {
+ paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
+ }
+ }
+
+ for (j = 0, ln = paramObjects.length; j < ln; j++) {
+ paramObject = paramObjects[j];
+ value = paramObject.value;
+
+ if (Ext.isEmpty(value)) {
+ value = '';
+ }
+ else if (Ext.isDate(value)) {
+ value = Ext.Date.toString(value);
+ }
+
+ params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
+ }
+
+ return params.join('&');
+ },
+
+<span id='Ext-Object-method-fromQueryString'> /**
+</span> * Converts a query string back into an object.
+ *
+ * Non-recursive:
+ *
+ * Ext.Object.fromQueryString(foo=1&bar=2); // returns {foo: 1, bar: 2}
+ * Ext.Object.fromQueryString(foo=&bar=2); // returns {foo: null, bar: 2}
+ * Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
+ * Ext.Object.fromQueryString(colors=red&colors=green&colors=blue); // returns {colors: ['red', 'green', 'blue']}
+ *
+ * Recursive:
+ *
+ * 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);
+ * // returns
+ * {
+ * username: 'Jacky',
+ * dateOfBirth: {
+ * day: '1',
+ * month: '2',
+ * year: '1911'
+ * },
+ * hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
+ * }
+ *
+ * @param {String} queryString The query string to decode
+ * @param {Boolean} [recursive=false] Whether or not to recursively decode the string. This format is supported by
+ * PHP / Ruby on Rails servers and similar.
+ * @return {Object}
+ */
+ fromQueryString: function(queryString, recursive) {
+ var parts = queryString.replace(/^\?/, '').split('&'),
+ object = {},
+ temp, components, name, value, i, ln,
+ part, j, subLn, matchedKeys, matchedName,
+ keys, key, nextKey;
+
+ for (i = 0, ln = parts.length; i < ln; i++) {
+ part = parts[i];
+
+ if (part.length > 0) {
+ components = part.split('=');
+ name = decodeURIComponent(components[0]);
+ value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
+
+ if (!recursive) {
+ if (object.hasOwnProperty(name)) {
+ if (!Ext.isArray(object[name])) {
+ object[name] = [object[name]];
+ }
+
+ object[name].push(value);
+ }
+ else {
+ object[name] = value;
+ }
+ }
+ else {
+ matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
+ matchedName = name.match(/^([^\[]+)/);
+
+ //<debug error>
+ if (!matchedName) {
+ Ext.Error.raise({
+ sourceClass: "Ext.Object",
+ sourceMethod: "fromQueryString",
+ queryString: queryString,
+ recursive: recursive,
+ msg: 'Malformed query string given, failed parsing name from "' + part + '"'
+ });
+ }
+ //</debug>
+
+ name = matchedName[0];
+ keys = [];
+
+ if (matchedKeys === null) {
+ object[name] = value;
+ continue;
+ }
+
+ for (j = 0, subLn = matchedKeys.length; j < subLn; j++) {
+ key = matchedKeys[j];
+ key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
+ keys.push(key);
+ }
+
+ keys.unshift(name);
+
+ temp = object;
+
+ for (j = 0, subLn = keys.length; j < subLn; j++) {
+ key = keys[j];
+
+ if (j === subLn - 1) {
+ if (Ext.isArray(temp) && key === '') {
+ temp.push(value);
+ }
+ else {
+ temp[key] = value;
+ }
+ }
+ else {
+ if (temp[key] === undefined || typeof temp[key] === 'string') {
+ nextKey = keys[j+1];
+
+ temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
+ }
+
+ temp = temp[key];
+ }
+ }
+ }
+ }
+ }
+
+ return object;
+ },
+
+<span id='Ext-Object-method-each'> /**
+</span> * Iterates through an object and invokes the given callback function for each iteration.
+ * The iteration can be stopped by returning `false` in the callback function. For example:
+ *
+ * var person = {
+ * name: 'Jacky'
+ * hairColor: 'black'
+ * loves: ['food', 'sleeping', 'wife']
+ * };
+ *
+ * Ext.Object.each(person, function(key, value, myself) {
+ * console.log(key + ":" + value);
+ *
+ * if (key === 'hairColor') {
+ * return false; // stop the iteration
+ * }
+ * });
+ *
+ * @param {Object} object The object to iterate
+ * @param {Function} fn The callback function.
+ * @param {String} fn.key
+ * @param {Object} fn.value
+ * @param {Object} fn.object The object itself
+ * @param {Object} [scope] The execution scope (`this`) of the callback function
+ */
+ each: function(object, fn, scope) {
+ for (var property in object) {
+ if (object.hasOwnProperty(property)) {
+ if (fn.call(scope || object, property, object[property], object) === false) {
+ return;
+ }
+ }
+ }
+ },
+
+<span id='Ext-Object-method-merge'> /**
+</span> * Merges any number of objects recursively without referencing them or their children.
+ *
+ * var extjs = {
+ * companyName: 'Ext JS',
+ * products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
+ * isSuperCool: true
+ * office: {
+ * size: 2000,
+ * location: 'Palo Alto',
+ * isFun: true
+ * }
+ * };
+ *
+ * var newStuff = {
+ * companyName: 'Sencha Inc.',
+ * products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
+ * office: {
+ * size: 40000,
+ * location: 'Redwood City'
+ * }
+ * };
+ *
+ * var sencha = Ext.Object.merge(extjs, newStuff);
+ *
+ * // extjs and sencha then equals to
+ * {
+ * companyName: 'Sencha Inc.',
+ * products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
+ * isSuperCool: true
+ * office: {
+ * size: 30000,
+ * location: 'Redwood City'
+ * isFun: true
+ * }
+ * }
+ *
+ * @param {Object...} object Any number of objects to merge.
+ * @return {Object} merged The object that is created as a result of merging all the objects passed in.
+ */
+ merge: function(source, key, value) {
+ if (typeof key === 'string') {
+ if (value && value.constructor === Object) {
+ if (source[key] && source[key].constructor === Object) {
+ ExtObject.merge(source[key], value);
+ }
+ else {
+ source[key] = Ext.clone(value);
+ }
+ }
+ else {
+ source[key] = value;
+ }
+
+ return source;
+ }
+
+ var i = 1,
+ ln = arguments.length,
+ object, property;
+
+ for (; i < ln; i++) {
+ object = arguments[i];
+
+ for (property in object) {
+ if (object.hasOwnProperty(property)) {
+ ExtObject.merge(source, property, object[property]);
+ }
+ }
+ }
+
+ return source;
+ },
+
+<span id='Ext-Object-method-getKey'> /**
+</span> * Returns the first matching key corresponding to the given value.
+ * If no matching value is found, null is returned.
+ *
+ * var person = {
+ * name: 'Jacky',
+ * loves: 'food'
+ * };
+ *
+ * alert(Ext.Object.getKey(person, 'food')); // alerts 'loves'
+ *
+ * @param {Object} object
+ * @param {Object} value The value to find
+ */
+ getKey: function(object, value) {
+ for (var property in object) {
+ if (object.hasOwnProperty(property) && object[property] === value) {
+ return property;
+ }
+ }
+
+ return null;
+ },
+
+<span id='Ext-Object-method-getValues'> /**
+</span> * Gets all values of the given object as an array.
+ *
+ * var values = Ext.Object.getValues({
+ * name: 'Jacky',
+ * loves: 'food'
+ * }); // ['Jacky', 'food']
+ *
+ * @param {Object} object
+ * @return {Array} An array of values from the object
+ */
+ getValues: function(object) {
+ var values = [],
+ property;
+
+ for (property in object) {
+ if (object.hasOwnProperty(property)) {
+ values.push(object[property]);
+ }
+ }
+
+ return values;
+ },
+
+<span id='Ext-Object-method-getKeys'> /**
+</span> * Gets all keys of the given object as an array.
+ *
+ * var values = Ext.Object.getKeys({
+ * name: 'Jacky',
+ * loves: 'food'
+ * }); // ['name', 'loves']
+ *
+ * @param {Object} object
+ * @return {String[]} An array of keys from the object
+ * @method
+ */
+ getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
+ var keys = [],
+ property;
+
+ for (property in object) {
+ if (object.hasOwnProperty(property)) {
+ keys.push(property);
+ }
+ }
+
+ return keys;
+ },
+
+<span id='Ext-Object-method-getSize'> /**
+</span> * Gets the total number of this object's own properties
+ *
+ * var size = Ext.Object.getSize({
+ * name: 'Jacky',
+ * loves: 'food'
+ * }); // size equals 2
+ *
+ * @param {Object} object
+ * @return {Number} size
+ */
+ getSize: function(object) {
+ var size = 0,
+ property;
+
+ for (property in object) {
+ if (object.hasOwnProperty(property)) {
+ size++;
+ }
+ }
+
+ return size;
+ }
+};
+
+
+<span id='Ext-method-merge'>/**
+</span> * A convenient alias method for {@link Ext.Object#merge}.
+ *
+ * @member Ext
+ * @method merge
+ * @alias Ext.Object#merge
+ */
+Ext.merge = Ext.Object.merge;
+
+<span id='Ext-method-urlEncode'>/**
+</span> * Alias for {@link Ext.Object#toQueryString}.
+ *
+ * @member Ext
+ * @method urlEncode
+ * @alias Ext.Object#toQueryString
+ * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString} instead
+ */
+Ext.urlEncode = function() {
+ var args = Ext.Array.from(arguments),
+ prefix = '';
+
+ // Support for the old `pre` argument
+ if ((typeof args[1] === 'string')) {
+ prefix = args[1] + '&';
+ args[1] = false;
+ }
+
+ return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
+};
+
+<span id='Ext-method-urlDecode'>/**
+</span> * Alias for {@link Ext.Object#fromQueryString}.
+ *
+ * @member Ext
+ * @method urlDecode
+ * @alias Ext.Object#fromQueryString
+ * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString} instead
+ */
+Ext.urlDecode = function() {
+ return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
+};
+
+})();
+</pre>
+</body>
+</html>