/*!
* Ext JS Library 3.0.3
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext
*/
Ext.ns("Ext.grid", "Ext.dd", "Ext.tree", "Ext.form", "Ext.menu",
"Ext.state", "Ext.layout", "Ext.app", "Ext.ux", "Ext.chart", "Ext.direct");
/**
* Namespace alloted for extensions to the framework.
* @property ux
* @type Object
*/
Ext.apply(Ext, function(){
var E = Ext,
idSeed = 0,
scrollWidth = null;
return {
/**
* A reusable empty function
* @property
* @type Function
*/
emptyFn : function(){},
/**
* URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images.
* In older versions of IE, this defaults to "http://extjs.com/s.gif" and you should change this to a URL on your server.
* For other browsers it uses an inline data URL.
* @type String
*/
BLANK_IMAGE_URL : Ext.isIE6 || Ext.isIE7 || Ext.isAir ?
'http:/' + '/extjs.com/s.gif' :
'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
extendX : function(supr, fn){
return Ext.extend(supr, fn(supr.prototype));
},
/**
* Returns the current HTML document object as an {@link Ext.Element}.
* @return Ext.Element The document
*/
getDoc : function(){
return Ext.get(document);
},
/**
* Utility method for validating that a value is numeric, returning the specified default value if it is not.
* @param {Mixed} value Should be a number, but any type will be handled appropriately
* @param {Number} defaultValue The value to return if the original value is non-numeric
* @return {Number} Value, if numeric, else defaultValue
*/
num : function(v, defaultValue){
v = Number(Ext.isEmpty(v) || Ext.isBoolean(v) ? NaN : v);
return isNaN(v)? defaultValue : v;
},
/**
* Utility method for returning a default value if the passed value is empty.
* The value is deemed to be empty if it is
* - null
* - undefined
* - an empty array
* - a zero length string (Unless the allowBlank parameter is true)
*
* @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
*/
value : function(v, defaultValue, allowBlank){
return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
},
/**
* Escapes the passed string for use in a regular expression
* @param {String} str
* @return {String}
*/
escapeRe : function(s) {
return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
},
sequence : function(o, name, fn, scope){
o[name] = o[name].createSequence(fn, scope);
},
/**
* Applies event listeners to elements by selectors when the document is ready.
* The event name is specified with an @ suffix.
*
Ext.addBehaviors({
// add a listener for click on all anchors in element with id foo
'#foo a@click' : function(e, t){
// do something
},
// add the same listener to multiple selectors (separated by comma BEFORE the @)
'#foo a, #bar span.some-class@mouseover' : function(){
// do something
}
});
*
* @param {Object} obj The list of behaviors to apply
*/
addBehaviors : function(o){
if(!Ext.isReady){
Ext.onReady(function(){
Ext.addBehaviors(o);
});
} else {
var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
parts,
b,
s;
for (b in o) {
if ((parts = b.split('@'))[1]) { // for Object prototype breakers
s = parts[0];
if(!cache[s]){
cache[s] = Ext.select(s);
}
cache[s].on(parts[1], o[b]);
}
}
cache = null;
}
},
/**
* Utility method for getting the width of the browser scrollbar. This can differ depending on
* operating system settings, such as the theme or font size.
* @param {Boolean} force (optional) true to force a recalculation of the value.
* @return {Number} The width of the scrollbar.
*/
getScrollBarWidth: function(force){
if(!Ext.isReady){
return 0;
}
if(force === true || scrollWidth === null){
// Append our div, do our calculation and then remove it
var div = Ext.getBody().createChild(''),
child = div.child('div', true);
var w1 = child.offsetWidth;
div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
var w2 = child.offsetWidth;
div.remove();
// Need to add 2 to ensure we leave enough space
scrollWidth = w1 - w2 + 2;
}
return scrollWidth;
},
// deprecated
combine : function(){
var as = arguments, l = as.length, r = [];
for(var i = 0; i < l; i++){
var a = as[i];
if(Ext.isArray(a)){
r = r.concat(a);
}else if(a.length !== undefined && !a.substr){
r = r.concat(Array.prototype.slice.call(a, 0));
}else{
r.push(a);
}
}
return r;
},
/**
* Copies a set of named properties fom the source object to the destination object.
* example:
ImageComponent = Ext.extend(Ext.BoxComponent, {
initComponent: function() {
this.autoEl = { tag: 'img' };
MyComponent.superclass.initComponent.apply(this, arguments);
this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
}
});
*
* @param {Object} The destination object.
* @param {Object} The source object.
* @param {Array/String} Either an Array of property names, or a comma-delimited list
* of property names to copy.
* @return {Object} The modified object.
*/
copyTo : function(dest, source, names){
if(Ext.isString(names)){
names = names.split(/[,;\s]/);
}
Ext.each(names, function(name){
if(source.hasOwnProperty(name)){
dest[name] = source[name];
}
}, this);
return dest;
},
/**
* Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
* DOM (if applicable) and calling their destroy functions (if available). This method is primarily
* intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
* {@link Ext.util.Observable} can be passed in. Any number of elements and/or components can be
* passed into this function in a single call as separate arguments.
* @param {Mixed} arg1 An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
* @param {Mixed} arg2 (optional)
* @param {Mixed} etc... (optional)
*/
destroy : function(){
Ext.each(arguments, function(arg){
if(arg){
if(Ext.isArray(arg)){
this.destroy.apply(this, arg);
}else if(Ext.isFunction(arg.destroy)){
arg.destroy();
}else if(arg.dom){
arg.remove();
}
}
}, this);
},
/**
* Attempts to destroy and then remove a set of named properties of the passed object.
* @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
* @param {Mixed} arg1 The name of the property to destroy and remove from the object.
* @param {Mixed} etc... More property names to destroy and remove.
*/
destroyMembers : function(o, arg1, arg2, etc){
for(var i = 1, a = arguments, len = a.length; i < len; i++) {
Ext.destroy(o[a[i]]);
delete o[a[i]];
}
},
/**
* Creates a copy of the passed Array with falsy values removed.
* @param {Array/NodeList} arr The Array from which to remove falsy values.
* @return {Array} The new, compressed Array.
*/
clean : function(arr){
var ret = [];
Ext.each(arr, function(v){
if(!!v){
ret.push(v);
}
});
return ret;
},
/**
* Creates a copy of the passed Array, filtered to contain only unique values.
* @param {Array} arr The Array to filter
* @return {Array} The new Array containing unique values.
*/
unique : function(arr){
var ret = [],
collect = {};
Ext.each(arr, function(v) {
if(!collect[v]){
ret.push(v);
}
collect[v] = true;
});
return ret;
},
/**
* Recursively flattens into 1-d Array. Injects Arrays inline.
* @param {Array} arr The array to flatten
* @return {Array} The new, flattened array.
*/
flatten : function(arr){
var worker = [];
function rFlatten(a) {
Ext.each(a, function(v) {
if(Ext.isArray(v)){
rFlatten(v);
}else{
worker.push(v);
}
});
return worker;
}
return rFlatten(arr);
},
/**
* Returns the minimum value in the Array.
* @param {Array|NodeList} arr The Array from which to select the minimum value.
* @param {Function} comp (optional) a function to perform the comparision which determines minimization.
* If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
* @return {Object} The minimum value in the Array.
*/
min : function(arr, comp){
var ret = arr[0];
comp = comp || function(a,b){ return a < b ? -1 : 1; };
Ext.each(arr, function(v) {
ret = comp(ret, v) == -1 ? ret : v;
});
return ret;
},
/**
* Returns the maximum value in the Array
* @param {Array|NodeList} arr The Array from which to select the maximum value.
* @param {Function} comp (optional) a function to perform the comparision which determines maximization.
* If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
* @return {Object} The maximum value in the Array.
*/
max : function(arr, comp){
var ret = arr[0];
comp = comp || function(a,b){ return a > b ? 1 : -1; };
Ext.each(arr, function(v) {
ret = comp(ret, v) == 1 ? ret : v;
});
return ret;
},
/**
* Calculates the mean of the Array
* @param {Array} arr The Array to calculate the mean value of.
* @return {Number} The mean.
*/
mean : function(arr){
return Ext.sum(arr) / arr.length;
},
/**
* Calculates the sum of the Array
* @param {Array} arr The Array to calculate the sum value of.
* @return {Number} The sum.
*/
sum : function(arr){
var ret = 0;
Ext.each(arr, function(v) {
ret += v;
});
return ret;
},
/**
* Partitions the set into two sets: a true set and a false set.
* Example:
* Example2:
*
// Example 1:
Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
// Example 2:
Ext.partition(
Ext.query("p"),
function(val){
return val.className == "class1"
}
);
// true are those paragraph elements with a className of "class1",
// false set are those that do not have that className.
*
* @param {Array|NodeList} arr The array to partition
* @param {Function} truth (optional) a function to determine truth. If this is omitted the element
* itself must be able to be evaluated for its truthfulness.
* @return {Array} [true,false]
*/
partition : function(arr, truth){
var ret = [[],[]];
Ext.each(arr, function(v, i, a) {
ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
});
return ret;
},
/**
* Invokes a method on each item in an Array.
*
// Example:
Ext.invoke(Ext.query("p"), "getAttribute", "id");
// [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
*
* @param {Array|NodeList} arr The Array of items to invoke the method on.
* @param {String} methodName The method name to invoke.
* @param {Anything} ... Arguments to send into the method invocation.
* @return {Array} The results of invoking the method on each item in the array.
*/
invoke : function(arr, methodName){
var ret = [],
args = Array.prototype.slice.call(arguments, 2);
Ext.each(arr, function(v,i) {
if (v && Ext.isFunction(v[methodName])) {
ret.push(v[methodName].apply(v, args));
} else {
ret.push(undefined);
}
});
return ret;
},
/**
* Plucks the value of a property from each item in the Array
*
// Example:
Ext.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
*
* @param {Array|NodeList} arr The Array of items to pluck the value from.
* @param {String} prop The property name to pluck from each element.
* @return {Array} The value from each item in the Array.
*/
pluck : function(arr, prop){
var ret = [];
Ext.each(arr, function(v) {
ret.push( v[prop] );
});
return ret;
},
/**
* Zips N sets together.
*
// Example 1:
Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
// Example 2:
Ext.zip(
[ "+", "-", "+"],
[ 12, 10, 22],
[ 43, 15, 96],
function(a, b, c){
return "$" + a + "" + b + "." + c
}
); // ["$+12.43", "$-10.15", "$+22.96"]
*
* @param {Arrays|NodeLists} arr This argument may be repeated. Array(s) to contribute values.
* @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
* @return {Array} The zipped set.
*/
zip : function(){
var parts = Ext.partition(arguments, function( val ){ return !Ext.isFunction(val); }),
arrs = parts[0],
fn = parts[1][0],
len = Ext.max(Ext.pluck(arrs, "length")),
ret = [];
for (var i = 0; i < len; i++) {
ret[i] = [];
if(fn){
ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
}else{
for (var j = 0, aLen = arrs.length; j < aLen; j++){
ret[i].push( arrs[j][i] );
}
}
}
return ret;
},
/**
* This is shorthand reference to {@link Ext.ComponentMgr#get}.
* Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
* @param {String} id The component {@link Ext.Component#id id}
* @return Ext.Component The Component, undefined if not found, or null if a
* Class was found.
*/
getCmp : function(id){
return Ext.ComponentMgr.get(id);
},
/**
* By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
* you may want to set this to true.
* @type Boolean
*/
useShims: E.isIE6 || (E.isMac && E.isGecko2),
// inpired by a similar function in mootools library
/**
* Returns the type of object that is passed in. If the object passed in is null or undefined it
* return false otherwise it returns one of the following values:
* - string: If the object passed is a string
* - number: If the object passed is a number
* - boolean: If the object passed is a boolean value
* - date: If the object passed is a Date object
* - function: If the object passed is a function reference
* - object: If the object passed is an object
* - array: If the object passed is an array
* - regexp: If the object passed is a regular expression
* - element: If the object passed is a DOM Element
* - nodelist: If the object passed is a DOM NodeList
* - textnode: If the object passed is a DOM text node and contains something other than whitespace
* - whitespace: If the object passed is a DOM text node and contains only whitespace
*
* @param {Mixed} object
* @return {String}
*/
type : function(o){
if(o === undefined || o === null){
return false;
}
if(o.htmlElement){
return 'element';
}
var t = typeof o;
if(t == 'object' && o.nodeName) {
switch(o.nodeType) {
case 1: return 'element';
case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
}
}
if(t == 'object' || t == 'function') {
switch(o.constructor) {
case Array: return 'array';
case RegExp: return 'regexp';
case Date: return 'date';
}
if(Ext.isNumber(o.length) && Ext.isFunction(o.item)) {
return 'nodelist';
}
}
return t;
},
intercept : function(o, name, fn, scope){
o[name] = o[name].createInterceptor(fn, scope);
},
// internal
callback : function(cb, scope, args, delay){
if(Ext.isFunction(cb)){
if(delay){
cb.defer(delay, scope, args || []);
}else{
cb.apply(scope, args || []);
}
}
}
};
}());
/**
* @class Function
* These functions are available on every Function object (any JavaScript function).
*/
Ext.apply(Function.prototype, {
/**
* 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 fcn 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 = sayHi.createSequence(function(name){
alert('Bye, ' + name);
});
sayGoodbye('Fred'); // both alerts show
* @param {Function} fcn 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(fcn, scope){
var method = this;
return !Ext.isFunction(fcn) ?
this :
function(){
var retval = method.apply(this || window, arguments);
fcn.apply(scope || this || window, arguments);
return retval;
};
}
});
/**
* @class String
* These functions are available as static methods on the JavaScript String object.
*/
Ext.applyIf(String, {
/**
* Escapes the passed string for ' and \
* @param {String} string The string to escape
* @return {String} The escaped string
* @static
*/
escape : function(string) {
return string.replace(/('|\\)/g, "\\$1");
},
/**
* 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 = String.leftPad('123', 5, '0');
// s now contains the string: '00123'
*
* @param {String} string The original string
* @param {Number} size The total length of the output string
* @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
* @return {String} The padded string
* @static
*/
leftPad : function (val, size, ch) {
var result = String(val);
if(!ch) {
ch = " ";
}
while (result.length < size) {
result = ch + result;
}
return result;
}
});
/**
* 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 = sort.toggle('ASC', 'DESC');
// instead of conditional logic:
sort = (sort == 'ASC' ? 'DESC' : 'ASC');
* @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
*/
String.prototype.toggle = function(value, other){
return this == value ? other : value;
};
/**
* Trims whitespace from either end of a string, leaving spaces within the string intact. Example:
*
var s = ' foo bar ';
alert('-' + s + '-'); //alerts "- foo bar -"
alert('-' + s.trim() + '-'); //alerts "-foo bar-"
* @return {String} The trimmed string
*/
String.prototype.trim = function(){
var re = /^\s+|\s+$/g;
return function(){ return this.replace(re, ""); };
}();
// here to prevent dependency on Date.js
/**
Returns the number of milliseconds between this date and date
@param {Date} date (optional) Defaults to now
@return {Number} The diff in milliseconds
@member Date getElapsed
*/
Date.prototype.getElapsed = function(date) {
return Math.abs((date || new Date()).getTime()-this.getTime());
};
/**
* @class Number
*/
Ext.applyIf(Number.prototype, {
/**
* Checks whether or not the current 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} 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(min, max){
return Math.min(Math.max(this, min), max);
}
});