3.0 source code

This commit is contained in:
agolybev
2015-04-28 17:59:00 +03:00
parent c69fd34bdd
commit 7b3b2248e5
16311 changed files with 1445974 additions and 3108429 deletions

View File

@@ -0,0 +1,152 @@
//@tag dom,core
//@define Ext.EventManager
//@define Ext.core.EventManager
//@require Ext.Loader
/**
* @class Ext.EventManager
*
* This object has been deprecated in Sencha Touch 2.0.0. Please refer to the method documentation for specific alternatives.
*
* @deprecated 2.0.0
* @singleton
* @private
*/
//<deprecated product=touch since=2.0>
Ext.ns('Ext.core');
Ext.core.EventManager =
Ext.EventManager = {
/**
* Appends an event handler to an element. The shorthand version {@link #on} is equivalent. Typically you will
* use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
* @param {String/HTMLElement} el The HTML element or `id` to assign the event handler to.
* @param {String} eventName The name of the event to listen for.
* @param {Function} handler The handler function the event invokes. This function is passed
* the following parameters:
* @param {Ext.EventObject} handler.evt The {@link Ext.EventObject EventObject} describing the event.
* @param {Ext.Element} handler.t The {@link Ext.Element Element} which was the target of the event.
* Note that this may be filtered by using the `delegate` option.
* @param {Object} handler.o The options object from the addListener call.
* @param {Object} scope (optional) The scope (`this` reference) in which the handler function is executed. __Defaults to the Element__.
* @param {Object} options (optional) An object containing handler configuration properties.
* This may contain any of the following properties:
* @param {Object} [options.scope] The scope (`this` reference) in which the handler function is executed. __Defaults to the Element__.
* @param {String} [options.delegate] A simple selector to filter the target or look for a descendant of the target.
* @param {Boolean} [options.stopEvent] `true` to stop the event. That is stop propagation, and prevent the default action.
* @param {Boolean} [options.preventDefault] `true` to prevent the default action.
* @param {Boolean} [options.stopPropagation] `true` to prevent event propagation.
* @param {Boolean} [options.normalized] `false` to pass a browser event to the handler function instead of an Ext.EventObject.
* @param {Number} [options.delay] The number of milliseconds to delay the invocation of the handler after the event fires.
* @param {Boolean} [options.single] `true` to add a handler to handle just the next firing of the event, and then remove itself.
* @param {Number} [options.buffer] Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
* by the specified number of milliseconds. If the event fires again within that time, the original
* handler is _not_ invoked, but the new handler is scheduled in its place.
* @param {Ext.Element} [options.target] Only call the handler if the event was fired on the target Element, _not_ if the event was bubbled up from a child node.
*
* See {@link Ext.Element#addListener} for examples of how to use these options.
* @deprecated 2.0.0 Please use {@link Ext.dom.Element#addListener addListener} on an instance of Ext.Element instead.
*/
addListener: function(element, eventName, fn, scope, options) {
//<debug warn>
Ext.Logger.deprecate("Ext.EventManager.addListener is deprecated, use addListener() directly from an instance of Ext.Element instead", 2);
//</debug>
element.on(eventName, fn, scope, options);
},
/**
* Removes an event handler from an element. The shorthand version {@link #un} is equivalent. Typically
* you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
* @param {String/HTMLElement} el The id or html element from which to remove the listener.
* @param {String} eventName The name of the event.
* @param {Function} fn The handler function to remove. __This must be a reference to the function passed into the {@link #addListener} call.__
* @param {Object} scope If a scope (`this` reference) was specified when the listener was added,
* then this must refer to the same object.
* @deprecated 2.0.0 Please use {@link Ext.dom.Element#removeListener removeListener} on an instance of Ext.Element instead.
*/
removeListener: function(element, eventName, fn, scope) {
//<debug warn>
Ext.Logger.deprecate("Ext.EventManager.removeListener is deprecated, use removeListener() directly from an instance of Ext.Element instead", 2);
//</debug>
element.un(eventName, fn, scope);
},
/**
* Removes all event handers from an element. Typically you will use {@link Ext.Element#clearListeners}
* directly on an Element in favor of calling this version.
* @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
* @deprecated 2.0.0 Please use {@link Ext.dom.Element#clearListeners clearListeners} on an instance of Ext.Element instead.
*/
removeAll: function(element){
//<debug warn>
Ext.Logger.deprecate("Ext.EventManager.removeAll is deprecated, use clearListeners() directly from an instance of Ext.Element instead", 3);
//</debug>
Ext.get(element).clearListeners();
},
/**
* Adds a listener to be notified when the document is ready (before `onload` and before images are loaded).
* @removed 2.0.0 Please use {@link Ext#onReady onReady}
*/
onDocumentReady: function() {
//<debug warn>
Ext.Logger.deprecate("Ext.EventManager.onDocumentReady has been removed, please use Ext.onReady instead", 3);
//</debug>
},
/**
* Adds a listener to be notified when the browser window is resized and provides resize event buffering (50 milliseconds),
* passes new viewport width and height to handlers.
* @param {Function} fn The handler function the window resize event invokes.
* @param {Object} scope The scope (`this` reference) in which the handler function executes. Defaults to the browser window.
* @param {Boolean} options Options object as passed to {@link Ext.Element#addListener}
* @deprecated 2.0.0 Please listen to the {@link Ext.Viewport#event-resize resize} on Ext.Viewport instead.
*/
onWindowResize: function(fn, scope, options) {
//<debug warn>
Ext.Logger.deprecate("Ext.EventManager.onWindowResize is deprecated, attach listener to Ext.Viewport instead, i.e: Ext.Viewport.on('resize', ...)", 2);
//</debug>
Ext.Viewport.on('resize', fn, scope, options);
},
onOrientationChange: function(fn, scope, options) {
//<debug warn>
Ext.Logger.deprecate("Ext.EventManager.onOrientationChange is deprecated, attach listener to Ext.Viewport instead, i.e: Ext.Viewport.on('orientationchange', ...)", 2);
//</debug>
Ext.Viewport.on('orientationchange', fn, scope, options);
},
unOrientationChange: function(fn, scope, options) {
//<debug warn>
Ext.Logger.deprecate("Ext.EventManager.unOrientationChange is deprecated, remove listener from Ext.Viewport instead, i.e: Ext.Viewport.un('orientationchange', ...)", 2);
//</debug>
Ext.Viewport.un('orientationchange', fn, scope, options);
}
};
/**
* Appends an event handler to an element. Shorthand for {@link #addListener}.
* @param {String/HTMLElement} el The html element or id to assign the event handler to.
* @param {String} eventName The name of the event to listen for.
* @param {Function} handler The handler function the event invokes.
* @param {Object} scope (optional) (`this` reference) in which the handler function executes. __Defaults to the Element__.
* @param {Object} options (optional) An object containing standard {@link #addListener} options
* @member Ext.EventManager
* @method on
* @deprecated 2.0.0 Please use {@link Ext.dom.Element#addListener addListener} on an instance of Ext.Element instead.
*/
Ext.EventManager.on = Ext.EventManager.addListener;
/**
* Removes an event handler from an element. Shorthand for {@link #removeListener}.
* @param {String/HTMLElement} el The id or html element from which to remove the listener.
* @param {String} eventName The name of the event.
* @param {Function} fn The handler function to remove. __This must be a reference to the function passed into the {@link #on} call.__
* @param {Object} scope If a scope (`this` reference) was specified when the listener was added,
* then this must refer to the same object.
* @member Ext.EventManager
* @method un
* @deprecated 2.0.0 Please use {@link Ext.dom.Element#removeListener removeListener} on an instance of Ext.Element instead.
*/
Ext.EventManager.un = Ext.EventManager.removeListener;
//</deprecated>

File diff suppressed because it is too large Load Diff

614
OfficeWeb/vendor/touch/src/core/Ext.js vendored Normal file
View File

