--- /dev/null
+/**
+ * @class Ext
+ * @singleton
+ */
+(function() {
+ var global = this,
+ objectPrototype = Object.prototype,
+ toString = Object.prototype.toString,
+ enumerables = true,
+ enumerablesTest = { toString: 1 },
+ i;
+
+ if (typeof Ext === 'undefined') {
+ global.Ext = {};
+ }
+
+ Ext.global = global;
+
+ for (i in enumerablesTest) {
+ enumerables = null;
+ }
+
+ if (enumerables) {
+ enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
+ 'toLocaleString', 'toString', 'constructor'];
+ }
+
+ /**
+ * An array containing extra enumerables for old browsers
+ * @type Array
+ */
+ Ext.enumerables = enumerables;
+
+ /**
+ * Copies all the properties of config to the specified object.
+ * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
+ * {@link Ext.Object#merge} instead.
+ * @param {Object} object The receiver of the properties
+ * @param {Object} config The source of the properties
+ * @param {Object} defaults A different object that will also be applied for default values
+ * @return {Object} returns obj
+ */
+ Ext.apply = function(object, config, defaults) {
+ if (defaults) {
+ Ext.apply(object, defaults);
+ }
+
+ if (object && config && typeof config === 'object') {
+ var i, j, k;
+
+ for (i in config) {
+ object[i] = config[i];
+ }
+
+ if (enumerables) {
+ for (j = enumerables.length; j--;) {
+ k = enumerables[j];
+ if (config.hasOwnProperty(k)) {
+ object[k] = config[k];
+ }
+ }
+ }
+ }
+
+ return object;
+ };
+
+ Ext.buildSettings = Ext.apply({
+ baseCSSPrefix: 'x-',
+ scopeResetCSS: false
+ }, Ext.buildSettings || {});
+
+ Ext.apply(Ext, {
+ /**
+ * A reusable empty function
+ */
+ emptyFn: function() {},
+
+ baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
+
+ /**
+ * Copies all the properties of config to object if they don't already exist.
+ * @function
+ * @param {Object} object The receiver of the properties
+ * @param {Object} config The source of the properties
+ * @return {Object} returns obj
+ */
+ applyIf: function(object, config) {
+ var property;
+
+ if (object) {
+ for (property in config) {
+ if (object[property] === undefined) {
+ object[property] = config[property];
+ }
+ }
+ }
+
+ return object;
+ },
+
+ /**
+ * Iterates either an array or an object. This method delegates to
+ * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
+ *
+ * @param {Object/Array} object The object or array to be iterated.
+ * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
+ * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
+ * type that is being iterated.
+ * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
+ * Defaults to the object being iterated itself.
+ * @markdown
+ */
+ iterate: function(object, fn, scope) {
+ if (Ext.isEmpty(object)) {
+ return;
+ }
+
+ if (scope === undefined) {
+ scope = object;
+ }
+
+ if (Ext.isIterable(object)) {
+ Ext.Array.each.call(Ext.Array, object, fn, scope);
+ }
+ else {
+ Ext.Object.each.call(Ext.Object, object, fn, scope);
+ }
+ }
+ });
+
+ Ext.apply(Ext, {
+
+ /**
+ * This method deprecated. Use {@link Ext#define Ext.define} instead.
+ * @function
+ * @param {Function} superclass
+ * @param {Object} overrides
+ * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
+ * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
+ */
+ extend: function() {
+ // inline overrides
+ var objectConstructor = objectPrototype.constructor,
+ inlineOverrides = function(o) {
+ for (var m in o) {
+ if (!o.hasOwnProperty(m)) {
+ continue;
+ }
+ this[m] = o[m];
+ }
+ };
+
+ return function(subclass, superclass, overrides) {
+ // First we check if the user passed in just the superClass with overrides
+ if (Ext.isObject(superclass)) {
+ overrides = superclass;
+ superclass = subclass;
+ subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
+ superclass.apply(this, arguments);
+ };
+ }
+
+ //<debug>
+ if (!superclass) {
+ Ext.Error.raise({
+ sourceClass: 'Ext',
+ sourceMethod: 'extend',
+ msg: 'Attempting to extend from a class which has not been loaded on the page.'
+ });
+ }
+ //</debug>
+
+ // We create a new temporary class
+ var F = function() {},
+ subclassProto, superclassProto = superclass.prototype;
+
+ F.prototype = superclassProto;
+ subclassProto = subclass.prototype = new F();
+ subclassProto.constructor = subclass;
+ subclass.superclass = superclassProto;
+
+ if (superclassProto.constructor === objectConstructor) {
+ superclassProto.constructor = superclass;
+ }
+
+ subclass.override = function(overrides) {
+ Ext.override(subclass, overrides);
+ };
+
+ subclassProto.override = inlineOverrides;
+ subclassProto.proto = subclassProto;
+
+ subclass.override(overrides);
+ subclass.extend = function(o) {
+ return Ext.extend(subclass, o);
+ };
+
+ return subclass;
+ };
+ }(),
+
+ /**
+ * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
+
+ Ext.define('My.cool.Class', {
+ sayHi: function() {
+ alert('Hi!');
+ }
+ }
+
+ Ext.override(My.cool.Class, {
+ sayHi: function() {
+ alert('About to say...');
+
+ this.callOverridden();
+ }
+ });
+
+ var cool = new My.cool.Class();
+ cool.sayHi(); // alerts 'About to say...'
+ // alerts 'Hi!'
+
+ * Please note that `this.callOverridden()` only works if the class was previously
+ * created with {@link Ext#define)
+ *
+ * @param {Object} cls The class to override
+ * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
+ * containing one or more methods.
+ * @method override
+ * @markdown
+ */
+ override: function(cls, overrides) {
+ if (cls.prototype.$className) {
+ return cls.override(overrides);
+ }
+ else {
+ Ext.apply(cls.prototype, overrides);
+ }
+ }
+ });
+
+ // A full set of static methods to do type checking
+ Ext.apply(Ext, {
+
+ /**
+ * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
+ * value (second argument) otherwise.
+ *
+ * @param {Mixed} value The value to test
+ * @param {Mixed} defaultValue The value to return if the original value is empty
+ * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
+ * @return {Mixed} value, if non-empty, else defaultValue
+ */
+ valueFrom: function(value, defaultValue, allowBlank){
+ return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
+ },
+
+ /**
+ * Returns the type of the given variable in string format. List of possible values are:
+ *
+ * - `undefined`: If the given value is `undefined`
+ * - `null`: If the given value is `null`
+ * - `string`: If the given value is a string
+ * - `number`: If the given value is a number
+ * - `boolean`: If the given value is a boolean value
+ * - `date`: If the given value is a `Date` object
+ * - `function`: If the given value is a function reference
+ * - `object`: If the given value is an object
+ * - `array`: If the given value is an array
+ * - `regexp`: If the given value is a regular expression
+ * - `element`: If the given value is a DOM Element
+ * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
+ * - `whitespace`: If the given value is a DOM text node and contains only whitespace
+ *
+ * @param {Mixed} value
+ * @return {String}
+ * @markdown
+ */
+ typeOf: function(value) {
+ if (value === null) {
+ return 'null';
+ }
+
+ var type = typeof value;
+
+ if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
+ return type;
+ }
+
+ var typeToString = toString.call(value);
+
+ switch(typeToString) {
+ case '[object Array]':
+ return 'array';
+ case '[object Date]':
+ return 'date';
+ case '[object Boolean]':
+ return 'boolean';
+ case '[object Number]':
+ return 'number';
+ case '[object RegExp]':
+ return 'regexp';
+ }
+
+ if (type === 'function') {
+ return 'function';
+ }
+
+ if (type === 'object') {
+ if (value.nodeType !== undefined) {
+ if (value.nodeType === 3) {
+ return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
+ }
+ else {
+ return 'element';
+ }
+ }
+
+ return 'object';
+ }
+
+ //<debug error>
+ Ext.Error.raise({
+ sourceClass: 'Ext',
+ sourceMethod: 'typeOf',
+ msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
+ });
+ //</debug>
+ },
+
+ /**
+ * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
+ *
+ * - `null`
+ * - `undefined`
+ * - a zero-length array
+ * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
+ *
+ * @param {Mixed} value The value to test
+ * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
+ * @return {Boolean}
+ * @markdown
+ */
+ isEmpty: function(value, allowEmptyString) {
+ return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
+ },
+
+ /**
+ * Returns true if the passed value is a JavaScript Array, false otherwise.
+ *
+ * @param {Mixed} target The target to test
+ * @return {Boolean}
+ */
+ isArray: ('isArray' in Array) ? Array.isArray : function(value) {
+ return toString.call(value) === '[object Array]';
+ },
+
+ /**
+ * Returns true if the passed value is a JavaScript Date object, false otherwise.
+ * @param {Object} object The object to test
+ * @return {Boolean}
+ */
+ isDate: function(value) {
+ return toString.call(value) === '[object Date]';
+ },
+
+ /**
+ * Returns true if the passed value is a JavaScript Object, false otherwise.
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isObject: (toString.call(null) === '[object Object]') ?
+ function(value) {
+ return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.nodeType === undefined;
+ } :
+ function(value) {
+ return toString.call(value) === '[object Object]';
+ },
+
+ /**
+ * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isPrimitive: function(value) {
+ var type = typeof value;
+
+ return type === 'string' || type === 'number' || type === 'boolean';
+ },
+
+ /**
+ * Returns true if the passed value is a JavaScript Function, false otherwise.
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isFunction:
+ // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
+ // Object.prorotype.toString (slower)
+ (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
+ return toString.call(value) === '[object Function]';
+ } : function(value) {
+ return typeof value === 'function';
+ },
+
+ /**
+ * Returns true if the passed value is a number. Returns false for non-finite numbers.
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isNumber: function(value) {
+ return typeof value === 'number' && isFinite(value);
+ },
+
+ /**
+ * Validates that a value is numeric.
+ * @param {Mixed} value Examples: 1, '1', '2.34'
+ * @return {Boolean} True if numeric, false otherwise
+ */
+ isNumeric: function(value) {
+ return !isNaN(parseFloat(value)) && isFinite(value);
+ },
+
+ /**
+ * Returns true if the passed value is a string.
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isString: function(value) {
+ return typeof value === 'string';
+ },
+
+ /**
+ * Returns true if the passed value is a boolean.
+ *
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isBoolean: function(value) {
+ return typeof value === 'boolean';
+ },
+
+ /**
+ * Returns true if the passed value is an HTMLElement
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isElement: function(value) {
+ return value ? value.nodeType !== undefined : false;
+ },
+
+ /**
+ * Returns true if the passed value is a TextNode
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isTextNode: function(value) {
+ return value ? value.nodeName === "#text" : false;
+ },
+
+ /**
+ * Returns true if the passed value is defined.
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isDefined: function(value) {
+ return typeof value !== 'undefined';
+ },
+
+ /**
+ * Returns true if the passed value is iterable, false otherwise
+ * @param {Mixed} value The value to test
+ * @return {Boolean}
+ */
+ isIterable: function(value) {
+ return (value && typeof value !== 'string') ? value.length !== undefined : false;
+ }
+ });
+
+ Ext.apply(Ext, {
+
+ /**
+ * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
+ * @param {Mixed} item The variable to clone
+ * @return {Mixed} clone
+ */
+ clone: function(item) {
+ if (item === null || item === undefined) {
+ return item;
+ }
+
+ // DOM nodes
+ // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
+ // recursively
+ if (item.nodeType && item.cloneNode) {
+ return item.cloneNode(true);
+ }
+
+ var type = toString.call(item);
+
+ // Date
+ if (type === '[object Date]') {
+ return new Date(item.getTime());
+ }
+
+ var i, j, k, clone, key;
+
+ // Array
+ if (type === '[object Array]') {
+ i = item.length;
+
+ clone = [];
+
+ while (i--) {
+ clone[i] = Ext.clone(item[i]);
+ }
+ }
+ // Object
+ else if (type === '[object Object]' && item.constructor === Object) {
+ clone = {};
+
+ for (key in item) {
+ clone[key] = Ext.clone(item[key]);
+ }
+
+ if (enumerables) {
+ for (j = enumerables.length; j--;) {
+ k = enumerables[j];
+ clone[k] = item[k];
+ }
+ }
+ }
+
+ return clone || item;
+ },
+
+ /**
+ * @private
+ * Generate a unique reference of Ext in the global scope, useful for sandboxing
+ */
+ getUniqueGlobalNamespace: function() {
+ var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
+
+ if (uniqueGlobalNamespace === undefined) {
+ var i = 0;
+
+ do {
+ uniqueGlobalNamespace = 'ExtSandbox' + (++i);
+ } while (Ext.global[uniqueGlobalNamespace] !== undefined);
+
+ Ext.global[uniqueGlobalNamespace] = Ext;
+ this.uniqueGlobalNamespace = uniqueGlobalNamespace;
+ }
+
+ return uniqueGlobalNamespace;
+ },
+
+ /**
+ * @private
+ */
+ functionFactory: function() {
+ var args = Array.prototype.slice.call(arguments);
+
+ if (args.length > 0) {
+ args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
+ args[args.length - 1];
+ }
+
+ return Function.prototype.constructor.apply(Function.prototype, args);
+ }
+ });
+
+ /**
+ * Old alias to {@link Ext#typeOf}
+ * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
+ */
+ Ext.type = Ext.typeOf;
+
+})();