<!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">// @tag foundation,core
|
// @require Function.js
|
// @define Ext.Object
|
|
<span id='Ext-Object'>/**
|
</span> * @class Ext.Object
|
*
|
* A collection of useful static methods to deal with objects.
|
*
|
* @singleton
|
*/
|
|
(function() {
|
|
// The "constructor" for chain:
|
var TemplateClass = function(){},
|
ExtObject = Ext.Object = {
|
|
<span id='Ext-Object-method-chain'> /**
|
</span> * Returns a new object with the given object as the prototype chain. This method is
|
* designed to mimic the ECMA standard `Object.create` method and is assigned to that
|
* function when it is available.
|
*
|
* **NOTE** This method does not support the property definitions capability of the
|
* `Object.create` method. Only the first argument is supported.
|
*
|
* @param {Object} object The prototype chain for the new object.
|
*/
|
chain: Object.create || function (object) {
|
TemplateClass.prototype = object;
|
var result = new TemplateClass();
|
TemplateClass.prototype = null;
|
return result;
|
},
|
|
<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) {
|
throw new Error('[Ext.Object.fromQueryString] 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: 40000,
|
* location: 'Redwood City',
|
* isFun: true
|
* }
|
* }
|
*
|
* @param {Object} destination The object into which all subsequent objects are merged.
|
* @param {Object...} object Any number of objects to merge into the destination.
|
* @return {Object} merged The destination object with all passed objects merged in.
|
*/
|
merge: function(destination) {
|
var i = 1,
|
ln = arguments.length,
|
mergeFn = ExtObject.merge,
|
cloneFn = Ext.clone,
|
object, key, value, sourceKey;
|
|
for (; i < ln; i++) {
|
object = arguments[i];
|
|
for (key in object) {
|
value = object[key];
|
if (value && value.constructor === Object) {
|
sourceKey = destination[key];
|
if (sourceKey && sourceKey.constructor === Object) {
|
mergeFn(sourceKey, value);
|
}
|
else {
|
destination[key] = cloneFn(value);
|
}
|
}
|
else {
|
destination[key] = value;
|
}
|
}
|
}
|
|
return destination;
|
},
|
|
<span id='Ext-Object-method-mergeIf'> /**
|
</span> * @private
|
* @param destination
|
*/
|
mergeIf: function(destination) {
|
var i = 1,
|
ln = arguments.length,
|
cloneFn = Ext.clone,
|
object, key, value;
|
|
for (; i < ln; i++) {
|
object = arguments[i];
|
|
for (key in object) {
|
if (!(key in destination)) {
|
value = object[key];
|
|
if (value && value.constructor === Object) {
|
destination[key] = cloneFn(value);
|
}
|
else {
|
destination[key] = value;
|
}
|
}
|
}
|
}
|
|
return destination;
|
},
|
|
<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: (typeof Object.keys == 'function')
|
? function(object){
|
if (!object) {
|
return [];
|
}
|
return Object.keys(object);
|
}
|
: 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-Object-method-isEmpty'> /**
|
</span> * Checks if there are any properties on this object.
|
* @param {Object} object
|
* @return {Boolean} `true` if there no properties on the object.
|
*/
|
isEmpty: function(object){
|
for (var key in object) {
|
if (object.hasOwnProperty(key)) {
|
return false;
|
}
|
}
|
return true;
|
},
|
|
<span id='Ext-Object-method-equals'> /**
|
</span> * Shallow compares the contents of 2 objects using strict equality. Objects are
|
* considered equal if they both have the same set of properties and the
|
* value for those properties equals the other in the corresponding object.
|
*
|
* // Returns true
|
* Ext.Object.equals({
|
* foo: 1,
|
* bar: 2
|
* }, {
|
* foo: 1,
|
* bar: 2
|
* });
|
*
|
* @param {Object} object1
|
* @param {Object} object2
|
* @return {Boolean} `true` if the objects are equal.
|
*/
|
equals: (function() {
|
var check = function(o1, o2) {
|
var key;
|
|
for (key in o1) {
|
if (o1.hasOwnProperty(key)) {
|
if (o1[key] !== o2[key]) {
|
return false;
|
}
|
}
|
}
|
return true;
|
};
|
|
return function(object1, object2) {
|
|
// Short circuit if the same object is passed twice
|
if (object1 === object2) {
|
return true;
|
} if (object1 && object2) {
|
// Do the second check because we could have extra keys in
|
// object2 that don't exist in object1.
|
return check(object1, object2) && check(object2, object1);
|
} else if (!object1 && !object2) {
|
return object1 === object2;
|
} else {
|
return false;
|
}
|
};
|
})(),
|
|
<span id='Ext-Object-method-classify'> /**
|
</span> * @private
|
*/
|
classify: function(object) {
|
var prototype = object,
|
objectProperties = [],
|
propertyClassesMap = {},
|
objectClass = function() {
|
var i = 0,
|
ln = objectProperties.length,
|
property;
|
|
for (; i < ln; i++) {
|
property = objectProperties[i];
|
this[property] = new propertyClassesMap[property]();
|
}
|
},
|
key, value;
|
|
for (key in object) {
|
if (object.hasOwnProperty(key)) {
|
value = object[key];
|
|
if (value && value.constructor === Object) {
|
objectProperties.push(key);
|
propertyClassesMap[key] = ExtObject.classify(value);
|
}
|
}
|
}
|
|
objectClass.prototype = prototype;
|
|
return objectClass;
|
}
|
};
|
|
<span id='Ext-method-merge'>/**
|
</span> * A convenient alias method for {@link Ext.Object#merge}.
|
*
|
* @member Ext
|
* @method merge
|
* @inheritdoc Ext.Object#merge
|
*/
|
Ext.merge = Ext.Object.merge;
|
|
<span id='Ext-property-mergeIf'>/**
|
</span> * @private
|
* @member Ext
|
*/
|
Ext.mergeIf = Ext.Object.mergeIf;
|
|
<span id='Ext-method-urlEncode'>/**
|
</span> *
|
* @member Ext
|
* @method urlEncode
|
* @inheritdoc 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 + ExtObject.toQueryString.apply(ExtObject, args);
|
};
|
|
<span id='Ext-method-urlDecode'>/**
|
</span> * Alias for {@link Ext.Object#fromQueryString}.
|
*
|
* @member Ext
|
* @method urlDecode
|
* @inheritdoc Ext.Object#fromQueryString
|
* @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString} instead
|
*/
|
Ext.urlDecode = function() {
|
return ExtObject.fromQueryString.apply(ExtObject, arguments);
|
};
|
|
}());
|
</pre>
|
</body>
|
</html>
|