@@ -0,0 +1,614 @@
//@tag foundation,core
//@define Ext
/**
* @class Ext
* @singleton
*/
(function() {
var global = this,
objectPrototype = Object.prototype,
toString = objectPrototype.toString,
enumerables = true,
enumerablesTest = { toString: 1 },
emptyFn = function(){},
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.
* @property {String[]}
*/
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, {
/**
* @property {Function}
* A reusable empty function
*/
emptyFn: emptyFn,
baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
/**
* Copies all the properties of config to object if they don't already exist.
* @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.
*/
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.
* @method
* @param {Function} superclass
* @param {Object} overrides
* @return {Function} The subclass constructor from the `overrides` parameter, or a generated one if not provided.
* @deprecated 4.0.0 Please 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.
*
* @param {Object} cls The class to override
* @param {Object} overrides The properties to add to `origClass`. This should be specified as an object literal
* containing one or more properties.
* @method override
* @deprecated 4.1.0 Please use {@link Ext#define Ext.define} instead.
*/
override: function(cls, overrides) {
if (cls.$isClass) {
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 {Object} value The value to test.
* @param {Object} defaultValue The value to return if the original value is empty.
* @param {Boolean} [allowBlank=false] (optional) `true` to allow zero length strings to qualify as non-empty.
* @return {Object} `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 {Object} value
* @return {String}
*/
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 {Object} value The value to test.
* @param {Boolean} [allowEmptyString=false] (optional) `true` to allow empty strings.
* @return {Boolean}
*/
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 {Object} target The target to test.
* @return {Boolean}
* @method
*/
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 {Object} value The value to test.
* @return {Boolean}
* @method
*/
isObject: (toString.call(null) === '[object Object]') ?
function(value) {
// check ownerDocument here as well to exclude DOM nodes
return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
} :
function(value) {
return toString.call(value) === '[object Object]';
},
/**
* @private
*/
isSimpleObject: function(value) {
return value instanceof Object && value.constructor === Object;
},
/**
* Returns `true` if the passed value is a JavaScript 'primitive', a string, number or Boolean.
* @param {Object} 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 {Object} value The value to test.
* @return {Boolean}
* @method
*/
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 {Object} value The value to test.
* @return {Boolean}
*/
isNumber: function(value) {
return typeof value === 'number' && isFinite(value);
},
/**
* Validates that a value is numeric.
* @param {Object} 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 {Object} value The value to test.
* @return {Boolean}
*/
isString: function(value) {
return typeof value === 'string';
},
/**
* Returns `true` if the passed value is a Boolean.
*
* @param {Object} value The value to test.
* @return {Boolean}
*/
isBoolean: function(value) {
return typeof value === 'boolean';
},
/**
* Returns `true` if the passed value is an HTMLElement.
* @param {Object} value The value to test.
* @return {Boolean}
*/
isElement: function(value) {
return value ? value.nodeType === 1 : false;
},
/**
* Returns `true` if the passed value is a TextNode.
* @param {Object} 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 {Object} 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 {Object} 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 {Object} item The variable to clone.
* @return {Object} clone
*/
clone: function(item) {
if (item === null || item === undefined) {
return item;
}
// DOM nodes
if (item.nodeType && item.cloneNode) {
return item.cloneNode(true);
}
// Strings
var type = toString.call(item);
// Dates
if (type === '[object Date]') {
return new Date(item.getTime());
}
var i, j, k, clone, key;
// Arrays
if (type === '[object Array]') {
i = item.length;
clone = [];
while (i--) {
clone[i] = Ext.clone(item[i]);
}
}
// Objects
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 = 'ExtBox' + (++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),
ln = args.length;
if (ln > 0) {
args[ln - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' + args[ln - 1];
}
return Function.prototype.constructor.apply(Function.prototype, args);
},
/**
* @private
*/
globalEval: ('execScript' in global) ? function(code) {
global.execScript(code)
} : function(code) {
(function(){
eval(code);
})();
}
//<feature logger>
/**
* @private
* @property
*/
,Logger: {
log: function(message, priority) {
if ('console' in global) {
if (!priority || !(priority in global.console)) {
priority = 'log';
}
message = '[' + priority.toUpperCase() + '] ' + message;
global.console[priority](message);
}
},
verbose: function(message) {
this.log(message, 'verbose');
},
info: function(message) {
this.log(message, 'info');
},
warn: function(message) {
this.log(message, 'warn');
},
error: function(message) {
throw new Error(message);
},
deprecate: function(message) {
this.log(message, 'warn');
}
}
//</feature>
});
/**
* Old alias to {@link Ext#typeOf}.
* @deprecated 4.0.0 Please use {@link Ext#typeOf} instead.
* @method
* @alias Ext#typeOf
*/
Ext.type = Ext.typeOf;
})();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,743 @@
//@tag foundation,core
//@define Ext.Class
//@require Ext.Base
/**
* @class Ext.Class
*
* @author Jacky Nguyen <jacky@sencha.com>
* @aside guide class_system
* @aside video class-system
*
* Handles class creation throughout the framework. This is a low level factory that is used by Ext.ClassManager and generally
* should not be used directly. If you choose to use Ext.Class you will lose out on the namespace, aliasing and dependency loading
* features made available by Ext.ClassManager. The only time you would use Ext.Class directly is to create an anonymous class.
*
* If you wish to create a class you should use {@link Ext#define Ext.define} which aliases
* {@link Ext.ClassManager#create Ext.ClassManager.create} to enable namespacing and dynamic dependency resolution.
*
* Ext.Class is the factory and **not** the superclass of everything. For the base class that **all** Ext classes inherit
* from, see {@link Ext.Base}.
*/
(function() {
var ExtClass,
Base = Ext.Base,
baseStaticMembers = [],
baseStaticMember, baseStaticMemberLength;
for (baseStaticMember in Base) {
if (Base.hasOwnProperty(baseStaticMember)) {
baseStaticMembers.push(baseStaticMember);
}
}
baseStaticMemberLength = baseStaticMembers.length;
/**
* @method constructor
* Creates a new anonymous class.
*
* @param {Object} data An object represent the properties of this class.
* @param {Function} onCreated (optional) The callback function to be executed when this class is fully created.
* Note that the creation process can be asynchronous depending on the pre-processors used.
*
* @return {Ext.Base} The newly created class
*/
Ext.Class = ExtClass = function(Class, data, onCreated) {
if (typeof Class != 'function') {
onCreated = data;
data = Class;
Class = null;
}
if (!data) {
data = {};
}
Class = ExtClass.create(Class);
ExtClass.process(Class, data, onCreated);
return Class;
};
Ext.apply(ExtClass, {
/**
* @private
* @static
*/
onBeforeCreated: function(Class, data, hooks) {
Class.addMembers(data);
hooks.onCreated.call(Class, Class);
},
/**
* @private
* @static
*/
create: function(Class) {
var name, i;
if (!Class) {
Class = function() {
return this.constructor.apply(this, arguments);
};
}
for (i = 0; i < baseStaticMemberLength; i++) {
name = baseStaticMembers[i];
Class[name] = Base[name];
}
return Class;
},
/**
* @private
* @static
*/
process: function(Class, data, onCreated) {
var preprocessorStack = data.preprocessors || ExtClass.defaultPreprocessors,
preprocessors = this.preprocessors,
hooks = {
onBeforeCreated: this.onBeforeCreated,
onCreated: onCreated || Ext.emptyFn
},
index = 0,
name, preprocessor, properties,
i, ln, fn, property, process;
delete data.preprocessors;
process = function(Class, data, hooks) {
fn = null;
while (fn === null) {
name = preprocessorStack[index++];
if (name) {
preprocessor = preprocessors[name];
properties = preprocessor.properties;
if (properties === true) {
fn = preprocessor.fn;
}
else {
for (i = 0,ln = properties.length; i < ln; i++) {
property = properties[i];
if (data.hasOwnProperty(property)) {
fn = preprocessor.fn;
break;
}
}
}
}
else {
hooks.onBeforeCreated.apply(this, arguments);
return;
}
}
if (fn.call(this, Class, data, hooks, process) !== false) {
process.apply(this, arguments);
}
};
process.call(this, Class, data, hooks);
},
/**
* @private
* @static
*/
preprocessors: {},
/**
* Register a new pre-processor to be used during the class creation process.
*
* @private
* @static
* @param {String} name The pre-processor's name.
* @param {Function} fn The callback function to be executed. Typical format:
*
* function(cls, data, fn) {
* // Your code here
*
* // Execute this when the processing is finished.
* // Asynchronous processing is perfectly OK
* if (fn) {
* fn.call(this, cls, data);
* }
* });
*
* @param {Function} fn.cls The created class.
* @param {Object} fn.data The set of properties passed in {@link Ext.Class} constructor.
* @param {Function} fn.fn The callback function that __must__ to be executed when this pre-processor finishes,
* regardless of whether the processing is synchronous or asynchronous.
*
* @return {Ext.Class} this
*/
registerPreprocessor: function(name, fn, properties, position, relativeTo) {
if (!position) {
position = 'last';
}
if (!properties) {
properties = [name];
}
this.preprocessors[name] = {
name: name,
properties: properties || false,
fn: fn
};
this.setDefaultPreprocessorPosition(name, position, relativeTo);
return this;
},
/**
* Retrieve a pre-processor callback function by its name, which has been registered before.
*
* @private
* @static
* @param {String} name
* @return {Function} preprocessor
*/
getPreprocessor: function(name) {
return this.preprocessors[name];
},
/**
* @private
* @static
*/
getPreprocessors: function() {
return this.preprocessors;
},
/**
* @private
* @static
*/
defaultPreprocessors: [],
/**
* Retrieve the array stack of default pre-processors.
* @private
* @static
* @return {Function} defaultPreprocessors
*/
getDefaultPreprocessors: function() {
return this.defaultPreprocessors;
},
/**
* Set the default array stack of default pre-processors.
*
* @private
* @static
* @param {Array} preprocessors
* @return {Ext.Class} this
*/
setDefaultPreprocessors: function(preprocessors) {
this.defaultPreprocessors = Ext.Array.from(preprocessors);
return this;
},
/**
* Insert this pre-processor at a specific position in the stack, optionally relative to
* any existing pre-processor. For example:
*
* Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
* // Your code here
*
* if (fn) {
* fn.call(this, cls, data);
* }
* }).insertDefaultPreprocessor('debug', 'last');
*
* @private
* @static
* @param {String} name The pre-processor name. Note that it needs to be registered with
* {@link Ext.Class#registerPreprocessor registerPreprocessor} before this.
* @param {String} offset The insertion position. Four possible values are:
* 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument).
* @param {String} relativeName
* @return {Ext.Class} this
*/
setDefaultPreprocessorPosition: function(name, offset, relativeName) {
var defaultPreprocessors = this.defaultPreprocessors,
index;
if (typeof offset == 'string') {
if (offset === 'first') {
defaultPreprocessors.unshift(name);
return this;
}
else if (offset === 'last') {
defaultPreprocessors.push(name);
return this;
}
offset = (offset === 'after') ? 1 : -1;
}
index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
if (index !== -1) {
Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name);
}
return this;
},
/**
* @private
* @static
*/
configNameCache: {},
/**
* @private
* @static
*/
getConfigNameMap: function(name) {
var cache = this.configNameCache,
map = cache[name],
capitalizedName;
if (!map) {
capitalizedName = name.charAt(0).toUpperCase() + name.substr(1);
map = cache[name] = {
name: name,
internal: '_' + name,
initializing: 'is' + capitalizedName + 'Initializing',
apply: 'apply' + capitalizedName,
update: 'update' + capitalizedName,
set: 'set' + capitalizedName,
get: 'get' + capitalizedName,
initGet: 'initGet' + capitalizedName,
doSet : 'doSet' + capitalizedName,
changeEvent: name.toLowerCase() + 'change'
}
}
return map;
},
/**
* @private
* @static
*/
generateSetter: function(nameMap) {
var internalName = nameMap.internal,
getName = nameMap.get,
applyName = nameMap.apply,
updateName = nameMap.update,
setter;
setter = function(value) {
var oldValue = this[internalName],
applier = this[applyName],
updater = this[updateName];
delete this[getName];
if (applier) {
value = applier.call(this, value, oldValue);
}
if (typeof value != 'undefined') {
this[internalName] = value;
if (updater && value !== oldValue) {
updater.call(this, value, oldValue);
}
}
return this;
};
setter.$isDefault = true;
return setter;
},
/**
* @private
* @static
*/
generateInitGetter: function(nameMap) {
var name = nameMap.name,
setName = nameMap.set,
getName = nameMap.get,
initializingName = nameMap.initializing;
return function() {
this[initializingName] = true;
delete this[getName];
this[setName].call(this, this.config[name]);
delete this[initializingName];
return this[getName].apply(this, arguments);
}
},
/**
* @private
* @static
*/
generateGetter: function(nameMap) {
var internalName = nameMap.internal;
return function() {
return this[internalName];
}
}
});
/**
* @cfg {String} extend
* The parent class that this class extends. For example:
*
* @example
* Ext.define('Person', {
* say: function(text) {
* alert(text);
* }
* });
*
* Ext.define('Developer', {
* extend: 'Person',
* say: function(text) {
* this.callParent(["print " + text]);
* }
* });
*
* var person1 = Ext.create("Person");
* person1.say("Bill");
*
* var developer1 = Ext.create("Developer");
* developer1.say("Ted");
*/
ExtClass.registerPreprocessor('extend', function(Class, data) {
var Base = Ext.Base,
extend = data.extend,
Parent;
delete data.extend;
if (extend && extend !== Object) {
Parent = extend;
}
else {
Parent = Base;
}
Class.extend(Parent);
Class.triggerExtended.apply(Class, arguments);
if (data.onClassExtended) {
Class.onExtended(data.onClassExtended, Class);
delete data.onClassExtended;
}
}, true);
//<feature classSystem.statics>
/**
* @cfg {Object} statics
* List of static methods for this class. For example:
*
* Ext.define('Computer', {
* statics: {
* factory: function(brand) {
* // 'this' in static methods refer to the class itself
* return new this(brand);
* }
* },
*
* constructor: function() {
* // ...
* }
* });
*
* var dellComputer = Computer.factory('Dell');
*/
ExtClass.registerPreprocessor('statics', function(Class, data) {
Class.addStatics(data.statics);
delete data.statics;
});
//</feature>
//<feature classSystem.inheritableStatics>
/**
* @cfg {Object} inheritableStatics
* List of inheritable static methods for this class.
* Otherwise just like {@link #statics} but subclasses inherit these methods.
*/
ExtClass.registerPreprocessor('inheritableStatics', function(Class, data) {
Class.addInheritableStatics(data.inheritableStatics);
delete data.inheritableStatics;
});
//</feature>
//<feature classSystem.config>
/**
* @cfg {Object} config
*
* List of configuration options with their default values.
*
* __Note:__ You need to make sure {@link Ext.Base#initConfig} is called from your constructor if you are defining
* your own class or singleton, unless you are extending a Component. Otherwise the generated getter and setter
* methods will not be initialized.
*
* Each config item will have its own setter and getter method automatically generated inside the class prototype
* during class creation time, if the class does not have those methods explicitly defined.
*
* As an example, let's convert the name property of a Person class to be a config item, then add extra age and
* gender items.
*
* Ext.define('My.sample.Person', {
* config: {
* name: 'Mr. Unknown',
* age: 0,
* gender: 'Male'
* },
*
* constructor: function(config) {
* this.initConfig(config);
*
* return this;
* }
*
* // ...
* });
*
* Within the class, this.name still has the default value of "Mr. Unknown". However, it's now publicly accessible
* without sacrificing encapsulation, via setter and getter methods.
*
* var jacky = new Person({
* name: "Jacky",
* age: 35
* });
*
* alert(jacky.getAge()); // alerts 35
* alert(jacky.getGender()); // alerts "Male"
*
* jacky.walk(10); // alerts "Jacky is walking 10 steps"
*
* jacky.setName("Mr. Nguyen");
* alert(jacky.getName()); // alerts "Mr. Nguyen"
*
* jacky.walk(10); // alerts "Mr. Nguyen is walking 10 steps"
*
* Notice that we changed the class constructor to invoke this.initConfig() and pass in the provided config object.
* Two key things happened:
*
* - The provided config object when the class is instantiated is recursively merged with the default config object.
* - All corresponding setter methods are called with the merged values.
*
* Beside storing the given values, throughout the frameworks, setters generally have two key responsibilities:
*
* - Filtering / validation / transformation of the given value before it's actually stored within the instance.
* - Notification (such as firing events) / post-processing after the value has been set, or changed from a
* previous value.
*
* By standardize this common pattern, the default generated setters provide two extra template methods that you
* can put your own custom logics into, i.e: an "applyFoo" and "updateFoo" method for a "foo" config item, which are
* executed before and after the value is actually set, respectively. Back to the example class, let's validate that
* age must be a valid positive number, and fire an 'agechange' if the value is modified.
*
* Ext.define('My.sample.Person', {
* config: {
* // ...
* },
*
* constructor: {
* // ...
* },
*
* applyAge: function(age) {
* if (typeof age !== 'number' || age < 0) {
* console.warn("Invalid age, must be a positive number");
* return;
* }
*
* return age;
* },
*
* updateAge: function(newAge, oldAge) {
* // age has changed from "oldAge" to "newAge"
* this.fireEvent('agechange', this, newAge, oldAge);
* }
*
* // ...
* });
*
* var jacky = new Person({
* name: "Jacky",
* age: 'invalid'
* });
*
* alert(jacky.getAge()); // alerts 0
*
* alert(jacky.setAge(-100)); // alerts 0
* alert(jacky.getAge()); // alerts 0
*
* alert(jacky.setAge(35)); // alerts 0
* alert(jacky.getAge()); // alerts 35
*
* In other words, when leveraging the config feature, you mostly never need to define setter and getter methods
* explicitly. Instead, "apply*" and "update*" methods should be implemented where necessary. Your code will be
* consistent throughout and only contain the minimal logic that you actually care about.
*
* When it comes to inheritance, the default config of the parent class is automatically, recursively merged with
* the child's default config. The same applies for mixins.
*/
ExtClass.registerPreprocessor('config', function(Class, data) {
var config = data.config,
prototype = Class.prototype,
defaultConfig = prototype.config,
nameMap, name, setName, getName, initGetName, internalName, value;
delete data.config;
for (name in config) {
// Once per config item, per class hierarchy
if (config.hasOwnProperty(name) && !(name in defaultConfig)) {
value = config[name];
nameMap = this.getConfigNameMap(name);
setName = nameMap.set;
getName = nameMap.get;
initGetName = nameMap.initGet;
internalName = nameMap.internal;
data[initGetName] = this.generateInitGetter(nameMap);
if (value === null && !data.hasOwnProperty(internalName)) {
data[internalName] = null;
}
if (!data.hasOwnProperty(getName)) {
data[getName] = this.generateGetter(nameMap);
}
if (!data.hasOwnProperty(setName)) {
data[setName] = this.generateSetter(nameMap);
}
}
}
Class.addConfig(config, true);
});
//</feature>
//<feature classSystem.mixins>
/**
* @cfg {Object} mixins
* List of classes to mix into this class. For example:
*
* Ext.define('CanSing', {
* sing: function() {
* alert("I'm on the highway to hell...");
* }
* });
*
* Ext.define('Musician', {
* extend: 'Person',
*
* mixins: {
* canSing: 'CanSing'
* }
* });
*/
ExtClass.registerPreprocessor('mixins', function(Class, data, hooks) {
var mixins = data.mixins,
name, mixin, i, ln;
delete data.mixins;
Ext.Function.interceptBefore(hooks, 'onCreated', function() {
if (mixins instanceof Array) {
for (i = 0,ln = mixins.length; i < ln; i++) {
mixin = mixins[i];
name = mixin.prototype.mixinId || mixin.$className;
Class.mixin(name, mixin);
}
}
else {
for (name in mixins) {
if (mixins.hasOwnProperty(name)) {
Class.mixin(name, mixins[name]);
}
}
}
});
});
//</feature>
//<feature classSystem.backwardsCompatible>
// Backwards compatible
Ext.extend = function(Class, Parent, members) {
if (arguments.length === 2 && Ext.isObject(Parent)) {
members = Parent;
Parent = Class;
Class = null;
}
var cls;
if (!Parent) {
throw new Error("[Ext.extend] Attempting to extend from a class which has not been loaded on the page.");
}
members.extend = Parent;
members.preprocessors = [
'extend'
//<feature classSystem.statics>
,'statics'
//</feature>
//<feature classSystem.inheritableStatics>
,'inheritableStatics'
//</feature>
//<feature classSystem.mixins>
,'mixins'
//</feature>
//<feature classSystem.config>
,'config'
//</feature>
];
if (Class) {
cls = new ExtClass(Class, members);
}
else {
cls = new ExtClass(members);
}
cls.prototype.override = function(o) {
for (var m in o) {
if (o.hasOwnProperty(m)) {
this[m] = o[m];
}
}
};
return cls;
};
//</feature>
})();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
//@tag foundation,core
//@define Ext.Date
//@require Ext.Error
/**
*
*/
Ext.Date = {
/** @ignore */
now: Date.now,
/**
* @private
* Private for now
*/
toString: function(date) {
if (!date) {
date = new Date();
}
var pad = Ext.String.leftPad;
return date.getFullYear() + "-"
+ pad(date.getMonth() + 1, 2, '0') + "-"
+ pad(date.getDate(), 2, '0') + "T"
+ pad(date.getHours(), 2, '0') + ":"
+ pad(date.getMinutes(), 2, '0') + ":"
+ pad(date.getSeconds(), 2, '0');
}
};
//<deprecated product=touch since="2.0">
Ext.merge(Ext, {
util: {
Date: Ext.Date
}
});
//</deprecated>

View File

@@ -0,0 +1,9 @@
//@tag foundation,core
//@define Ext.Error
//@require Ext.JSON
Ext.Error = {
raise: function(object) {
throw new Error(object.msg);
}
};

View File

@@ -0,0 +1,426 @@
//@tag foundation,core
//@define Ext.Function
//@require Ext.Object
/**
* @class Ext.Function
*
* A collection of useful static methods to deal with function callbacks.
* @singleton
* @alternateClassName Ext.util.Functions
*/
Ext.Function = {
/**
* A very commonly used method throughout the framework. It acts as a wrapper around another method
* which originally accepts 2 arguments for `name` and `value`.
* The wrapped function then allows "flexible" value setting of either:
*
* - `name` and `value` as 2 arguments
* - one single object argument with multiple key - value pairs
*
* For example:
*
* var setValue = Ext.Function.flexSetter(function(name, value) {
* this[name] = value;
* });
*
* // Afterwards
* // Setting a single name - value
* setValue('name1', 'value1');
*
* // Settings multiple name - value pairs
* setValue({
* name1: 'value1',
* name2: 'value2',
* name3: 'value3'
* });
*
* @param {Function} setter
* @return {Function} flexSetter
*/
flexSetter: function(fn) {
return function(a, b) {
var k, i;
if (a === null) {
return this;
}
if (typeof a !== 'string') {
for (k in a) {
if (a.hasOwnProperty(k)) {
fn.call(this, k, a[k]);
}
}
if (Ext.enumerables) {
for (i = Ext.enumerables.length; i--;) {
k = Ext.enumerables[i];
if (a.hasOwnProperty(k)) {
fn.call(this, k, a[k]);
}
}
}
} else {
fn.call(this, a, b);
}
return this;
};
},
/**
* Create a new function from the provided `fn`, change `this` to the provided scope, optionally
* overrides arguments for the call. Defaults to the arguments passed by the caller.
*
* {@link Ext#bind Ext.bind} is alias for {@link Ext.Function#bind Ext.Function.bind}
*
* @param {Function} fn The function to delegate.
* @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
* **If omitted, defaults to the browser window.**
* @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
* @param {Boolean/Number} appendArgs (optional) if `true` args are appended to call args instead of overriding,
* if a number the args are inserted at the specified position.
* @return {Function} The new function.
*/
bind: function(fn, scope, args, appendArgs) {
if (arguments.length === 2) {
return function() {
return fn.apply(scope, arguments);
}
}
var method = fn,
slice = Array.prototype.slice;
return function() {
var callArgs = args || arguments;
if (appendArgs === true) {
callArgs = slice.call(arguments, 0);
callArgs = callArgs.concat(args);
}
else if (typeof appendArgs == 'number') {
callArgs = slice.call(arguments, 0); // copy arguments first
Ext.Array.insert(callArgs, appendArgs, args);
}
return method.apply(scope || window, callArgs);
};
},
/**
* Create a new function from the provided `fn`, the arguments of which are pre-set to `args`.
* New arguments passed to the newly created callback when it's invoked are appended after the pre-set ones.
* This is especially useful when creating callbacks.
*
* For example:
*
* var originalFunction = function(){
* alert(Ext.Array.from(arguments).join(' '));
* };
*
* var callback = Ext.Function.pass(originalFunction, ['Hello', 'World']);
*
* callback(); // alerts 'Hello World'
* callback('by Me'); // alerts 'Hello World by Me'
*
* {@link Ext#pass Ext.pass} is alias for {@link Ext.Function#pass Ext.Function.pass}
*
* @param {Function} fn The original function.
* @param {Array} args The arguments to pass to new callback.
* @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
* @return {Function} The new callback function.
*/
pass: function(fn, args, scope) {
if (!Ext.isArray(args)) {
args = Ext.Array.clone(args);
}
return function() {
args.push.apply(args, arguments);
return fn.apply(scope || this, args);
};
},
/**
* Create an alias to the provided method property with name `methodName` of `object`.
* Note that the execution scope will still be bound to the provided `object` itself.
*
* @param {Object/Function} object
* @param {String} methodName
* @return {Function} aliasFn
*/
alias: function(object, methodName) {
return function() {
return object[methodName].apply(object, arguments);
};
},
/**
* Create a "clone" of the provided method. The returned method will call the given
* method passing along all arguments and the "this" pointer and return its result.
*
* @param {Function} method
* @return {Function} cloneFn
*/
clone: function(method) {
return function() {
return method.apply(this, arguments);
};
},
/**
* Creates an interceptor function. The passed function is called before the original one. If it returns false,
* the original one is not called. The resulting function returns the results of the original function.
* The passed function is called with the parameters of the original function. Example usage:
*
* var sayHi = function(name){
* alert('Hi, ' + name);
* };
*
* sayHi('Fred'); // alerts "Hi, Fred"
*
* // create a new function that validates input without
* // directly modifying the original function:
* var sayHiToFriend = Ext.Function.createInterceptor(sayHi, function(name){
* return name === 'Brian';
* });
*
* sayHiToFriend('Fred'); // no alert
* sayHiToFriend('Brian'); // alerts "Hi, Brian"
*
* @param {Function} origFn The original function.
* @param {Function} newFn The function to call before the original.
* @param {Object} scope (optional) The scope (`this` reference) in which the passed function is executed.
* **If omitted, defaults to the scope in which the original function is called or the browser window.**
* @param {Object} [returnValue=null] (optional) The value to return if the passed function return `false`.
* @return {Function} The new function.
*/
createInterceptor: function(origFn, newFn, scope, returnValue) {
var method = origFn;
if (!Ext.isFunction(newFn)) {
return origFn;
}
else {
return function() {
var me = this,
args = arguments;
newFn.target = me;
newFn.method = origFn;
return (newFn.apply(scope || me || window, args) !== false) ? origFn.apply(me || window, args) : returnValue || null;
};
}
},
/**
* Creates a delegate (callback) which, when called, executes after a specific delay.
*
* @param {Function} fn The function which will be called on a delay when the returned function is called.
* Optionally, a replacement (or additional) argument list may be specified.
* @param {Number} delay The number of milliseconds to defer execution by whenever called.
* @param {Object} scope (optional) The scope (`this` reference) used by the function at execution time.
* @param {Array} args (optional) Override arguments for the call. (Defaults to the arguments passed by the caller)
* @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
* if a number the args are inserted at the specified position.
* @return {Function} A function which, when called, executes the original function after the specified delay.
*/
createDelayed: function(fn, delay, scope, args, appendArgs) {
if (scope || args) {
fn = Ext.Function.bind(fn, scope, args, appendArgs);
}
return function() {
var me = this,
args = Array.prototype.slice.call(arguments);
setTimeout(function() {
fn.apply(me, args);
}, delay);
}
},
/**
* Calls this function after the number of milliseconds specified, optionally in a specific scope. Example usage:
*
* var sayHi = function(name){
* alert('Hi, ' + name);
* };
*
* // executes immediately:
* sayHi('Fred');
*
* // executes after 2 seconds:
* Ext.Function.defer(sayHi, 2000, this, ['Fred']);
*
* // this syntax is sometimes useful for deferring
* // execution of an anonymous function:
* Ext.Function.defer(function(){
* alert('Anonymous');
* }, 100);
*
* {@link Ext#defer Ext.defer} is alias for {@link Ext.Function#defer Ext.Function.defer}
*
* @param {Function} fn The function to defer.
* @param {Number} millis The number of milliseconds for the `setTimeout()` call.
* If less than or equal to 0 the function is executed immediately.
* @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
* If omitted, defaults to the browser window.
* @param {Array} args (optional) Overrides arguments for the call. Defaults to the arguments passed by the caller.
* @param {Boolean/Number} appendArgs (optional) if `true`, args are appended to call args instead of overriding,
* if a number the args are inserted at the specified position.
* @return {Number} The timeout id that can be used with `clearTimeout()`.
*/
defer: function(fn, millis, scope, args, appendArgs) {
fn = Ext.Function.bind(fn, scope, args, appendArgs);
if (millis > 0) {
return setTimeout(fn, millis);
}
fn();
return 0;
},
/**
* Create a combined function call sequence of the original function + the passed function.
* The resulting function returns the results of the original function.
* The passed function is called with the parameters of the original function. Example usage:
*
* var sayHi = function(name){
* alert('Hi, ' + name);
* };
*
* sayHi('Fred'); // alerts "Hi, Fred"
*
* var sayGoodbye = Ext.Function.createSequence(sayHi, function(name){
* alert('Bye, ' + name);
* });
*
* sayGoodbye('Fred'); // both alerts show
*
* @param {Function} originalFn The original function.
* @param {Function} newFn The function to sequence.
* @param {Object} scope (optional) The scope (`this` reference) in which the passed function is executed.
* If omitted, defaults to the scope in which the original function is called or the browser window.
* @return {Function} The new function.
*/
createSequence: function(originalFn, newFn, scope) {
if (!newFn) {
return originalFn;
}
else {
return function() {
var result = originalFn.apply(this, arguments);
newFn.apply(scope || this, arguments);
return result;
};
}
},
/**
* Creates a delegate function, optionally with a bound scope which, when called, buffers
* the execution of the passed function for the configured number of milliseconds.
* If called again within that period, the impending invocation will be canceled, and the
* timeout period will begin again.
*
* @param {Function} fn The function to invoke on a buffered timer.
* @param {Number} buffer The number of milliseconds by which to buffer the invocation of the
* function.
* @param {Object} scope (optional) The scope (`this` reference) in which
* the passed function is executed. If omitted, defaults to the scope specified by the caller.
* @param {Array} args (optional) Override arguments for the call. Defaults to the arguments
* passed by the caller.
* @return {Function} A function which invokes the passed function after buffering for the specified time.
*/
createBuffered: function(fn, buffer, scope, args) {
var timerId;
return function() {
var callArgs = args || Array.prototype.slice.call(arguments, 0),
me = scope || this;
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(function(){
fn.apply(me, callArgs);
}, buffer);
};
},
/**
* Creates a throttled version of the passed function which, when called repeatedly and
* rapidly, invokes the passed function only after a certain interval has elapsed since the
* previous invocation.
*
* This is useful for wrapping functions which may be called repeatedly, such as
* a handler of a mouse move event when the processing is expensive.
*
* @param {Function} fn The function to execute at a regular time interval.
* @param {Number} interval The interval, in milliseconds, on which the passed function is executed.
* @param {Object} scope (optional) The scope (`this` reference) in which
* the passed function is executed. If omitted, defaults to the scope specified by the caller.
* @return {Function} A function which invokes the passed function at the specified interval.
*/
createThrottled: function(fn, interval, scope) {
var lastCallTime, elapsed, lastArgs, timer, execute = function() {
fn.apply(scope || this, lastArgs);
lastCallTime = new Date().getTime();
};
return function() {
elapsed = new Date().getTime() - lastCallTime;
lastArgs = arguments;
clearTimeout(timer);
if (!lastCallTime || (elapsed >= interval)) {
execute();
} else {
timer = setTimeout(execute, interval - elapsed);
}
};
},
interceptBefore: function(object, methodName, fn) {
var method = object[methodName] || Ext.emptyFn;
return object[methodName] = function() {
var ret = fn.apply(this, arguments);
method.apply(this, arguments);
return ret;
};
},
interceptAfter: function(object, methodName, fn) {
var method = object[methodName] || Ext.emptyFn;
return object[methodName] = function() {
method.apply(this, arguments);
return fn.apply(this, arguments);
};
}
};
/**
* @method
* @member Ext
* @alias Ext.Function#defer
*/
Ext.defer = Ext.Function.alias(Ext.Function, 'defer');
/**
* @method
* @member Ext
* @alias Ext.Function#pass
*/
Ext.pass = Ext.Function.alias(Ext.Function, 'pass');
/**
* @method
* @member Ext
* @alias Ext.Function#bind
*/
Ext.bind = Ext.Function.alias(Ext.Function, 'bind');

View File

@@ -0,0 +1,181 @@
//@tag foundation,core
//@define Ext.JSON
//@require Ext.Function
/**
* @class Ext.JSON
* Modified version of Douglas Crockford's json.js that doesn't
* mess with the Object prototype.
* [http://www.json.org/js.html](http://www.json.org/js.html)
* @singleton
*/
Ext.JSON = new(function() {
var useHasOwn = !! {}.hasOwnProperty,
isNative = function() {
var useNative = null;
return function() {
if (useNative === null) {
useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
}
return useNative;
};
}(),
pad = function(n) {
return n < 10 ? "0" + n : n;
},
doDecode = function(json) {
return eval("(" + json + ')');
},
doEncode = function(o) {
if (!Ext.isDefined(o) || o === null) {
return "null";
} else if (Ext.isArray(o)) {
return encodeArray(o);
} else if (Ext.isDate(o)) {
return Ext.JSON.encodeDate(o);
} else if (Ext.isString(o)) {
return encodeString(o);
} else if (typeof o == "number") {
//don't use isNumber here, since finite checks happen inside isNumber
return isFinite(o) ? String(o) : "null";
} else if (Ext.isBoolean(o)) {
return String(o);
} else if (Ext.isObject(o)) {
return encodeObject(o);
} else if (typeof o === "function") {
return "null";
}
return 'undefined';
},
m = {
"\b": '\\b',
"\t": '\\t',
"\n": '\\n',
"\f": '\\f',
"\r": '\\r',
'"': '\\"',
"\\": '\\\\',
'\x0b': '\\u000b' //ie doesn't handle \v
},
charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
encodeString = function(s) {
return '"' + s.replace(charToReplace, function(a) {
var c = m[a];
return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"';
},
encodeArray = function(o) {
var a = ["[", ""],
// Note empty string in case there are no serializable members.
len = o.length,
i;
for (i = 0; i < len; i += 1) {
a.push(doEncode(o[i]), ',');
}
// Overwrite trailing comma (or empty string)
a[a.length - 1] = ']';
return a.join("");
},
encodeObject = function(o) {
var a = ["{", ""],
// Note empty string in case there are no serializable members.
i;
for (i in o) {
if (!useHasOwn || o.hasOwnProperty(i)) {
a.push(doEncode(i), ":", doEncode(o[i]), ',');
}
}
// Overwrite trailing comma (or empty string)
a[a.length - 1] = '}';
return a.join("");
};
/**
* Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
* __The returned value includes enclosing double quotation marks.__
*
* The default return format is "yyyy-mm-ddThh:mm:ss".
*
* To override this:
*
* Ext.JSON.encodeDate = function(d) {
* return Ext.Date.format(d, '"Y-m-d"');
* };
*
* @param {Date} d The Date to encode.
* @return {String} The string literal to use in a JSON string.
*/
this.encodeDate = function(o) {
return '"' + o.getFullYear() + "-"
+ pad(o.getMonth() + 1) + "-"
+ pad(o.getDate()) + "T"
+ pad(o.getHours()) + ":"
+ pad(o.getMinutes()) + ":"
+ pad(o.getSeconds()) + '"';
};
/**
* Encodes an Object, Array or other value.
* @param {Object} o The variable to encode.
* @return {String} The JSON string.
* @method
*/
this.encode = function() {
var ec;
return function(o) {
if (!ec) {
// setup encoding function on first access
ec = isNative() ? JSON.stringify : doEncode;
}
return ec(o);
};
}();
/**
* Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a Error unless the safe option is set.
* @param {String} json The JSON string.
* @param {Boolean} safe (optional) Whether to return `null` or throw an exception if the JSON is invalid.
* @return {Object/null} The resulting object.
* @method
*/
this.decode = function() {
var dc;
return function(json, safe) {
if (!dc) {
// setup decoding function on first access
dc = isNative() ? JSON.parse : doDecode;
}
try {
return dc(json);
} catch (e) {
if (safe === true) {
return null;
}
Ext.Error.raise({
sourceClass: "Ext.JSON",
sourceMethod: "decode",
msg: "You're trying to decode an invalid JSON String: " + json
});
}
};
}();
})();
/**
* Shorthand for {@link Ext.JSON#encode}.
* @member Ext
* @method encode
* @alias Ext.JSON#encode
*/
Ext.encode = Ext.JSON.encode;
/**
* Shorthand for {@link Ext.JSON#decode}.
* @member Ext
* @method decode
* @alias Ext.JSON#decode
*/
Ext.decode = Ext.JSON.decode;

View File

@@ -0,0 +1,111 @@
//@tag foundation,core
//@define Ext.Number
//@require Ext.Array
/**
* @class Ext.Number
*
* A collection of useful static methods to deal with numbers
* @singleton
*/
(function() {
var isToFixedBroken = (0.9).toFixed() !== '1';
Ext.Number = {
/**
* Checks whether or not the passed number is within a desired range. If the number is already within the
* range it is returned, otherwise the min or max value is returned depending on which side of the range is
* exceeded. Note that this method returns the constrained value but does not change the current number.
* @param {Number} number The number to check
* @param {Number} min The minimum number in the range
* @param {Number} max The maximum number in the range
* @return {Number} The constrained value if outside the range, otherwise the current value
*/
constrain: function(number, min, max) {
number = parseFloat(number);
if (!isNaN(min)) {
number = Math.max(number, min);
}
if (!isNaN(max)) {
number = Math.min(number, max);
}
return number;
},
/**
* Snaps the passed number between stopping points based upon a passed increment value.
* @param {Number} value The unsnapped value.
* @param {Number} increment The increment by which the value must move.
* @param {Number} minValue The minimum value to which the returned value must be constrained. Overrides the increment..
* @param {Number} maxValue The maximum value to which the returned value must be constrained. Overrides the increment..
* @return {Number} The value of the nearest snap target.
*/
snap : function(value, increment, minValue, maxValue) {
var newValue = value,
m;
if (!(increment && value)) {
return value;
}
m = value % increment;
if (m !== 0) {
newValue -= m;
if (m * 2 >= increment) {
newValue += increment;
} else if (m * 2 < -increment) {
newValue -= increment;
}
}
return Ext.Number.constrain(newValue, minValue, maxValue);
},
/**
* Formats a number using fixed-point notation
* @param {Number} value The number to format
* @param {Number} precision The number of digits to show after the decimal point
*/
toFixed: function(value, precision) {
if (isToFixedBroken) {
precision = precision || 0;
var pow = Math.pow(10, precision);
return (Math.round(value * pow) / pow).toFixed(precision);
}
return value.toFixed(precision);
},
/**
* Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
* it is not.
Ext.Number.from('1.23', 1); // returns 1.23
Ext.Number.from('abc', 1); // returns 1
* @param {Object} value
* @param {Number} defaultValue The value to return if the original value is non-numeric
* @return {Number} value, if numeric, defaultValue otherwise
*/
from: function(value, defaultValue) {
if (isFinite(value)) {
value = parseFloat(value);
}
return !isNaN(value) ? value : defaultValue;
}
};
})();
/**
* This method is deprecated, please use {@link Ext.Number#from Ext.Number.from} instead
*
* @deprecated 4.0.0 Replaced by Ext.Number.from
* @member Ext
* @method num
*/
Ext.num = function() {
return Ext.Number.from.apply(this, arguments);
};

View File

@@ -0,0 +1,630 @@
//@tag foundation,core
//@define Ext.Object
//@require Ext.Number
/**
* @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() {
// The "constructor" for chain:
var TemplateClass = function(){};
var ExtObject = Ext.Object = {
/**
* Returns a new object with the given object as the prototype chain.
* @param {Object} object The prototype chain for the new object.
*/
chain: ('create' in Object) ? function(object){
return Object.create(object);
} : function (object) {
TemplateClass.prototype = object;
var result = new TemplateClass();
TemplateClass.prototype = null;
return result;
},
/**
* Convert a `name` - `value` pair to an array of objects with support for nested structures; useful to construct
* query strings. For example:
*
* Non-recursive:
*
* var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
*
* // objects then equals:
* [
* { name: 'hobbies', value: 'reading' },
* { name: 'hobbies', value: 'cooking' },
* { name: 'hobbies', value: 'swimming' }
* ]
*
* Recursive:
*
* var objects = Ext.Object.toQueryObjects('dateOfBirth', {
* day: 3,
* month: 8,
* year: 1987,
* extra: {
* hour: 4,
* minute: 30
* }
* }, true);
*
* // 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} value
* @param {Boolean} [recursive=false] `true` to recursively encode any sub-objects.
* @return {Object[]} Array of objects with `name` and `value` fields.
*/
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;
},
/**
* 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('&');
},
/**
* 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;
},
/**
* Iterate through an object and invoke the given callback function for each iteration. The iteration can be stop
* 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 {Mixed} 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;
}
}
}
},
/**
* 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);
*
* // 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} source The first object into which to merge the others.
* @param {Object...} objs One or more objects to be merged into the first.
* @return {Object} The object that is created as a result of merging all the objects passed in.
*/
merge: function(source) {
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 = source[key];
if (sourceKey && sourceKey.constructor === Object) {
mergeFn(sourceKey, value);
}
else {
source[key] = cloneFn(value);
}
}
else {
source[key] = value;
}
}
}
return source;
},
/**
* @private
* @param source
*/
mergeIf: function(source) {
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 source)) {
value = object[key];
if (value && value.constructor === Object) {
source[key] = cloneFn(value);
}
else {
source[key] = value;
}
}
}
}
return source;
},
/**
* 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(sencha, '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;
},
/**
* 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;
},
/**
* 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) ? Object.keys : function(object) {
var keys = [],
property;
for (property in object) {
if (object.hasOwnProperty(property)) {
keys.push(property);
}
}
return keys;
},
/**
* 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;
},
/**
* @private
*/
classify: function(object) {
var objectProperties = [],
arrayProperties = [],
propertyClassesMap = {},
objectClass = function() {
var i = 0,
ln = objectProperties.length,
property;
for (; i < ln; i++) {
property = objectProperties[i];
this[property] = new propertyClassesMap[property];
}
ln = arrayProperties.length;
for (i = 0; i < ln; i++) {
property = arrayProperties[i];
this[property] = object[property].slice();
}
},
key, value, constructor;
for (key in object) {
if (object.hasOwnProperty(key)) {
value = object[key];
if (value) {
constructor = value.constructor;
if (constructor === Object) {
objectProperties.push(key);
propertyClassesMap[key] = ExtObject.classify(value);
}
else if (constructor === Array) {
arrayProperties.push(key);
}
}
}
}
objectClass.prototype = object;
return objectClass;
},
defineProperty: ('defineProperty' in Object) ? Object.defineProperty : function(object, name, descriptor) {
if (descriptor.get) {
object.__defineGetter__(name, descriptor.get);
}
if (descriptor.set) {
object.__defineSetter__(name, descriptor.set);
}
}
};
/**
* A convenient alias method for {@link Ext.Object#merge}.
*
* @member Ext
* @method merge
*/
Ext.merge = Ext.Object.merge;
/**
* @private
*/
Ext.mergeIf = Ext.Object.mergeIf;
/**
* A convenient alias method for {@link Ext.Object#toQueryString}.
*
* @member Ext
* @method urlEncode
* @deprecated 4.0.0 Please use `{@link Ext.Object#toQueryString 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);
};
/**
* A convenient alias method for {@link Ext.Object#fromQueryString}.
*
* @member Ext
* @method urlDecode
* @deprecated 4.0.0 Please use {@link Ext.Object#fromQueryString Ext.Object.fromQueryString} instead
*/
Ext.urlDecode = function() {
return ExtObject.fromQueryString.apply(ExtObject, arguments);
};
})();

View File

@@ -0,0 +1,262 @@
//@tag foundation,core
//@define Ext.String
//@require Ext.Version
/**
* @class Ext.String
*
* A collection of useful static methods to deal with strings.
* @singleton
*/
Ext.String = {
trimRegex: /^[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+|[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+$/g,
escapeRe: /('|\\)/g,
formatRe: /\{(\d+)\}/g,
escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
/**
* Convert certain characters (&, <, >, and ") to their HTML character equivalents for literal display in web pages.
* @param {String} value The string to encode.
* @return {String} The encoded text.
* @method
*/
htmlEncode: (function() {
var entities = {
'&': '&amp;',
'>': '&gt;',
'<': '&lt;',
'"': '&quot;'
}, keys = [], p, regex;
for (p in entities) {
keys.push(p);
}
regex = new RegExp('(' + keys.join('|') + ')', 'g');
return function(value) {
return (!value) ? value : String(value).replace(regex, function(match, capture) {
return entities[capture];
});
};
})(),
/**
* Convert certain characters (&, <, >, and ") from their HTML character equivalents.
* @param {String} value The string to decode.
* @return {String} The decoded text.
* @method
*/
htmlDecode: (function() {
var entities = {
'&amp;': '&',
'&gt;': '>',
'&lt;': '<',
'&quot;': '"'
}, keys = [], p, regex;
for (p in entities) {
keys.push(p);
}
regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
return function(value) {
return (!value) ? value : String(value).replace(regex, function(match, capture) {
if (capture in entities) {
return entities[capture];
} else {
return String.fromCharCode(parseInt(capture.substr(2), 10));
}
});
};
})(),
/**
* Appends content to the query string of a URL, handling logic for whether to place
* a question mark or ampersand.
* @param {String} url The URL to append to.
* @param {String} string The content to append to the URL.
* @return {String} The resulting URL.
*/
urlAppend : function(url, string) {
if (!Ext.isEmpty(string)) {
return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
}
return url;
},
/**
* Trims whitespace from either end of a string, leaving spaces within the string intact. Example:
*
* @example
* var s = ' foo bar ';
* alert('-' + s + '-'); // alerts "- foo bar -"
* alert('-' + Ext.String.trim(s) + '-'); // alerts "-foo bar-"
*
* @param {String} string The string to escape
* @return {String} The trimmed string
*/
trim: function(string) {
return string.replace(Ext.String.trimRegex, "");
},
/**
* Capitalize the given string.
* @param {String} string
* @return {String}
*/
capitalize: function(string) {
return string.charAt(0).toUpperCase() + string.substr(1);
},
/**
* Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length.
* @param {String} value The string to truncate.
* @param {Number} length The maximum length to allow before truncating.
* @param {Boolean} word `true` to try to find a common word break.
* @return {String} The converted text.
*/
ellipsis: function(value, len, word) {
if (value && value.length > len) {
if (word) {
var vs = value.substr(0, len - 2),
index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
if (index !== -1 && index >= (len - 15)) {
return vs.substr(0, index) + "...";
}
}
return value.substr(0, len - 3) + "...";
}
return value;
},
/**
* Escapes the passed string for use in a regular expression.
* @param {String} string
* @return {String}
*/
escapeRegex: function(string) {
return string.replace(Ext.String.escapeRegexRe, "\\$1");
},
/**
* Escapes the passed string for ' and \.
* @param {String} string The string to escape.
* @return {String} The escaped string.
*/
escape: function(string) {
return string.replace(Ext.String.escapeRe, "\\$1");
},
/**
* Utility function that allows you to easily switch a string between two alternating values. The passed value
* is compared to the current string, and if they are equal, the other value that was passed in is returned. If
* they are already different, the first value passed in is returned. Note that this method returns the new value
* but does not change the current string.
*
* // alternate sort directions
* sort = Ext.String.toggle(sort, 'ASC', 'DESC');
*
* // instead of conditional logic:
* sort = (sort == 'ASC' ? 'DESC' : 'ASC');
*
* @param {String} string The current string.
* @param {String} value The value to compare to the current string.
* @param {String} other The new value to use if the string already equals the first value passed in.
* @return {String} The new value.
*/
toggle: function(string, value, other) {
return string === value ? other : value;
},
/**
* Pads the left side of a string with a specified character. This is especially useful
* for normalizing number and date strings. Example usage:
*
* var s = Ext.String.leftPad('123', 5, '0');
* alert(s); // '00123'
*
* @param {String} string The original string.
* @param {Number} size The total length of the output string.
* @param {String} [character= ] (optional) The character with which to pad the original string (defaults to empty string " ").
* @return {String} The padded string.
*/
leftPad: function(string, size, character) {
var result = String(string);
character = character || " ";
while (result.length < size) {
result = character + result;
}
return result;
},
/**
* Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
* token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
*
* var cls = 'my-class',
* text = 'Some text';
* var s = Ext.String.format('<div class="{0}">{1}</div>', cls, text);
* alert(s); // '<div class="my-class">Some text</div>'
*
* @param {String} string The tokenized string to be formatted.
* @param {String} value1 The value to replace token {0}.
* @param {String} value2 Etc...
* @return {String} The formatted string.
*/
format: function(format) {
var args = Ext.Array.toArray(arguments, 1);
return format.replace(Ext.String.formatRe, function(m, i) {
return args[i];
});
},
/**
* Returns a string with a specified number of repetitions a given string pattern.
* The pattern be separated by a different string.
*
* var s = Ext.String.repeat('---', 4); // '------------'
* var t = Ext.String.repeat('--', 3, '/'); // '--/--/--'
*
* @param {String} pattern The pattern to repeat.
* @param {Number} count The number of times to repeat the pattern (may be 0).
* @param {String} sep An option string to separate each pattern.
*/
repeat: function(pattern, count, sep) {
for (var buf = [], i = count; i--; ) {
buf.push(pattern);
}
return buf.join(sep || '');
}
};
/**
* Old alias to {@link Ext.String#htmlEncode}.
* @deprecated Use {@link Ext.String#htmlEncode} instead.
* @method
* @member Ext
* @alias Ext.String#htmlEncode
*/
Ext.htmlEncode = Ext.String.htmlEncode;
/**
* Old alias to {@link Ext.String#htmlDecode}.
* @deprecated Use {@link Ext.String#htmlDecode} instead.
* @method
* @member Ext
* @alias Ext.String#htmlDecode
*/
Ext.htmlDecode = Ext.String.htmlDecode;
/**
* Old alias to {@link Ext.String#urlAppend}.
* @deprecated Use {@link Ext.String#urlAppend} instead.
* @method
* @member Ext
* @alias Ext.String#urlAppend
*/
Ext.urlAppend = Ext.String.urlAppend;

View File

@@ -0,0 +1,380 @@
//@tag foundation,core
//@define Ext.Version
//@require Ext
/**
* @author Jacky Nguyen <jacky@sencha.com>
* @docauthor Jacky Nguyen <jacky@sencha.com>
* @class Ext.Version
*
* A utility class that wrap around a string version number and provide convenient
* method to perform comparison. See also: {@link Ext.Version#compare compare}. Example:
*
* var version = new Ext.Version('1.0.2beta');
* console.log("Version is " + version); // Version is 1.0.2beta
*
* console.log(version.getMajor()); // 1
* console.log(version.getMinor()); // 0
* console.log(version.getPatch()); // 2
* console.log(version.getBuild()); // 0
* console.log(version.getRelease()); // beta
*
* console.log(version.isGreaterThan('1.0.1')); // true
* console.log(version.isGreaterThan('1.0.2alpha')); // true
* console.log(version.isGreaterThan('1.0.2RC')); // false
* console.log(version.isGreaterThan('1.0.2')); // false
* console.log(version.isLessThan('1.0.2')); // true
*
* console.log(version.match(1.0)); // true
* console.log(version.match('1.0.2')); // true
*/
(function() {
// Current core version
var version = '4.1.0', Version;
Ext.Version = Version = Ext.extend(Object, {
/**
* Creates new Version object.
* @param {String/Number} version The version number in the follow standard format: major[.minor[.patch[.build[release]]]]
* Examples: 1.0 or 1.2.3beta or 1.2.3.4RC
* @return {Ext.Version} this
*/
constructor: function(version) {
var toNumber = this.toNumber,
parts, releaseStartIndex;
if (version instanceof Version) {
return version;
}
this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
releaseStartIndex = this.version.search(/([^\d\.])/);
if (releaseStartIndex !== -1) {
this.release = this.version.substr(releaseStartIndex, version.length);
this.shortVersion = this.version.substr(0, releaseStartIndex);
}
this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');
parts = this.version.split('.');
this.major = toNumber(parts.shift());
this.minor = toNumber(parts.shift());
this.patch = toNumber(parts.shift());
this.build = toNumber(parts.shift());
return this;
},
/**
* @param value
* @return {Number}
*/
toNumber: function(value) {
value = parseInt(value || 0, 10);
if (isNaN(value)) {
value = 0;
}
return value;
},
/**
* Override the native `toString()` method.
* @private
* @return {String} version
*/
toString: function() {
return this.version;
},
/**
* Override the native `valueOf()` method.
* @private
* @return {String} version
*/
valueOf: function() {
return this.version;
},
/**
* Returns the major component value.
* @return {Number} major
*/
getMajor: function() {
return this.major || 0;
},
/**
* Returns the minor component value.
* @return {Number} minor
*/
getMinor: function() {
return this.minor || 0;
},
/**
* Returns the patch component value.
* @return {Number} patch
*/
getPatch: function() {
return this.patch || 0;
},
/**
* Returns the build component value.
* @return {Number} build
*/
getBuild: function() {
return this.build || 0;
},
/**
* Returns the release component value.
* @return {Number} release
*/
getRelease: function() {
return this.release || '';
},
/**
* Returns whether this version if greater than the supplied argument.
* @param {String/Number} target The version to compare with.
* @return {Boolean} `true` if this version if greater than the target, `false` otherwise.
*/
isGreaterThan: function(target) {
return Version.compare(this.version, target) === 1;
},
/**
* Returns whether this version if greater than or equal to the supplied argument.
* @param {String/Number} target The version to compare with.
* @return {Boolean} `true` if this version if greater than or equal to the target, `false` otherwise.
*/
isGreaterThanOrEqual: function(target) {
return Version.compare(this.version, target) >= 0;
},
/**
* Returns whether this version if smaller than the supplied argument.
* @param {String/Number} target The version to compare with.
* @return {Boolean} `true` if this version if smaller than the target, `false` otherwise.
*/
isLessThan: function(target) {
return Version.compare(this.version, target) === -1;
},
/**
* Returns whether this version if less than or equal to the supplied argument.
* @param {String/Number} target The version to compare with.
* @return {Boolean} `true` if this version if less than or equal to the target, `false` otherwise.
*/
isLessThanOrEqual: function(target) {
return Version.compare(this.version, target) <= 0;
},
/**
* Returns whether this version equals to the supplied argument.
* @param {String/Number} target The version to compare with.
* @return {Boolean} `true` if this version equals to the target, `false` otherwise.
*/
equals: function(target) {
return Version.compare(this.version, target) === 0;
},
/**
* Returns whether this version matches the supplied argument. Example:
*
* var version = new Ext.Version('1.0.2beta');
* console.log(version.match(1)); // true
* console.log(version.match(1.0)); // true
* console.log(version.match('1.0.2')); // true
* console.log(version.match('1.0.2RC')); // false
*
* @param {String/Number} target The version to compare with.
* @return {Boolean} `true` if this version matches the target, `false` otherwise.
*/
match: function(target) {
target = String(target);
return this.version.substr(0, target.length) === target;
},
/**
* Returns this format: [major, minor, patch, build, release]. Useful for comparison.
* @return {Number[]}
*/
toArray: function() {
return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
},
/**
* Returns shortVersion version without dots and release.
* @return {String}
*/
getShortVersion: function() {
return this.shortVersion;
},
/**
* Convenient alias to {@link Ext.Version#isGreaterThan isGreaterThan}
* @param {String/Number} target
* @return {Boolean}
*/
gt: function() {
return this.isGreaterThan.apply(this, arguments);
},
/**
* Convenient alias to {@link Ext.Version#isLessThan isLessThan}
* @param {String/Number} target
* @return {Boolean}
*/
lt: function() {
return this.isLessThan.apply(this, arguments);
},
/**
* Convenient alias to {@link Ext.Version#isGreaterThanOrEqual isGreaterThanOrEqual}
* @param {String/Number} target
* @return {Boolean}
*/
gtEq: function() {
return this.isGreaterThanOrEqual.apply(this, arguments);
},
/**
* Convenient alias to {@link Ext.Version#isLessThanOrEqual isLessThanOrEqual}
* @param {String/Number} target
* @return {Boolean}
*/
ltEq: function() {
return this.isLessThanOrEqual.apply(this, arguments);
}
});
Ext.apply(Version, {
// @private
releaseValueMap: {
'dev': -6,
'alpha': -5,
'a': -5,
'beta': -4,
'b': -4,
'rc': -3,
'#': -2,
'p': -1,
'pl': -1
},
/**
* Converts a version component to a comparable value.
*
* @static
* @param {Object} value The value to convert
* @return {Object}
*/
getComponentValue: function(value) {
return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
},
/**
* Compare 2 specified versions, starting from left to right. If a part contains special version strings,
* they are handled in the following order:
* 'dev' < 'alpha' = 'a' < 'beta' = 'b' < 'RC' = 'rc' < '#' < 'pl' = 'p' < 'anything else'
*
* @static
* @param {String} current The current version to compare to.
* @param {String} target The target version to compare to.
* @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent.
*/
compare: function(current, target) {
var currentValue, targetValue, i;
current = new Version(current).toArray();
target = new Version(target).toArray();
for (i = 0; i < Math.max(current.length, target.length); i++) {
currentValue = this.getComponentValue(current[i]);
targetValue = this.getComponentValue(target[i]);
if (currentValue < targetValue) {
return -1;
} else if (currentValue > targetValue) {
return 1;
}
}
return 0;
}
});
Ext.apply(Ext, {
/**
* @private
*/
versions: {},
/**
* @private
*/
lastRegisteredVersion: null,
/**
* Set version number for the given package name.
*
* @param {String} packageName The package name, for example: 'core', 'touch', 'extjs'.
* @param {String/Ext.Version} version The version, for example: '1.2.3alpha', '2.4.0-dev'.
* @return {Ext}
*/
setVersion: function(packageName, version) {
Ext.versions[packageName] = new Version(version);
Ext.lastRegisteredVersion = Ext.versions[packageName];
return this;
},
/**
* Get the version number of the supplied package name; will return the last registered version
* (last `Ext.setVersion()` call) if there's no package name given.
*
* @param {String} packageName (Optional) The package name, for example: 'core', 'touch', 'extjs'.
* @return {Ext.Version} The version.
*/
getVersion: function(packageName) {
if (packageName === undefined) {
return Ext.lastRegisteredVersion;
}
return Ext.versions[packageName];
},
/**
* Create a closure for deprecated code.
*
* // This means Ext.oldMethod is only supported in 4.0.0beta and older.
* // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
* // the closure will not be invoked
* Ext.deprecate('extjs', '4.0.0beta', function() {
* Ext.oldMethod = Ext.newMethod;
* // ...
* });
*
* @param {String} packageName The package name.
* @param {String} since The last version before it's deprecated.
* @param {Function} closure The callback function to be executed with the specified version is less than the current version.
* @param {Object} scope The execution scope (`this`) if the closure
*/
deprecate: function(packageName, since, closure, scope) {
if (Version.compare(Ext.getVersion(packageName), since) < 1) {
closure.call(scope);
}
}
}); // End Versioning
Ext.setVersion('core', version);
})();