/*! * Ext JS Library 3.4.0 * Copyright(c) 2006-2011 Sencha Inc. * licensing@sencha.com * http://www.sencha.com/license */ /** * @class Ext */ Ext.ns("Ext.grid", "Ext.list", "Ext.dd", "Ext.tree", "Ext.form", "Ext.menu", "Ext.state", "Ext.layout.boxOverflow", "Ext.app", "Ext.ux", "Ext.chart", "Ext.direct", "Ext.slider"); /** * 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:/' + '/www.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.isArray(v) || typeof v == 'boolean' || (typeof v == 'string' && v.trim().length == 0) ? 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
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} dest The destination object.
* @param {Object} source The source object.
* @param {Array/String} names 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(typeof names == 'string'){
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(typeof arg.destroy == 'function'){
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 arr.length > 0 ? Ext.sum(arr) / arr.length : undefined;
},
/**
* 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
// 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 {...*} args 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 && typeof v[methodName] == 'function') {
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 typeof val != 'function'; }),
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:
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 (typeof fcn != 'function') ?
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);
}
});
Ext.lib.Dom.getRegion = function(el) {
return Ext.lib.Region.getRegion(el);
}; Ext.lib.Region = function(t, r, b, l) {
var me = this;
me.top = t;
me[1] = t;
me.right = r;
me.bottom = b;
me.left = l;
me[0] = l;
};
Ext.lib.Region.prototype = {
contains : function(region) {
var me = this;
return ( region.left >= me.left &&
region.right <= me.right &&
region.top >= me.top &&
region.bottom <= me.bottom );
},
getArea : function() {
var me = this;
return ( (me.bottom - me.top) * (me.right - me.left) );
},
intersect : function(region) {
var me = this,
t = Math.max(me.top, region.top),
r = Math.min(me.right, region.right),
b = Math.min(me.bottom, region.bottom),
l = Math.max(me.left, region.left);
if (b >= t && r >= l) {
return new Ext.lib.Region(t, r, b, l);
}
},
union : function(region) {
var me = this,
t = Math.min(me.top, region.top),
r = Math.max(me.right, region.right),
b = Math.max(me.bottom, region.bottom),
l = Math.min(me.left, region.left);
return new Ext.lib.Region(t, r, b, l);
},
constrainTo : function(r) {
var me = this;
me.top = me.top.constrain(r.top, r.bottom);
me.bottom = me.bottom.constrain(r.top, r.bottom);
me.left = me.left.constrain(r.left, r.right);
me.right = me.right.constrain(r.left, r.right);
return me;
},
adjust : function(t, l, b, r) {
var me = this;
me.top += t;
me.left += l;
me.right += r;
me.bottom += b;
return me;
}
};
Ext.lib.Region.getRegion = function(el) {
var p = Ext.lib.Dom.getXY(el),
t = p[1],
r = p[0] + el.offsetWidth,
b = p[1] + el.offsetHeight,
l = p[0];
return new Ext.lib.Region(t, r, b, l);
}; Ext.lib.Point = function(x, y) {
if (Ext.isArray(x)) {
y = x[1];
x = x[0];
}
var me = this;
me.x = me.right = me.left = me[0] = x;
me.y = me.top = me.bottom = me[1] = y;
};
Ext.lib.Point.prototype = new Ext.lib.Region();
/**
* @class Ext.DomHelper
*/
Ext.apply(Ext.DomHelper,
function(){
var pub,
afterbegin = 'afterbegin',
afterend = 'afterend',
beforebegin = 'beforebegin',
beforeend = 'beforeend',
confRe = /tag|children|cn|html$/i;
// private
function doInsert(el, o, returnElement, pos, sibling, append){
el = Ext.getDom(el);
var newNode;
if (pub.useDom) {
newNode = createDom(o, null);
if (append) {
el.appendChild(newNode);
} else {
(sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
}
} else {
newNode = Ext.DomHelper.insertHtml(pos, el, Ext.DomHelper.createHtml(o));
}
return returnElement ? Ext.get(newNode, true) : newNode;
}
// build as dom
/** @ignore */
function createDom(o, parentNode){
var el,
doc = document,
useSet,
attr,
val,
cn;
if (Ext.isArray(o)) { // Allow Arrays of siblings to be inserted
el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
for (var i = 0, l = o.length; i < l; i++) {
createDom(o[i], el);
}
} else if (typeof o == 'string') { // Allow a string as a child spec.
el = doc.createTextNode(o);
} else {
el = doc.createElement( o.tag || 'div' );
useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
for (var attr in o) {
if(!confRe.test(attr)){
val = o[attr];
if(attr == 'cls'){
el.className = val;
}else{
if(useSet){
el.setAttribute(attr, val);
}else{
el[attr] = val;
}
}
}
}
Ext.DomHelper.applyStyles(el, o.style);
if ((cn = o.children || o.cn)) {
createDom(cn, el);
} else if (o.html) {
el.innerHTML = o.html;
}
}
if(parentNode){
parentNode.appendChild(el);
}
return el;
}
pub = {
/**
* Creates a new Ext.Template from the DOM object spec.
* @param {Object} o The DOM object spec (and children)
* @return {Ext.Template} The new template
*/
createTemplate : function(o){
var html = Ext.DomHelper.createHtml(o);
return new Ext.Template(html);
},
/** True to force the use of DOM instead of html fragments @type Boolean */
useDom : false,
/**
* Creates new DOM element(s) and inserts them before el.
* @param {Mixed} el The context element
* @param {Object/String} o The DOM object spec (and children) or raw HTML blob
* @param {Boolean} returnElement (optional) true to return a Ext.Element
* @return {HTMLElement/Ext.Element} The new node
* @hide (repeat)
*/
insertBefore : function(el, o, returnElement){
return doInsert(el, o, returnElement, beforebegin);
},
/**
* Creates new DOM element(s) and inserts them after el.
* @param {Mixed} el The context element
* @param {Object} o The DOM object spec (and children)
* @param {Boolean} returnElement (optional) true to return a Ext.Element
* @return {HTMLElement/Ext.Element} The new node
* @hide (repeat)
*/
insertAfter : function(el, o, returnElement){
return doInsert(el, o, returnElement, afterend, 'nextSibling');
},
/**
* Creates new DOM element(s) and inserts them as the first child of el.
* @param {Mixed} el The context element
* @param {Object/String} o The DOM object spec (and children) or raw HTML blob
* @param {Boolean} returnElement (optional) true to return a Ext.Element
* @return {HTMLElement/Ext.Element} The new node
* @hide (repeat)
*/
insertFirst : function(el, o, returnElement){
return doInsert(el, o, returnElement, afterbegin, 'firstChild');
},
/**
* Creates new DOM element(s) and appends them to el.
* @param {Mixed} el The context element
* @param {Object/String} o The DOM object spec (and children) or raw HTML blob
* @param {Boolean} returnElement (optional) true to return a Ext.Element
* @return {HTMLElement/Ext.Element} The new node
* @hide (repeat)
*/
append: function(el, o, returnElement){
return doInsert(el, o, returnElement, beforeend, '', true);
},
/**
* Creates new DOM element(s) without inserting them to the document.
* @param {Object/String} o The DOM object spec (and children) or raw HTML blob
* @return {HTMLElement} The new uninserted node
*/
createDom: createDom
};
return pub;
}());
/**
* @class Ext.Template
*/
Ext.apply(Ext.Template.prototype, {
/**
* @cfg {Boolean} disableFormats Specify true to disable format
* functions in the template. If the template does not contain
* {@link Ext.util.Format format functions}, setting disableFormats
* to true will reduce {@link #apply}
time. Defaults to false.
*
var t = new Ext.Template(
'<div name="{id}">',
'<span class="{cls}">{name} {value}</span>',
'</div>',
{
compiled: true, // {@link #compile} immediately
disableFormats: true // reduce {@link #apply}
time since no formatting
}
);
*
* For a list of available format functions, see {@link Ext.util.Format}.
*/
disableFormats : false,
/**
* See {@link #disableFormats}
.
* @type Boolean
* @property disableFormats
*/
/**
* The regular expression used to match template variables
* @type RegExp
* @property
* @hide repeat doc
*/
re : /\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
argsRe : /^\s*['"](.*)["']\s*$/,
compileARe : /\\/g,
compileBRe : /(\r\n|\n)/g,
compileCRe : /'/g,
/**
* Returns an HTML fragment of this template with the specified values applied.
* @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
* @return {String} The HTML fragment
* @hide repeat doc
*/
applyTemplate : function(values){
var me = this,
useF = me.disableFormats !== true,
fm = Ext.util.Format,
tpl = me;
if(me.compiled){
return me.compiled(values);
}
function fn(m, name, format, args){
if (format && useF) {
if (format.substr(0, 5) == "this.") {
return tpl.call(format.substr(5), values[name], values);
} else {
if (args) {
// quoted values are required for strings in compiled templates,
// but for non compiled we need to strip them
// quoted reversed for jsmin
var re = me.argsRe;
args = args.split(',');
for(var i = 0, len = args.length; i < len; i++){
args[i] = args[i].replace(re, "$1");
}
args = [values[name]].concat(args);
} else {
args = [values[name]];
}
return fm[format].apply(fm, args);
}
} else {
return values[name] !== undefined ? values[name] : "";
}
}
return me.html.replace(me.re, fn);
},
/**
* Compiles the template into an internal function, eliminating the RegEx overhead.
* @return {Ext.Template} this
* @hide repeat doc
*/
compile : function(){
var me = this,
fm = Ext.util.Format,
useF = me.disableFormats !== true,
sep = Ext.isGecko ? "+" : ",",
body;
function fn(m, name, format, args){
if(format && useF){
args = args ? ',' + args : "";
if(format.substr(0, 5) != "this."){
format = "fm." + format + '(';
}else{
format = 'this.call("'+ format.substr(5) + '", ';
args = ", values";
}
}else{
args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
}
return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
}
// branched to use + in gecko and [].join() in others
if(Ext.isGecko){
body = "this.compiled = function(values){ return '" +
me.html.replace(me.compileARe, '\\\\').replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn) +
"';};";
}else{
body = ["this.compiled = function(values){ return ['"];
body.push(me.html.replace(me.compileARe, '\\\\').replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn));
body.push("'].join('');};");
body = body.join('');
}
eval(body);
return me;
},
// private function used to call members
call : function(fnName, value, allValues){
return this[fnName](value, allValues);
}
});
Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
/**
* @class Ext.util.Functions
* @singleton
*/
Ext.util.Functions = {
/**
* 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.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.
* @return {Function} The new function
*/
createInterceptor: function(origFn, newFn, scope) {
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) :
null;
};
}
},
/**
* Creates a delegate (callback) that sets the scope to obj.
* Call directly on any function. Example: Ext.createDelegate(this.myFunction, this, [arg1, arg2])
* Will create a function that is automatically scoped to obj so that the this variable inside the
* callback points to obj. Example usage:
*
var sayHi = function(name){
// Note this use of "this.text" here. This function expects to
// execute within a scope that contains a text property. In this
// example, the "this" variable is pointing to the btn object that
// was passed in createDelegate below.
alert('Hi, ' + name + '. You clicked the "' + this.text + '" button.');
}
var btn = new Ext.Button({
text: 'Say Hi',
renderTo: Ext.getBody()
});
// This callback will execute in the scope of the
// button instance. Clicking the button alerts
// "Hi, Fred. You clicked the "Say Hi" button."
btn.on('click', Ext.createDelegate(sayHi, btn, ['Fred']));
* @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
*/
createDelegate: function(fn, obj, args, appendArgs) {
if (!Ext.isFunction(fn)) {
return fn;
}
return function() {
var callArgs = args || arguments;
if (appendArgs === true) {
callArgs = Array.prototype.slice.call(arguments, 0);
callArgs = callArgs.concat(args);
}
else if (Ext.isNumber(appendArgs)) {
callArgs = Array.prototype.slice.call(arguments, 0);
// copy arguments first
var applyArgs = [appendArgs, 0].concat(args);
// create method call params
Array.prototype.splice.apply(callArgs, applyArgs);
// splice them in
}
return fn.apply(obj || window, callArgs);
};
},
/**
* Calls this function after the number of millseconds specified, optionally in a specific scope. Example usage:
*
var sayHi = function(name){
alert('Hi, ' + name);
}
// executes immediately:
sayHi('Fred');
// executes after 2 seconds:
Ext.defer(sayHi, 2000, this, ['Fred']);
// this syntax is sometimes useful for deferring
// execution of an anonymous function:
Ext.defer(function(){
alert('Anonymous');
}, 100);
* @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, obj, args, appendArgs) {
fn = Ext.util.Functions.createDelegate(fn, obj, 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 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 = Ext.createSequence(sayHi, function(name){
alert('Bye, ' + name);
});
sayGoodbye('Fred'); // both alerts show
* @param {Function} origFn 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(origFn, newFn, scope) {
if (!Ext.isFunction(newFn)) {
return origFn;
}
else {
return function() {
var retval = origFn.apply(this || window, arguments);
newFn.apply(scope || this || window, arguments);
return retval;
};
}
}
};
/**
* Shorthand for {@link Ext.util.Functions#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
* @member Ext
* @method defer
*/
Ext.defer = Ext.util.Functions.defer;
/**
* Shorthand for {@link Ext.util.Functions#createInterceptor}
* @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.
* @return {Function} The new function
* @member Ext
* @method defer
*/
Ext.createInterceptor = Ext.util.Functions.createInterceptor;
/**
* Shorthand for {@link Ext.util.Functions#createSequence}
* @param {Function} origFn 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
* @member Ext
* @method defer
*/
Ext.createSequence = Ext.util.Functions.createSequence;
/**
* Shorthand for {@link Ext.util.Functions#createDelegate}
* @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
* @member Ext
* @method defer
*/
Ext.createDelegate = Ext.util.Functions.createDelegate;
/**
* @class Ext.util.Observable
*/
Ext.apply(Ext.util.Observable.prototype, function(){
// this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
// allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
// private
function getMethodEvent(method){
var e = (this.methodEvents = this.methodEvents ||
{})[method], returnValue, v, cancel, obj = this;
if (!e) {
this.methodEvents[method] = e = {};
e.originalFn = this[method];
e.methodName = method;
e.before = [];
e.after = [];
var makeCall = function(fn, scope, args){
if((v = fn.apply(scope || obj, args)) !== undefined){
if (typeof v == 'object') {
if(v.returnValue !== undefined){
returnValue = v.returnValue;
}else{
returnValue = v;
}
cancel = !!v.cancel;
}
else
if (v === false) {
cancel = true;
}
else {
returnValue = v;
}
}
};
this[method] = function(){
var args = Array.prototype.slice.call(arguments, 0),
b;
returnValue = v = undefined;
cancel = false;
for(var i = 0, len = e.before.length; i < len; i++){
b = e.before[i];
makeCall(b.fn, b.scope, args);
if (cancel) {
return returnValue;
}
}
if((v = e.originalFn.apply(obj, args)) !== undefined){
returnValue = v;
}
for(var i = 0, len = e.after.length; i < len; i++){
b = e.after[i];
makeCall(b.fn, b.scope, args);
if (cancel) {
return returnValue;
}
}
return returnValue;
};
}
return e;
}
return {
// these are considered experimental
// allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
// adds an 'interceptor' called before the original method
beforeMethod : function(method, fn, scope){
getMethodEvent.call(this, method).before.push({
fn: fn,
scope: scope
});
},
// adds a 'sequence' called after the original method
afterMethod : function(method, fn, scope){
getMethodEvent.call(this, method).after.push({
fn: fn,
scope: scope
});
},
removeMethodListener: function(method, fn, scope){
var e = this.getMethodEvent(method);
for(var i = 0, len = e.before.length; i < len; i++){
if(e.before[i].fn == fn && e.before[i].scope == scope){
e.before.splice(i, 1);
return;
}
}
for(var i = 0, len = e.after.length; i < len; i++){
if(e.after[i].fn == fn && e.after[i].scope == scope){
e.after.splice(i, 1);
return;
}
}
},
/**
* Relays selected events from the specified Observable as if the events were fired by this.
* @param {Object} o The Observable whose events this object is to relay.
* @param {Array} events Array of event names to relay.
*/
relayEvents : function(o, events){
var me = this;
function createHandler(ename){
return function(){
return me.fireEvent.apply(me, [ename].concat(Array.prototype.slice.call(arguments, 0)));
};
}
for(var i = 0, len = events.length; i < len; i++){
var ename = events[i];
me.events[ename] = me.events[ename] || true;
o.on(ename, createHandler(ename), me);
}
},
/**
* Enables events fired by this Observable to bubble up an owner hierarchy by calling
* this.getBubbleTarget()
if present. There is no implementation in the Observable base class.
This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component.getBubbleTarget}. The default * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to * access the required target more quickly.
*Example:
Ext.override(Ext.form.Field, {
// Add functionality to Field's initComponent to enable the change event to bubble
initComponent : Ext.form.Field.prototype.initComponent.createSequence(function() {
this.enableBubble('change');
}),
// We know that we want Field's events to bubble directly to the FormPanel.
getBubbleTarget : function() {
if (!this.formPanel) {
this.formPanel = this.findParentByType('form');
}
return this.formPanel;
}
});
var myForm = new Ext.formPanel({
title: 'User Details',
items: [{
...
}],
listeners: {
change: function() {
// Title goes red if form has been modified.
myForm.header.setStyle('color', 'red');
}
}
});
* @param {String/Array} events The event name to bubble, or an Array of event names.
*/
enableBubble : function(events){
var me = this;
if(!Ext.isEmpty(events)){
events = Ext.isArray(events) ? events : Array.prototype.slice.call(arguments, 0);
for(var i = 0, len = events.length; i < len; i++){
var ename = events[i];
ename = ename.toLowerCase();
var ce = me.events[ename] || true;
if (typeof ce == 'boolean') {
ce = new Ext.util.Event(me, ename);
me.events[ename] = ce;
}
ce.bubble = true;
}
}
}
};
}());
/**
* Starts capture on the specified Observable. All events will be passed
* to the supplied function with the event name + standard signature of the event
* before the event is fired. If the supplied function returns false,
* the event will not fire.
* @param {Observable} o The Observable to capture events from.
* @param {Function} fn The function to call when an event is fired.
* @param {Object} scope (optional) The scope (this
reference) in which the function is executed. Defaults to the Observable firing the event.
* @static
*/
Ext.util.Observable.capture = function(o, fn, scope){
o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
};
/**
* Sets observability on the passed class constructor.*
This makes any event fired on any instance of the passed class also fire a single event through * the class allowing for central handling of events on many instances at once.
*Usage:
Ext.util.Observable.observeClass(Ext.data.Connection);
Ext.data.Connection.on('beforerequest', function(con, options) {
console.log('Ajax request made to ' + options.url);
});
* @param {Function} c The class constructor to make observable.
* @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}.
* @static
*/
Ext.util.Observable.observeClass = function(c, listeners){
if(c){
if(!c.fireEvent){
Ext.apply(c, new Ext.util.Observable());
Ext.util.Observable.capture(c.prototype, c.fireEvent, c);
}
if(typeof listeners == 'object'){
c.on(listeners);
}
return c;
}
};
/**
* @class Ext.EventManager
*/
Ext.apply(Ext.EventManager, function(){
var resizeEvent,
resizeTask,
textEvent,
textSize,
D = Ext.lib.Dom,
propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
unload = Ext.EventManager._unload,
curWidth = 0,
curHeight = 0,
// note 1: IE fires ONLY the keydown event on specialkey autorepeat
// note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat
// (research done by @Jan Wolter at http://unixpapa.com/js/key.html)
useKeydown = Ext.isWebKit ?
Ext.num(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1]) >= 525 :
!((Ext.isGecko && !Ext.isWindows) || Ext.isOpera);
return {
_unload: function(){
Ext.EventManager.un(window, "resize", this.fireWindowResize, this);
unload.call(Ext.EventManager);
},
// private
doResizeEvent: function(){
var h = D.getViewHeight(),
w = D.getViewWidth();
//whacky problem in IE where the resize event will fire even though the w/h are the same.
if(curHeight != h || curWidth != w){
resizeEvent.fire(curWidth = w, curHeight = h);
}
},
/**
* Adds a listener to be notified when the browser window is resized and provides resize event buffering (100 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}
*/
onWindowResize : function(fn, scope, options){
if(!resizeEvent){
resizeEvent = new Ext.util.Event();
resizeTask = new Ext.util.DelayedTask(this.doResizeEvent);
Ext.EventManager.on(window, "resize", this.fireWindowResize, this);
}
resizeEvent.addListener(fn, scope, options);
},
// exposed only to allow manual firing
fireWindowResize : function(){
if(resizeEvent){
resizeTask.delay(100);
}
},
/**
* Adds a listener to be notified when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
* @param {Function} fn The function the 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}
*/
onTextResize : function(fn, scope, options){
if(!textEvent){
textEvent = new Ext.util.Event();
var textEl = new Ext.Element(document.createElement('div'));
textEl.dom.className = 'x-text-resize';
textEl.dom.innerHTML = 'X';
textEl.appendTo(document.body);
textSize = textEl.dom.offsetHeight;
setInterval(function(){
if(textEl.dom.offsetHeight != textSize){
textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
}
}, this.textResizeInterval);
}
textEvent.addListener(fn, scope, options);
},
/**
* Removes the passed window resize listener.
* @param {Function} fn The method the event invokes
* @param {Object} scope The scope of handler
*/
removeResizeListener : function(fn, scope){
if(resizeEvent){
resizeEvent.removeListener(fn, scope);
}
},
// private
fireResize : function(){
if(resizeEvent){
resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
}
},
/**
* The frequency, in milliseconds, to check for text resize events (defaults to 50)
*/
textResizeInterval : 50,
/**
* Url used for onDocumentReady with using SSL (defaults to Ext.SSL_SECURE_URL)
*/
ieDeferSrc : false,
// protected, short accessor for useKeydown
getKeyEvent : function(){
return useKeydown ? 'keydown' : 'keypress';
},
// protected for use inside the framework
// detects whether we should use keydown or keypress based on the browser.
useKeydown: useKeydown
};
}());
Ext.EventManager.on = Ext.EventManager.addListener;
Ext.apply(Ext.EventObjectImpl.prototype, {
/** Key constant @type Number */
BACKSPACE: 8,
/** Key constant @type Number */
TAB: 9,
/** Key constant @type Number */
NUM_CENTER: 12,
/** Key constant @type Number */
ENTER: 13,
/** Key constant @type Number */
RETURN: 13,
/** Key constant @type Number */
SHIFT: 16,
/** Key constant @type Number */
CTRL: 17,
CONTROL : 17, // legacy
/** Key constant @type Number */
ALT: 18,
/** Key constant @type Number */
PAUSE: 19,
/** Key constant @type Number */
CAPS_LOCK: 20,
/** Key constant @type Number */
ESC: 27,
/** Key constant @type Number */
SPACE: 32,
/** Key constant @type Number */
PAGE_UP: 33,
PAGEUP : 33, // legacy
/** Key constant @type Number */
PAGE_DOWN: 34,
PAGEDOWN : 34, // legacy
/** Key constant @type Number */
END: 35,
/** Key constant @type Number */
HOME: 36,
/** Key constant @type Number */
LEFT: 37,
/** Key constant @type Number */
UP: 38,
/** Key constant @type Number */
RIGHT: 39,
/** Key constant @type Number */
DOWN: 40,
/** Key constant @type Number */
PRINT_SCREEN: 44,
/** Key constant @type Number */
INSERT: 45,
/** Key constant @type Number */
DELETE: 46,
/** Key constant @type Number */
ZERO: 48,
/** Key constant @type Number */
ONE: 49,
/** Key constant @type Number */
TWO: 50,
/** Key constant @type Number */
THREE: 51,
/** Key constant @type Number */
FOUR: 52,
/** Key constant @type Number */
FIVE: 53,
/** Key constant @type Number */
SIX: 54,
/** Key constant @type Number */
SEVEN: 55,
/** Key constant @type Number */
EIGHT: 56,
/** Key constant @type Number */
NINE: 57,
/** Key constant @type Number */
A: 65,
/** Key constant @type Number */
B: 66,
/** Key constant @type Number */
C: 67,
/** Key constant @type Number */
D: 68,
/** Key constant @type Number */
E: 69,
/** Key constant @type Number */
F: 70,
/** Key constant @type Number */
G: 71,
/** Key constant @type Number */
H: 72,
/** Key constant @type Number */
I: 73,
/** Key constant @type Number */
J: 74,
/** Key constant @type Number */
K: 75,
/** Key constant @type Number */
L: 76,
/** Key constant @type Number */
M: 77,
/** Key constant @type Number */
N: 78,
/** Key constant @type Number */
O: 79,
/** Key constant @type Number */
P: 80,
/** Key constant @type Number */
Q: 81,
/** Key constant @type Number */
R: 82,
/** Key constant @type Number */
S: 83,
/** Key constant @type Number */
T: 84,
/** Key constant @type Number */
U: 85,
/** Key constant @type Number */
V: 86,
/** Key constant @type Number */
W: 87,
/** Key constant @type Number */
X: 88,
/** Key constant @type Number */
Y: 89,
/** Key constant @type Number */
Z: 90,
/** Key constant @type Number */
CONTEXT_MENU: 93,
/** Key constant @type Number */
NUM_ZERO: 96,
/** Key constant @type Number */
NUM_ONE: 97,
/** Key constant @type Number */
NUM_TWO: 98,
/** Key constant @type Number */
NUM_THREE: 99,
/** Key constant @type Number */
NUM_FOUR: 100,
/** Key constant @type Number */
NUM_FIVE: 101,
/** Key constant @type Number */
NUM_SIX: 102,
/** Key constant @type Number */
NUM_SEVEN: 103,
/** Key constant @type Number */
NUM_EIGHT: 104,
/** Key constant @type Number */
NUM_NINE: 105,
/** Key constant @type Number */
NUM_MULTIPLY: 106,
/** Key constant @type Number */
NUM_PLUS: 107,
/** Key constant @type Number */
NUM_MINUS: 109,
/** Key constant @type Number */
NUM_PERIOD: 110,
/** Key constant @type Number */
NUM_DIVISION: 111,
/** Key constant @type Number */
F1: 112,
/** Key constant @type Number */
F2: 113,
/** Key constant @type Number */
F3: 114,
/** Key constant @type Number */
F4: 115,
/** Key constant @type Number */
F5: 116,
/** Key constant @type Number */
F6: 117,
/** Key constant @type Number */
F7: 118,
/** Key constant @type Number */
F8: 119,
/** Key constant @type Number */
F9: 120,
/** Key constant @type Number */
F10: 121,
/** Key constant @type Number */
F11: 122,
/** Key constant @type Number */
F12: 123,
/** @private */
isNavKeyPress : function(){
var me = this,
k = this.normalizeKey(me.keyCode);
return (k >= 33 && k <= 40) || // Page Up/Down, End, Home, Left, Up, Right, Down
k == me.RETURN ||
k == me.TAB ||
k == me.ESC;
},
isSpecialKey : function(){
var k = this.normalizeKey(this.keyCode);
return (this.type == 'keypress' && this.ctrlKey) ||
this.isNavKeyPress() ||
(k == this.BACKSPACE) || // Backspace
(k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
(k >= 44 && k <= 46); // Print Screen, Insert, Delete
},
getPoint : function(){
return new Ext.lib.Point(this.xy[0], this.xy[1]);
},
/**
* Returns true if the control, meta, shift or alt key was pressed during this event.
* @return {Boolean}
*/
hasModifier : function(){
return ((this.ctrlKey || this.altKey) || this.shiftKey);
}
});/**
* @class Ext.Element
*/
Ext.Element.addMethods({
/**
* Stops the specified event(s) from bubbling and optionally prevents the default action
* @param {String/Array} eventName an event / array of events to stop from bubbling
* @param {Boolean} preventDefault (optional) true to prevent the default action too
* @return {Ext.Element} this
*/
swallowEvent : function(eventName, preventDefault) {
var me = this;
function fn(e) {
e.stopPropagation();
if (preventDefault) {
e.preventDefault();
}
}
if (Ext.isArray(eventName)) {
Ext.each(eventName, function(e) {
me.on(e, fn);
});
return me;
}
me.on(eventName, fn);
return me;
},
/**
* Create an event handler on this element such that when the event fires and is handled by this element,
* it will be relayed to another object (i.e., fired again as if it originated from that object instead).
* @param {String} eventName The type of event to relay
* @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
* for firing the relayed event
*/
relayEvent : function(eventName, observable) {
this.on(eventName, function(e) {
observable.fireEvent(eventName, e);
});
},
/**
* Removes worthless text nodes
* @param {Boolean} forceReclean (optional) By default the element
* keeps track if it has been cleaned already so
* you can call this over and over. However, if you update the element and
* need to force a reclean, you can pass true.
*/
clean : function(forceReclean) {
var me = this,
dom = me.dom,
n = dom.firstChild,
ni = -1;
if (Ext.Element.data(dom, 'isCleaned') && forceReclean !== true) {
return me;
}
while (n) {
var nx = n.nextSibling;
if (n.nodeType == 3 && !(/\S/.test(n.nodeValue))) {
dom.removeChild(n);
} else {
n.nodeIndex = ++ni;
}
n = nx;
}
Ext.Element.data(dom, 'isCleaned', true);
return me;
},
/**
* Direct access to the Updater {@link Ext.Updater#update} method. The method takes the same object
* parameter as {@link Ext.Updater#update}
* @return {Ext.Element} this
*/
load : function() {
var updateManager = this.getUpdater();
updateManager.update.apply(updateManager, arguments);
return this;
},
/**
* Gets this element's {@link Ext.Updater Updater}
* @return {Ext.Updater} The Updater
*/
getUpdater : function() {
return this.updateManager || (this.updateManager = new Ext.Updater(this));
},
/**
* Update the innerHTML of this element, optionally searching for and processing scripts
* @param {String} html The new HTML
* @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)
* @param {Function} callback (optional) For async script loading you can be notified when the update completes
* @return {Ext.Element} this
*/
update : function(html, loadScripts, callback) {
if (!this.dom) {
return this;
}
html = html || "";
if (loadScripts !== true) {
this.dom.innerHTML = html;
if (typeof callback == 'function') {
callback();
}
return this;
}
var id = Ext.id(),
dom = this.dom;
html += '';
Ext.lib.Event.onAvailable(id, function() {
var DOC = document,
hd = DOC.getElementsByTagName("head")[0],
re = /(?: