X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/c930e9176a5a85509c5b0230e2bff5c22a591432..25ef3491bd9ae007ff1fc2b0d7943e6eaaccf775:/pkgs/ext-foundation-debug.js diff --git a/pkgs/ext-foundation-debug.js b/pkgs/ext-foundation-debug.js index 097d7d2c..baa1285c 100644 --- a/pkgs/ext-foundation-debug.js +++ b/pkgs/ext-foundation-debug.js @@ -1,380 +1,418 @@ /*! - * Ext JS Library 3.0.0 + * Ext JS Library 3.0.3 * Copyright(c) 2006-2009 Ext JS, LLC * licensing@extjs.com * http://www.extjs.com/license */ -/** - * @class Ext.DomHelper - *

The DomHelper class provides a layer of abstraction from DOM and transparently supports creating - * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates - * from your DOM building code.

- * - *

DomHelper element specification object

- *

A specification object is used when creating elements. Attributes of this object - * are assumed to be element attributes, except for 4 special attributes: - *

- * - *

Insertion methods

- *

Commonly used insertion methods: - *

- * - *

Example

- *

This is an example, where an unordered list with 3 children items is appended to an existing - * element with id 'my-div':
-


-var dh = Ext.DomHelper; // create shorthand alias
-// specification object
-var spec = {
-    id: 'my-ul',
-    tag: 'ul',
-    cls: 'my-list',
-    // append children after creating
-    children: [     // may also specify 'cn' instead of 'children'
-        {tag: 'li', id: 'item0', html: 'List Item 0'},
-        {tag: 'li', id: 'item1', html: 'List Item 1'},
-        {tag: 'li', id: 'item2', html: 'List Item 2'}
-    ]
-};
-var list = dh.append(
-    'my-div', // the context element 'my-div' can either be the id or the actual node
-    spec      // the specification object
-);
- 

- *

Element creation specification parameters in this class may also be passed as an Array of - * specification objects. This can be used to insert multiple sibling nodes into an existing - * container very efficiently. For example, to add more list items to the example above:


-dh.append('my-ul', [
-    {tag: 'li', id: 'item3', html: 'List Item 3'},
-    {tag: 'li', id: 'item4', html: 'List Item 4'}
-]);
- * 

- * - *

Templating

- *

The real power is in the built-in templating. Instead of creating or appending any elements, - * {@link #createTemplate} returns a Template object which can be used over and over to - * insert new elements. Revisiting the example above, we could utilize templating this time: - *


-// create the node
-var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
-// get template
-var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
-
-for(var i = 0; i < 5, i++){
-    tpl.append(list, [i]); // use template to append to the actual node
-}
- * 

- *

An example using a template:


-var html = '{2}';
-
-var tpl = new Ext.DomHelper.createTemplate(html);
-tpl.append('blog-roll', ['link1', 'http://www.jackslocum.com/', "Jack's Site"]);
-tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin's Site"]);
- * 

- * - *

The same example using named parameters:


-var html = '{text}';
-
-var tpl = new Ext.DomHelper.createTemplate(html);
-tpl.append('blog-roll', {
-    id: 'link1',
-    url: 'http://www.jackslocum.com/',
-    text: "Jack's Site"
-});
-tpl.append('blog-roll', {
-    id: 'link2',
-    url: 'http://www.dustindiaz.com/',
-    text: "Dustin's Site"
-});
- * 

- * - *

Compiling Templates

- *

Templates are applied using regular expressions. The performance is great, but if - * you are adding a bunch of DOM elements using the same template, you can increase - * performance even further by {@link Ext.Template#compile "compiling"} the template. - * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and - * broken up at the different variable points and a dynamic function is created and eval'ed. - * The generated function performs string concatenation of these parts and the passed - * variables instead of using regular expressions. - *


-var html = '{text}';
-
-var tpl = new Ext.DomHelper.createTemplate(html);
-tpl.compile();
-
-//... use template like normal
- * 

- * - *

Performance Boost

- *

DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead - * of DOM can significantly boost performance.

- *

Element creation specification parameters may also be strings. If {@link #useDom} is false, - * then the string is used as innerHTML. If {@link #useDom} is true, a string specification - * results in the creation of a text node. Usage:

- *

-Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
- * 
- * @singleton - */ -Ext.DomHelper = function(){ - var tempTableEl = null, - emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i, - tableRe = /^table|tbody|tr|td$/i, - pub, - // kill repeat to save bytes - afterbegin = "afterbegin", - afterend = "afterend", - beforebegin = "beforebegin", - beforeend = "beforeend", - ts = '', - te = '
', - tbs = ts+'', - tbe = ''+te, - trs = tbs + '', - tre = ''+tbe; - - // private - function doInsert(el, o, returnElement, pos, sibling, append){ - var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o)); - return returnElement ? Ext.get(newNode, true) : newNode; - } - - // build as innerHTML where available - function createHtml(o){ - var b = "", - attr, - val, - key, - keyVal, - cn; - - if(typeof o == 'string'){ - b = o; - } else if (Ext.isArray(o)) { - Ext.each(o, function(v) { - b += createHtml(v); - }); - } else { - b += "<" + (o.tag = o.tag || "div"); - Ext.iterate(o, function(attr, val){ - if(!/tag|children|cn|html$/i.test(attr)){ - if (Ext.isObject(val)) { - b += " " + attr + "='"; - Ext.iterate(val, function(key, keyVal){ - b += key + ":" + keyVal + ";"; - }); - b += "'"; - }else{ - b += " " + ({cls : "class", htmlFor : "for"}[attr] || attr) + "='" + val + "'"; - } - } - }); - // Now either just close the tag or try to add children and close the tag. - if (emptyTags.test(o.tag)) { - b += "/>"; - } else { - b += ">"; - if ((cn = o.children || o.cn)) { - b += createHtml(cn); - } else if(o.html){ - b += o.html; - } - b += ""; - } - } - return b; - } - - function ieTable(depth, s, h, e){ - tempTableEl.innerHTML = [s, h, e].join(''); - var i = -1, - el = tempTableEl; - while(++i < depth){ - el = el.firstChild; - } - return el; - } - - /** - * @ignore - * Nasty code for IE's broken table implementation - */ - function insertIntoTable(tag, where, el, html) { - var node, - before; - - tempTableEl = tempTableEl || document.createElement('div'); - - if(tag == 'td' && (where == afterbegin || where == beforeend) || - !/td|tr|tbody/i.test(tag) && (where == beforebegin || where == afterend)) { - return; - } - before = where == beforebegin ? el : - where == afterend ? el.nextSibling : - where == afterbegin ? el.firstChild : null; - - if (where == beforebegin || where == afterend) { - el = el.parentNode; - } - - if (tag == 'td' || (tag == "tr" && (where == beforeend || where == afterbegin))) { - node = ieTable(4, trs, html, tre); - } else if ((tag == "tbody" && (where == beforeend || where == afterbegin)) || - (tag == "tr" && (where == beforebegin || where == afterend))) { - node = ieTable(3, tbs, html, tbe); - } else { - node = ieTable(2, ts, html, te); - } - el.insertBefore(node, before); - return node; - } - - - pub = { - /** - * Returns the markup for the passed Element(s) config. - * @param {Object} o The DOM object spec (and children) - * @return {String} - */ - markup : function(o){ - return createHtml(o); - }, - - /** - * Inserts an HTML fragment into the DOM. - * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd. - * @param {HTMLElement} el The context element - * @param {String} html The HTML fragmenet - * @return {HTMLElement} The new node - */ - insertHtml : function(where, el, html){ - var hash = {}, - hashVal, - setStart, - range, - frag, - rangeEl, - rs; - - where = where.toLowerCase(); - // add these here because they are used in both branches of the condition. - hash[beforebegin] = ['BeforeBegin', 'previousSibling']; - hash[afterend] = ['AfterEnd', 'nextSibling']; - - if (el.insertAdjacentHTML) { - if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){ - return rs; - } - // add these two to the hash. - hash[afterbegin] = ['AfterBegin', 'firstChild']; - hash[beforeend] = ['BeforeEnd', 'lastChild']; - if ((hashVal = hash[where])) { - el.insertAdjacentHTML(hashVal[0], html); - return el[hashVal[1]]; - } - } else { - range = el.ownerDocument.createRange(); - setStart = "setStart" + (/end/i.test(where) ? "After" : "Before"); - if (hash[where]) { - range[setStart](el); - frag = range.createContextualFragment(html); - el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling); - return el[(where == beforebegin ? "previous" : "next") + "Sibling"]; - } else { - rangeEl = (where == afterbegin ? "first" : "last") + "Child"; - if (el.firstChild) { - range[setStart](el[rangeEl]); - frag = range.createContextualFragment(html); - if(where == afterbegin){ - el.insertBefore(frag, el.firstChild); - }else{ - el.appendChild(frag); - } - } else { - el.innerHTML = html; - } - return el[rangeEl]; - } - } - throw 'Illegal insertion point -> "' + where + '"'; - }, - - /** - * 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 - */ - 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 - */ - 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 - */ - 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 - */ - append : function(el, o, returnElement){ - return doInsert(el, o, returnElement, beforeend, "", true); - }, - - /** - * Creates new DOM element(s) and overwrites the contents of el with them. - * @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 - */ - overwrite : function(el, o, returnElement){ - el = Ext.getDom(el); - el.innerHTML = createHtml(o); - return returnElement ? Ext.get(el.firstChild) : el.firstChild; - }, - - createHtml : createHtml - }; - return pub; +/** + * @class Ext.DomHelper + *

The DomHelper class provides a layer of abstraction from DOM and transparently supports creating + * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates + * from your DOM building code.

+ * + *

DomHelper element specification object

+ *

A specification object is used when creating elements. Attributes of this object + * are assumed to be element attributes, except for 4 special attributes: + *

+ * + *

Insertion methods

+ *

Commonly used insertion methods: + *

+ * + *

Example

+ *

This is an example, where an unordered list with 3 children items is appended to an existing + * element with id 'my-div':
+


+var dh = Ext.DomHelper; // create shorthand alias
+// specification object
+var spec = {
+    id: 'my-ul',
+    tag: 'ul',
+    cls: 'my-list',
+    // append children after creating
+    children: [     // may also specify 'cn' instead of 'children'
+        {tag: 'li', id: 'item0', html: 'List Item 0'},
+        {tag: 'li', id: 'item1', html: 'List Item 1'},
+        {tag: 'li', id: 'item2', html: 'List Item 2'}
+    ]
+};
+var list = dh.append(
+    'my-div', // the context element 'my-div' can either be the id or the actual node
+    spec      // the specification object
+);
+ 

+ *

Element creation specification parameters in this class may also be passed as an Array of + * specification objects. This can be used to insert multiple sibling nodes into an existing + * container very efficiently. For example, to add more list items to the example above:


+dh.append('my-ul', [
+    {tag: 'li', id: 'item3', html: 'List Item 3'},
+    {tag: 'li', id: 'item4', html: 'List Item 4'}
+]);
+ * 

+ * + *

Templating

+ *

The real power is in the built-in templating. Instead of creating or appending any elements, + * {@link #createTemplate} returns a Template object which can be used over and over to + * insert new elements. Revisiting the example above, we could utilize templating this time: + *


+// create the node
+var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
+// get template
+var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
+
+for(var i = 0; i < 5, i++){
+    tpl.append(list, [i]); // use template to append to the actual node
+}
+ * 

+ *

An example using a template:


+var html = '{2}';
+
+var tpl = new Ext.DomHelper.createTemplate(html);
+tpl.append('blog-roll', ['link1', 'http://www.jackslocum.com/', "Jack's Site"]);
+tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin's Site"]);
+ * 

+ * + *

The same example using named parameters:


+var html = '{text}';
+
+var tpl = new Ext.DomHelper.createTemplate(html);
+tpl.append('blog-roll', {
+    id: 'link1',
+    url: 'http://www.jackslocum.com/',
+    text: "Jack's Site"
+});
+tpl.append('blog-roll', {
+    id: 'link2',
+    url: 'http://www.dustindiaz.com/',
+    text: "Dustin's Site"
+});
+ * 

+ * + *

Compiling Templates

+ *

Templates are applied using regular expressions. The performance is great, but if + * you are adding a bunch of DOM elements using the same template, you can increase + * performance even further by {@link Ext.Template#compile "compiling"} the template. + * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and + * broken up at the different variable points and a dynamic function is created and eval'ed. + * The generated function performs string concatenation of these parts and the passed + * variables instead of using regular expressions. + *


+var html = '{text}';
+
+var tpl = new Ext.DomHelper.createTemplate(html);
+tpl.compile();
+
+//... use template like normal
+ * 

+ * + *

Performance Boost

+ *

DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead + * of DOM can significantly boost performance.

+ *

Element creation specification parameters may also be strings. If {@link #useDom} is false, + * then the string is used as innerHTML. If {@link #useDom} is true, a string specification + * results in the creation of a text node. Usage:

+ *

+Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
+ * 
+ * @singleton + */ +Ext.DomHelper = function(){ + var tempTableEl = null, + emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i, + tableRe = /^table|tbody|tr|td$/i, + pub, + // kill repeat to save bytes + afterbegin = 'afterbegin', + afterend = 'afterend', + beforebegin = 'beforebegin', + beforeend = 'beforeend', + ts = '', + te = '
', + tbs = ts+'', + tbe = ''+te, + trs = tbs + '', + tre = ''+tbe; + + // private + function doInsert(el, o, returnElement, pos, sibling, append){ + var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o)); + return returnElement ? Ext.get(newNode, true) : newNode; + } + + // build as innerHTML where available + function createHtml(o){ + var b = '', + attr, + val, + key, + keyVal, + cn; + + if(Ext.isString(o)){ + b = o; + } else if (Ext.isArray(o)) { + Ext.each(o, function(v) { + b += createHtml(v); + }); + } else { + b += '<' + (o.tag = o.tag || 'div'); + Ext.iterate(o, function(attr, val){ + if(!/tag|children|cn|html$/i.test(attr)){ + if (Ext.isObject(val)) { + b += ' ' + attr + '="'; + Ext.iterate(val, function(key, keyVal){ + b += key + ':' + keyVal + ';'; + }); + b += '"'; + }else{ + b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"'; + } + } + }); + // Now either just close the tag or try to add children and close the tag. + if (emptyTags.test(o.tag)) { + b += '/>'; + } else { + b += '>'; + if ((cn = o.children || o.cn)) { + b += createHtml(cn); + } else if(o.html){ + b += o.html; + } + b += ''; + } + } + return b; + } + + function ieTable(depth, s, h, e){ + tempTableEl.innerHTML = [s, h, e].join(''); + var i = -1, + el = tempTableEl, + ns; + while(++i < depth){ + el = el.firstChild; + } +// If the result is multiple siblings, then encapsulate them into one fragment. + if(ns = el.nextSibling){ + var df = document.createDocumentFragment(); + while(el){ + ns = el.nextSibling; + df.appendChild(el); + el = ns; + } + el = df; + } + return el; + } + + /** + * @ignore + * Nasty code for IE's broken table implementation + */ + function insertIntoTable(tag, where, el, html) { + var node, + before; + + tempTableEl = tempTableEl || document.createElement('div'); + + if(tag == 'td' && (where == afterbegin || where == beforeend) || + !/td|tr|tbody/i.test(tag) && (where == beforebegin || where == afterend)) { + return; + } + before = where == beforebegin ? el : + where == afterend ? el.nextSibling : + where == afterbegin ? el.firstChild : null; + + if (where == beforebegin || where == afterend) { + el = el.parentNode; + } + + if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) { + node = ieTable(4, trs, html, tre); + } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) || + (tag == 'tr' && (where == beforebegin || where == afterend))) { + node = ieTable(3, tbs, html, tbe); + } else { + node = ieTable(2, ts, html, te); + } + el.insertBefore(node, before); + return node; + } + + + pub = { + /** + * Returns the markup for the passed Element(s) config. + * @param {Object} o The DOM object spec (and children) + * @return {String} + */ + markup : function(o){ + return createHtml(o); + }, + + /** + * Applies a style specification to an element. + * @param {String/HTMLElement} el The element to apply styles to + * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or + * a function which returns such a specification. + */ + applyStyles : function(el, styles){ + if(styles){ + var i = 0, + len, + style; + + el = Ext.fly(el); + if(Ext.isFunction(styles)){ + styles = styles.call(); + } + if(Ext.isString(styles)){ + styles = styles.trim().split(/\s*(?::|;)\s*/); + for(len = styles.length; i < len;){ + el.setStyle(styles[i++], styles[i++]); + } + }else if (Ext.isObject(styles)){ + el.setStyle(styles); + } + } + }, + + /** + * Inserts an HTML fragment into the DOM. + * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd. + * @param {HTMLElement} el The context element + * @param {String} html The HTML fragment + * @return {HTMLElement} The new node + */ + insertHtml : function(where, el, html){ + var hash = {}, + hashVal, + setStart, + range, + frag, + rangeEl, + rs; + + where = where.toLowerCase(); + // add these here because they are used in both branches of the condition. + hash[beforebegin] = ['BeforeBegin', 'previousSibling']; + hash[afterend] = ['AfterEnd', 'nextSibling']; + + if (el.insertAdjacentHTML) { + if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){ + return rs; + } + // add these two to the hash. + hash[afterbegin] = ['AfterBegin', 'firstChild']; + hash[beforeend] = ['BeforeEnd', 'lastChild']; + if ((hashVal = hash[where])) { + el.insertAdjacentHTML(hashVal[0], html); + return el[hashVal[1]]; + } + } else { + range = el.ownerDocument.createRange(); + setStart = 'setStart' + (/end/i.test(where) ? 'After' : 'Before'); + if (hash[where]) { + range[setStart](el); + frag = range.createContextualFragment(html); + el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling); + return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling']; + } else { + rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child'; + if (el.firstChild) { + range[setStart](el[rangeEl]); + frag = range.createContextualFragment(html); + if(where == afterbegin){ + el.insertBefore(frag, el.firstChild); + }else{ + el.appendChild(frag); + } + } else { + el.innerHTML = html; + } + return el[rangeEl]; + } + } + throw 'Illegal insertion point -> "' + where + '"'; + }, + + /** + * 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 + */ + 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 + */ + 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 + */ + 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 + */ + append : function(el, o, returnElement){ + return doInsert(el, o, returnElement, beforeend, '', true); + }, + + /** + * Creates new DOM element(s) and overwrites the contents of el with them. + * @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 + */ + overwrite : function(el, o, returnElement){ + el = Ext.getDom(el); + el.innerHTML = createHtml(o); + return returnElement ? Ext.get(el.firstChild) : el.firstChild; + }, + + createHtml : createHtml + }; + return pub; }();/** * @class Ext.DomHelper */ @@ -436,7 +474,7 @@ function(){ } } }); - pub.applyStyles(el, o.style); + Ext.DomHelper.applyStyles(el, o.style); if ((cn = o.children || o.cn)) { createDom(cn, el); @@ -464,33 +502,6 @@ function(){ /** True to force the use of DOM instead of html fragments @type Boolean */ useDom : false, - /** - * Applies a style specification to an element. - * @param {String/HTMLElement} el The element to apply styles to - * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or - * a function which returns such a specification. - */ - applyStyles : function(el, styles){ - if(styles){ - var i = 0, - len, - style; - - el = Ext.fly(el); - if(Ext.isFunction(styles)){ - styles = styles.call(); - } - if(Ext.isString(styles)){ - styles = styles.trim().split(/\s*(?::|;)\s*/); - for(len = styles.length; i < len;){ - el.setStyle(styles[i++], styles[i++]); - } - }else if (Ext.isObject(styles)){ - el.setStyle(styles); - } - } - }, - /** * Creates new DOM element(s) and inserts them before el. * @param {Mixed} el The context element @@ -549,19 +560,58 @@ function(){ return pub; }());/** * @class Ext.Template - * Represents an HTML fragment template. Templates can be precompiled for greater performance. - * For a list of available format functions, see {@link Ext.util.Format}.
- * Usage: + *

Represents an HTML fragment template. Templates may be {@link #compile precompiled} + * for greater performance.

+ *

For example usage {@link #Template see the constructor}.

+ * + * @constructor + * An instance of this class may be created by passing to the constructor either + * a single argument, or multiple arguments: + *
+ * @param {Mixed} config */ Ext.Template = function(html){ var me = this, @@ -583,14 +633,35 @@ Ext.Template = function(html){ /**@private*/ me.html = html; + /** + * @cfg {Boolean} compiled Specify true to compile the template + * immediately (see {@link #compile}). + * Defaults to false. + */ if (me.compiled) { me.compile(); } }; Ext.Template.prototype = { /** - * 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'}) + * @cfg {RegExp} re The regular expression used to match template variables. + * Defaults to:

+     * re : /\{([\w-]+)\}/g                                     // for Ext Core
+     * re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g      // for Ext JS
+     * 
+ */ + re : /\{([\w-]+)\}/g, + /** + * See {@link #re}. + * @type RegExp + * @property re + */ + + /** + * Returns an HTML fragment of this template with the specified values applied. + * @param {Object/Array} values + * The template values. Can be an array if the params are numeric (i.e. {0}) + * or an object (i.e. {foo: 'bar'}). * @return {String} The HTML fragment */ applyTemplate : function(values){ @@ -616,13 +687,6 @@ Ext.Template.prototype = { return compile ? me.compile() : me; }, - /** - * The regular expression used to match template variables - * @type RegExp - * @property - */ - re : /\{([\w-]+)\}/g, - /** * Compiles the template into an internal function, eliminating the RegEx overhead. * @return {Ext.Template} this @@ -676,10 +740,14 @@ Ext.Template.prototype = { }, /** - * Applies the supplied values to the template and appends the new node(s) to el. + * Applies the supplied values to the template and appends + * the new node(s) to the specified el. + *

For example usage {@link #Template see the constructor}.

* @param {Mixed} el The context element - * @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'}) - * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined) + * @param {Object/Array} values + * The template values. Can be an array if the params are numeric (i.e. {0}) + * or an object (i.e. {foo: 'bar'}). + * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined) * @return {HTMLElement/Ext.Element} The new node or Element */ append : function(el, values, returnElement){ @@ -707,8 +775,10 @@ Ext.Template.prototype = { }; /** * Alias for {@link #applyTemplate} - * 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'}) + * Returns an HTML fragment of this template with the specified values applied. + * @param {Object/Array} values + * The template values. Can be an array if the params are numeric (i.e. {0}) + * or an object (i.e. {foo: 'bar'}). * @return {String} The HTML fragment * @member Ext.Template * @method apply @@ -730,13 +800,46 @@ Ext.Template.from = function(el, config){ */ Ext.apply(Ext.Template.prototype, { /** - * 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 + * @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}. */ - applyTemplate : function(values){ - var me = this, + 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, + + /** + * 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; @@ -771,21 +874,6 @@ Ext.apply(Ext.Template.prototype, { return me.html.replace(me.re, fn); }, - /** - * true to disable format functions (defaults to false) - * @type Boolean - * @property - */ - disableFormats : false, - - /** - * The regular expression used to match template variables - * @type RegExp - * @property - * @hide repeat doc - */ - re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g, - /** * Compiles the template into an internal function, eliminating the RegEx overhead. * @return {Ext.Template} this @@ -1457,8 +1545,29 @@ Ext.DomQuery = function(){ }, /** - * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array) - * and the argument (if any) supplied in the selector. + *

Object hash of "pseudo class" filter functions which are used when filtering selections. Each function is passed + * two parameters:

+ *

A filter function returns an Array of DOM elements which conform to the pseudo class.

+ *

In addition to the provided pseudo classes listed above such as first-child and nth-child, + * developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.

+ *

For example, to filter <a> elements to only return links to external resources:

+ *
+Ext.DomQuery.pseudos.external = function(c, v){
+    var r = [], ri = -1;
+    for(var i = 0, ci; ci = c[i]; i++){
+//      Include in result set only if it's a link to an external resource
+        if(ci.hostname != location.hostname){
+            r[++ri] = ci;
+        }
+    }
+    return r;
+};
+ * Then external links could be gathered with the following statement:
+var externalLinks = Ext.select("a:external");
+
*/ pseudos : { "first-child" : function(c){ @@ -1765,216 +1874,221 @@ var combo = new Ext.form.ComboBox({ me.events = e || {}; }; -EXTUTIL.Observable.prototype = function(){ - var filterOptRe = /^(?:scope|delay|buffer|single)$/, toLower = function(s){ - return s.toLowerCase(); - }; - - return { - /** - *

Fires the specified event with the passed parameters (minus the event name).

- *

An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget}) - * by calling {@link #enableBubble}.

- * @param {String} eventName The name of the event to fire. - * @param {Object...} args Variable number of parameters are passed to handlers. - * @return {Boolean} returns false if any of the handlers return false otherwise it returns true. - */ +EXTUTIL.Observable.prototype = { + // private + filterOptRe : /^(?:scope|delay|buffer|single)$/, - fireEvent : function(){ - var a = TOARRAY(arguments), - ename = toLower(a[0]), - me = this, - ret = TRUE, - ce = me.events[ename], - q, - c; - if (me.eventsSuspended === TRUE) { - if (q = me.suspendedEventsQueue) { - q.push(a); - } + /** + *

Fires the specified event with the passed parameters (minus the event name).

+ *

An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget}) + * by calling {@link #enableBubble}.

+ * @param {String} eventName The name of the event to fire. + * @param {Object...} args Variable number of parameters are passed to handlers. + * @return {Boolean} returns false if any of the handlers return false otherwise it returns true. + */ + fireEvent : function(){ + var a = TOARRAY(arguments), + ename = a[0].toLowerCase(), + me = this, + ret = TRUE, + ce = me.events[ename], + q, + c; + if (me.eventsSuspended === TRUE) { + if (q = me.eventQueue) { + q.push(a); } - else if(ISOBJECT(ce) && ce.bubble){ - if(ce.fire.apply(ce, a.slice(1)) === FALSE) { - return FALSE; - } - c = me.getBubbleTarget && me.getBubbleTarget(); - if(c && c.enableBubble) { + } + else if(ISOBJECT(ce) && ce.bubble){ + if(ce.fire.apply(ce, a.slice(1)) === FALSE) { + return FALSE; + } + c = me.getBubbleTarget && me.getBubbleTarget(); + if(c && c.enableBubble) { + if(!c.events[ename] || !Ext.isObject(c.events[ename]) || !c.events[ename].bubble) { c.enableBubble(ename); - return c.fireEvent.apply(c, a); } + return c.fireEvent.apply(c, a); } - else { - if (ISOBJECT(ce)) { - a.shift(); - ret = ce.fire.apply(ce, a); - } + } + else { + if (ISOBJECT(ce)) { + a.shift(); + ret = ce.fire.apply(ce, a); } - return ret; - }, + } + return ret; + }, - /** - * Appends an event handler to this object. - * @param {String} eventName The name of the event to listen for. - * @param {Function} handler The method the event invokes. - * @param {Object} scope (optional) The scope (this reference) in which the handler function is executed. - * If omitted, defaults to the object which fired the event. - * @param {Object} options (optional) An object containing handler configuration. - * properties. This may contain any of the following properties:
- *

- * Combining Options
- * Using the options argument, it is possible to combine different types of listeners:
- *
- * A delayed, one-time listener. - *


+    /**
+     * Appends an event handler to this object.
+     * @param {String}   eventName The name of the event to listen for.
+     * @param {Function} handler The method the event invokes.
+     * @param {Object}   scope (optional) The scope (this reference) in which the handler function is executed.
+     * If omitted, defaults to the object which fired the event.
+     * @param {Object}   options (optional) An object containing handler configuration.
+     * properties. This may contain any of the following properties:
+ *

+ * Combining Options
+ * Using the options argument, it is possible to combine different types of listeners:
+ *
+ * A delayed, one-time listener. + *


 myDataView.on('click', this.onClick, this, {
-    single: true,
-    delay: 100
-});
- *

- * Attaching multiple handlers in 1 call
- * The method also allows for a single argument to be passed which is a config object containing properties - * which specify multiple handlers. - *

- *


-myGridPanel.on({
-    'click' : {
-        fn: this.onClick,
-        scope: this,
-        delay: 100
-    },
-    'mouseover' : {
-        fn: this.onMouseOver,
-        scope: this
-    },
-    'mouseout' : {
-        fn: this.onMouseOut,
-        scope: this
-    }
+single: true,
+delay: 100
 });
*

- * Or a shorthand syntax:
+ * Attaching multiple handlers in 1 call
+ * The method also allows for a single argument to be passed which is a config object containing properties + * which specify multiple handlers. + *

*


 myGridPanel.on({
-    'click' : this.onClick,
-    'mouseover' : this.onMouseOver,
-    'mouseout' : this.onMouseOut,
-     scope: this
+'click' : {
+    fn: this.onClick,
+    scope: this,
+    delay: 100
+},
+'mouseover' : {
+    fn: this.onMouseOver,
+    scope: this
+},
+'mouseout' : {
+    fn: this.onMouseOut,
+    scope: this
+}
 });
- */ - addListener : function(eventName, fn, scope, o){ - var me = this, - e, - oe, - isF, - ce; - if (ISOBJECT(eventName)) { - o = eventName; - for (e in o){ - oe = o[e]; - if (!filterOptRe.test(e)) { - me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o); - } - } - } else { - eventName = toLower(eventName); - ce = me.events[eventName] || TRUE; - if (typeof ce == "boolean") { - me.events[eventName] = ce = new EXTUTIL.Event(me, eventName); + *

+ * Or a shorthand syntax:
+ *


+myGridPanel.on({
+'click' : this.onClick,
+'mouseover' : this.onMouseOver,
+'mouseout' : this.onMouseOut,
+ scope: this
+});
+ */ + addListener : function(eventName, fn, scope, o){ + var me = this, + e, + oe, + isF, + ce; + if (ISOBJECT(eventName)) { + o = eventName; + for (e in o){ + oe = o[e]; + if (!me.filterOptRe.test(e)) { + me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o); } - ce.addListener(fn, scope, ISOBJECT(o) ? o : {}); } - }, - - /** - * Removes an event handler. - * @param {String} eventName The type of event the handler was associated with. - * @param {Function} handler The handler to remove. This must be a reference to the function passed into the {@link #addListener} call. - * @param {Object} scope (optional) The scope originally specified for the handler. - */ - removeListener : function(eventName, fn, scope){ - var ce = this.events[toLower(eventName)]; - if (ISOBJECT(ce)) { - ce.removeListener(fn, scope); + } else { + eventName = eventName.toLowerCase(); + ce = me.events[eventName] || TRUE; + if (Ext.isBoolean(ce)) { + me.events[eventName] = ce = new EXTUTIL.Event(me, eventName); } - }, + ce.addListener(fn, scope, ISOBJECT(o) ? o : {}); + } + }, - /** - * Removes all listeners for this object - */ - purgeListeners : function(){ - var events = this.events, - evt, - key; - for(key in events){ - evt = events[key]; - if(ISOBJECT(evt)){ - evt.clearListeners(); - } - } - }, + /** + * Removes an event handler. + * @param {String} eventName The type of event the handler was associated with. + * @param {Function} handler The handler to remove. This must be a reference to the function passed into the {@link #addListener} call. + * @param {Object} scope (optional) The scope originally specified for the handler. + */ + removeListener : function(eventName, fn, scope){ + var ce = this.events[eventName.toLowerCase()]; + if (ISOBJECT(ce)) { + ce.removeListener(fn, scope); + } + }, - /** - * Used to define events on this Observable - * @param {Object} object The object with the events defined - */ - addEvents : function(o){ - var me = this; - me.events = me.events || {}; - if (typeof o == 'string') { - EACH(arguments, function(a) { - me.events[a] = me.events[a] || TRUE; - }); - } else { - Ext.applyIf(me.events, o); + /** + * Removes all listeners for this object + */ + purgeListeners : function(){ + var events = this.events, + evt, + key; + for(key in events){ + evt = events[key]; + if(ISOBJECT(evt)){ + evt.clearListeners(); } - }, + } + }, - /** - * Checks to see if this object has any listeners for a specified event - * @param {String} eventName The name of the event to check for - * @return {Boolean} True if the event is being listened for, else false - */ - hasListener : function(eventName){ - var e = this.events[eventName]; - return ISOBJECT(e) && e.listeners.length > 0; - }, + /** + * Adds the specified events to the list of events which this Observable may fire. + * @param {Object|String} o Either an object with event names as properties with a value of true + * or the first event name string if multiple event names are being passed as separate parameters. + * @param {string} Optional. Event name if multiple event names are being passed as separate parameters. + * Usage:

+this.addEvents('storeloaded', 'storecleared');
+
+ */ + addEvents : function(o){ + var me = this; + me.events = me.events || {}; + if (Ext.isString(o)) { + EACH(arguments, function(a) { + me.events[a] = me.events[a] || TRUE; + }); + } else { + Ext.applyIf(me.events, o); + } + }, - /** - * Suspend the firing of all events. (see {@link #resumeEvents}) - * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired - * after the {@link #resumeEvents} call instead of discarding all suspended events; - */ - suspendEvents : function(queueSuspended){ - this.eventsSuspended = TRUE; - if (queueSuspended){ - this.suspendedEventsQueue = []; - } - }, + /** + * Checks to see if this object has any listeners for a specified event + * @param {String} eventName The name of the event to check for + * @return {Boolean} True if the event is being listened for, else false + */ + hasListener : function(eventName){ + var e = this.events[eventName]; + return ISOBJECT(e) && e.listeners.length > 0; + }, - /** - * Resume firing events. (see {@link #suspendEvents}) - * If events were suspended using the queueSuspended parameter, then all - * events fired during event suspension will be sent to any listeners now. - */ - resumeEvents : function(){ - var me = this; - me.eventsSuspended = !delete me.suspendedEventQueue; - EACH(me.suspendedEventsQueue, function(e) { - me.fireEvent.apply(me, e); - }); + /** + * Suspend the firing of all events. (see {@link #resumeEvents}) + * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired + * after the {@link #resumeEvents} call instead of discarding all suspended events; + */ + suspendEvents : function(queueSuspended){ + this.eventsSuspended = TRUE; + if(queueSuspended && !this.eventQueue){ + this.eventQueue = []; } + }, + + /** + * Resume firing events. (see {@link #suspendEvents}) + * If events were suspended using the queueSuspended parameter, then all + * events fired during event suspension will be sent to any listeners now. + */ + resumeEvents : function(){ + var me = this, + queued = me.eventQueue || []; + me.eventsSuspended = FALSE; + delete me.eventQueue; + EACH(queued, function(e) { + me.fireEvent.apply(me, e); + }); } -}(); +}; var OBSERVABLE = EXTUTIL.Observable.prototype; /** @@ -2247,21 +2361,56 @@ Ext.apply(Ext.util.Observable.prototype, function(){ }, /** - * Used to enable bubbling of events - * @param {Object} events + *

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 {Object} events The event name to bubble, or an Array of event names. */ enableBubble: function(events){ var me = this; - events = Ext.isArray(events) ? events : Ext.toArray(arguments); - Ext.each(events, function(ename){ - 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; - }); + if(!Ext.isEmpty(events)){ + events = Ext.isArray(events) ? events : Ext.toArray(arguments); + Ext.each(events, function(ename){ + ename = ename.toLowerCase(); + var ce = me.events[ename] || true; + if (Ext.isBoolean(ce)) { + ce = new Ext.util.Event(me, ename); + me.events[ename] = ce; + } + ce.bubble = true; + }); + } } }; }()); @@ -2309,21 +2458,21 @@ Ext.util.Observable.observeClass = function(c){ */ Ext.EventManager = function(){ var docReadyEvent, - docReadyProcId, - docReadyState = false, - E = Ext.lib.Event, - D = Ext.lib.Dom, - DOC = document, - WINDOW = window, - IEDEFERED = "ie-deferred-loader", - DOMCONTENTLOADED = "DOMContentLoaded", - elHash = {}, - propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/; + docReadyProcId, + docReadyState = false, + E = Ext.lib.Event, + D = Ext.lib.Dom, + DOC = document, + WINDOW = window, + IEDEFERED = "ie-deferred-loader", + DOMCONTENTLOADED = "DOMContentLoaded", + elHash = {}, + propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/; /// There is some jquery work around stuff here that isn't needed in Ext Core. - function addListener(el, ename, fn, wrap, scope){ + function addListener(el, ename, fn, wrap, scope){ var id = Ext.id(el), - es = elHash[id] = elHash[id] || {}; + es = elHash[id] = elHash[id] || {}; (es[ename] = es[ename] || []).push([fn, wrap, scope]); E.on(el, ename, wrap); @@ -2331,10 +2480,10 @@ Ext.EventManager = function(){ // this is a workaround for jQuery and should somehow be removed from Ext Core in the future // without breaking ExtJS. if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery - var args = ["DOMMouseScroll", wrap, false]; - el.addEventListener.apply(el, args); + var args = ["DOMMouseScroll", wrap, false]; + el.addEventListener.apply(el, args); E.on(window, 'unload', function(){ - el.removeEventListener.apply(el, args); + el.removeEventListener.apply(el, args); }); } if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document @@ -2366,8 +2515,8 @@ Ext.EventManager = function(){ }; function initDocReady(){ - var COMPLETE = "complete"; - + var COMPLETE = "complete"; + docReadyEvent = new Ext.util.Event(); if (Ext.isGecko || Ext.isOpera) { DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false); @@ -2391,7 +2540,7 @@ Ext.EventManager = function(){ function createTargeted(h, o){ return function(){ - var args = Ext.toArray(arguments); + var args = Ext.toArray(arguments); if(o.target == Ext.EventObject.setEvent(args[0]).target){ h.apply(this, args); } @@ -2425,8 +2574,8 @@ Ext.EventManager = function(){ function listen(element, ename, opt, fn, scope){ var o = !Ext.isObject(opt) ? {} : opt, - el = Ext.getDom(element); - + el = Ext.getDom(element); + fn = fn || o.fn; scope = scope || o.scope; @@ -2480,112 +2629,115 @@ Ext.EventManager = function(){ }; var pub = { - /** - * 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 type of event to listen for - * @param {Function} handler The handler function the event invokes This function is passed - * the following parameters: - * @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:
- *

See {@link Ext.Element#addListener} for examples of how to use these options.

- */ - addListener : function(element, eventName, fn, scope, options){ + /** + * 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 {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:
+ *

See {@link Ext.Element#addListener} for examples of how to use these options.

+ */ + addListener : function(element, eventName, fn, scope, options){ if(Ext.isObject(eventName)){ - var o = eventName, e, val; + var o = eventName, e, val; for(e in o){ - val = o[e]; - if(!propRe.test(e)){ - if(Ext.isFunction(val)){ - // shared options - listen(element, e, o, val, o.scope); - }else{ - // individual options - listen(element, e, val); - } + val = o[e]; + if(!propRe.test(e)){ + if(Ext.isFunction(val)){ + // shared options + listen(element, e, o, val, o.scope); + }else{ + // individual options + listen(element, e, val); + } } } } else { - listen(element, eventName, options, fn, scope); - } + listen(element, eventName, options, fn, scope); + } }, /** * 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 event - * @param {String} eventName The type of event - * @param {Function} fn The handler function to remove + * @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. */ removeListener : function(element, eventName, fn, scope){ var el = Ext.getDom(element), id = Ext.id(el), - wrap; - - Ext.each((elHash[id] || {})[eventName], function (v,i,a) { - if (Ext.isArray(v) && v[0] == fn && (!scope || v[2] == scope)) { - E.un(el, eventName, wrap = v[1]); - a.splice(i,1); - return false; - } - }); + wrap; + + Ext.each((elHash[id] || {})[eventName], function (v,i,a) { + if (Ext.isArray(v) && v[0] == fn && (!scope || v[2] == scope)) { + E.un(el, eventName, wrap = v[1]); + a.splice(i,1); + return false; + } + }); // jQuery workaround that should be removed from Ext Core - if(eventName == "mousewheel" && el.addEventListener && wrap){ - el.removeEventListener("DOMMouseScroll", wrap, false); - } - - if(eventName == "mousedown" && el == DOC && wrap){ // fix stopped mousedowns on the document - Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap); - } + if(eventName == "mousewheel" && el.addEventListener && wrap){ + el.removeEventListener("DOMMouseScroll", wrap, false); + } + + if(eventName == "mousedown" && el == DOC && wrap){ // fix stopped mousedowns on the document + Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap); + } }, /** * Removes all event handers from an element. Typically you will use {@link Ext.Element#removeAllListeners} * directly on an Element in favor of calling this version. - * @param {String/HTMLElement} el The id or html element from which to remove the event + * @param {String/HTMLElement} el The id or html element from which to remove all event handlers. */ removeAll : function(el){ - var id = Ext.id(el = Ext.getDom(el)), - es = elHash[id], - ename; - - for(ename in es){ - if(es.hasOwnProperty(ename)){ - Ext.each(es[ename], function(v) { - E.un(el, ename, v.wrap); - }); - } - } - elHash[id] = null; + var id = Ext.id(el = Ext.getDom(el)), + es = elHash[id], + ename; + + for(ename in es){ + if(es.hasOwnProperty(ename)){ + Ext.each(es[ename], function(v) { + E.un(el, ename, v.wrap); + }); + } + } + elHash[id] = null; }, /** - * Fires when the document is ready (before onload and before images are loaded). Can be + * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be * accessed shorthanded as Ext.onReady(). - * @param {Function} fn The method the event invokes - * @param {Object} scope (optional) An object that becomes the scope of the handler - * @param {boolean} options (optional) An object containing standard {@link #addListener} options + * @param {Function} fn The method the event invokes. + * @param {Object} scope (optional) The scope (this reference) in which the handler function executes. Defaults to the browser window. + * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options + * {single: true} be used so that the handler is removed on first invocation. */ onDocumentReady : function(fn, scope, options){ if(docReadyState){ // if it already fired @@ -2595,8 +2747,8 @@ Ext.EventManager = function(){ } else { if(!docReadyEvent) initDocReady(); options = options || {}; - options.delay = options.delay || 1; - docReadyEvent.addListener(fn, scope, options); + options.delay = options.delay || 1; + docReadyEvent.addListener(fn, scope, options); } }, @@ -2605,10 +2757,9 @@ Ext.EventManager = function(){ /** * 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 type of event to listen for - * @param {Function} handler The handler function the event invokes - * @param {Object} scope (optional) The scope in which to execute the handler - * function (the handler function's "this" context) + * @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 @@ -2616,10 +2767,11 @@ Ext.EventManager = function(){ pub.on = pub.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 event - * @param {String} eventName The type of event - * @param {Function} fn The handler function to remove - * @return {Boolean} True if a listener was actually removed, else false + * @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 */ @@ -2629,10 +2781,11 @@ Ext.EventManager = function(){ return pub; }(); /** - * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}. - * @param {Function} fn The method the event invokes - * @param {Object} scope An object that becomes the scope of the handler - * @param {boolean} options (optional) An object containing standard {@link #addListener} options + * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}. + * @param {Function} fn The method the event invokes. + * @param {Object} scope (optional) The scope (this reference) in which the handler function executes. Defaults to the browser window. + * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options + * {single: true} be used so that the handler is removed on first invocation. * @member Ext * @method onReady */ @@ -2707,21 +2860,21 @@ Ext.EventManager.addListener("myDiv", 'click', handleClick); */ Ext.EventObject = function(){ var E = Ext.lib.Event, - // safari keypress events for special keys return bad keycodes - safariKeys = { - 3 : 13, // enter - 63234 : 37, // left - 63235 : 39, // right - 63232 : 38, // up - 63233 : 40, // down - 63276 : 33, // page up - 63277 : 34, // page down - 63272 : 46, // delete - 63273 : 36, // home - 63275 : 35 // end - }, - // normalize button clicks - btnMap = Ext.isIE ? {1:0,4:1,2:2} : + // safari keypress events for special keys return bad keycodes + safariKeys = { + 3 : 13, // enter + 63234 : 37, // left + 63235 : 39, // right + 63232 : 38, // up + 63233 : 40, // down + 63276 : 33, // page up + 63277 : 34, // page down + 63272 : 46, // delete + 63273 : 36, // home + 63275 : 35 // end + }, + // normalize button clicks + btnMap = Ext.isIE ? {1:0,4:1,2:2} : (Ext.isWebKit ? {1:0,2:1,3:2} : {0:0,1:1,2:2}); Ext.EventObjectImpl = function(e){ @@ -2733,7 +2886,7 @@ Ext.EventObject = function(){ Ext.EventObjectImpl.prototype = { /** @private */ setEvent : function(e){ - var me = this; + var me = this; if(e == me || (e && e.browserEvent)){ // already wrapped return e; } @@ -2773,7 +2926,7 @@ Ext.EventObject = function(){ * Stop the event (preventDefault and stopPropagation) */ stopEvent : function(){ - var me = this; + var me = this; if(me.browserEvent){ if(me.browserEvent.type == 'mousedown'){ Ext.EventManager.stoppedMouseDownEvent.fire(me); @@ -2795,7 +2948,7 @@ Ext.EventObject = function(){ * Cancels bubbling of the event. */ stopPropagation : function(){ - var me = this; + var me = this; if(me.browserEvent){ if(me.browserEvent.type == 'mousedown'){ Ext.EventManager.stoppedMouseDownEvent.fire(me); @@ -2819,11 +2972,11 @@ Ext.EventObject = function(){ getKey : function(){ return this.normalizeKey(this.keyCode || this.charCode) }, - - // private - normalizeKey: function(k){ - return Ext.isSafari ? (safariKeys[k] || k) : k; - }, + + // private + normalizeKey: function(k){ + return Ext.isSafari ? (safariKeys[k] || k) : k; + }, /** * Gets the x coordinate of the event. @@ -2883,37 +3036,37 @@ Ext.EventObject = function(){ } return delta; }, - - /** - * Returns true if the target of this event is a child of el. Unless the allowEl parameter is set, it will return false if if the target is el. - * Example usage:

-		// Handle click on any child of an element
-		Ext.getBody().on('click', function(e){
-			if(e.within('some-el')){
-				alert('Clicked on a child of some-el!');
-			}
-		});
-		
-		// Handle click directly on an element, ignoring clicks on child nodes
-		Ext.getBody().on('click', function(e,t){
-			if((t.id == 'some-el') && !e.within(t, true)){
-				alert('Clicked directly on some-el!');
-			}
-		});
-		
- * @param {Mixed} el The id, DOM element or Ext.Element to check - * @param {Boolean} related (optional) true to test if the related target is within el instead of the target - * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target - * @return {Boolean} - */ - within : function(el, related, allowEl){ + + /** + * Returns true if the target of this event is a child of el. Unless the allowEl parameter is set, it will return false if if the target is el. + * Example usage:

+        // Handle click on any child of an element
+        Ext.getBody().on('click', function(e){
+            if(e.within('some-el')){
+                alert('Clicked on a child of some-el!');
+            }
+        });
+        
+        // Handle click directly on an element, ignoring clicks on child nodes
+        Ext.getBody().on('click', function(e,t){
+            if((t.id == 'some-el') && !e.within(t, true)){
+                alert('Clicked directly on some-el!');
+            }
+        });
+        
+ * @param {Mixed} el The id, DOM element or Ext.Element to check + * @param {Boolean} related (optional) true to test if the related target is within el instead of the target + * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target + * @return {Boolean} + */ + within : function(el, related, allowEl){ if(el){ - var t = this[related ? "getRelatedTarget" : "getTarget"](); - return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t)); + var t = this[related ? "getRelatedTarget" : "getTarget"](); + return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t)); } return false; - } - }; + } + }; return new Ext.EventObjectImpl(); }();/** @@ -2932,8 +3085,8 @@ Ext.apply(Ext.EventManager, function(){ // 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.isSafari ? - Ext.num(navigator.userAgent.toLowerCase().match(/version\/(\d+\.\d)/)[1] || 2) >= 3.1 : + useKeydown = Ext.isWebKit ? + Ext.num(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1]) >= 525 : !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera); return { @@ -3371,7 +3524,7 @@ El.prototype = { } } if(o.style){ - Ext.DomHelper.applyStyles(el, o.style); + DH.applyStyles(el, o.style); } return this; }, @@ -3384,6 +3537,13 @@ El.prototype = { * @param {HtmlElement} t The target of the event. * @param {Object} o The options configuration passed to the {@link #addListener} call. */ + /** + * @event contextmenu + * Fires when a right click is detected within the element. + * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event. + * @param {HtmlElement} t The target of the event. + * @param {Object} o The options configuration passed to the {@link #addListener} call. + */ /** * @event dblclick * Fires when a mouse double click is detected within the element. @@ -3683,11 +3843,11 @@ El.prototype = { /** * Appends an event handler to this element. The shorthand version {@link #on} is equivalent. - * @param {String} eventName The type of event to handle + * @param {String} eventName The name of event to handle. * @param {Function} fn The handler function the event invokes. This function is passed * the following parameters: @@ -3801,10 +3961,10 @@ el.removeListener('click', this.handlerFn); // or el.un('click', this.handlerFn);
- * @param {String} eventName the type of event to remove - * @param {Function} fn the method the event invokes - * @param {Object} scope (optional) The scope (The this reference) of the handler function. Defaults - * to this Element. + * @param {String} eventName The name of the event from which to remove the handler. + * @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. * @return {Ext.Element} this */ removeListener : function(eventName, fn, scope){ @@ -3868,16 +4028,19 @@ el.un('click', this.handlerFn); dom = me.dom; me.removeAllListeners(); - delete El.cache[dom.id]; - delete El.dataCache[dom.id] - Ext.removeNode(dom); + if (dom) { + delete me.dom; + delete El.cache[dom.id]; + delete El.dataCache[dom.id]; + Ext.removeNode(dom); + } }, /** * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element. * @param {Function} overFn The function to call when the mouse enters the Element. * @param {Function} outFn The function to call when the mouse leaves the Element. - * @param {Object} scope (optional) The scope (this reference) in which the functions are executed. Defaults to the Element's DOM element. + * @param {Object} scope (optional) The scope (this reference) in which the functions are executed. Defaults to the Element's DOM element. * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the options parameter}. * @return {Ext.Element} this */ @@ -3933,7 +4096,9 @@ el.un('click', this.handlerFn); * @return {Ext.Element} this */ update : function(html) { - this.dom.innerHTML = html; + if (this.dom) { + this.dom.innerHTML = html; + } return this; } }; @@ -3946,9 +4111,9 @@ El.addMethods = function(o){ /** * Appends an event handler (shorthand for {@link #addListener}). - * @param {String} eventName The type of event to handle - * @param {Function} fn The handler function the event invokes - * @param {Object} scope (optional) The scope (this element) of the handler function + * @param {String} eventName The name of event to handle. + * @param {Function} fn The handler function the event invokes. + * @param {Object} scope (optional) The scope (this reference) in which the handler function is executed. * @param {Object} options (optional) An object containing standard {@link #addListener} options * @member Ext.Element * @method on @@ -3957,10 +4122,10 @@ ep.on = ep.addListener; /** * Removes an event handler from this element (see {@link #removeListener} for additional notes). - * @param {String} eventName the type of event to remove - * @param {Function} fn the method the event invokes - * @param {Object} scope (optional) The scope (The this reference) of the handler function. Defaults - * to this Element. + * @param {String} eventName The name of the event from which to remove the handler. + * @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. * @return {Ext.Element} this * @member Ext.Element * @method un @@ -4053,7 +4218,7 @@ El.data = function(el, key, value){ if(arguments.length == 2){ return c[key]; }else{ - c[key] = value; + return (c[key] = value); } }; @@ -4907,10 +5072,7 @@ Ext.Element.addMethods( function() { var GETDOM = Ext.getDom, GET = Ext.get, - DH = Ext.DomHelper, - isEl = function(el){ - return (el.nodeType || el.dom || typeof el == 'string'); - }; + DH = Ext.DomHelper; return { /** @@ -4959,14 +5121,14 @@ function() { */ insertFirst: function(el, returnDom){ el = el || {}; - if(isEl(el)){ // element + if(el.nodeType || el.dom || typeof el == 'string'){ // element el = GETDOM(el); this.dom.insertBefore(el, this.dom.firstChild); return !returnDom ? GET(el) : el; }else{ // dh config return this.createChild(el, this.dom.firstChild, returnDom); } - }, + }, /** * Replaces the passed element with this element @@ -4988,7 +5150,7 @@ function() { replaceWith: function(el){ var me = this, Element = Ext.Element; - if(isEl(el)){ + if(el.nodeType || el.dom || typeof el == 'string'){ el = GETDOM(el); me.dom.parentNode.insertBefore(el, me.dom); }else{ @@ -5085,439 +5247,448 @@ Ext.apply(Ext.Element.prototype, function() { return rt; } }; -}());/** - * @class Ext.Element - */ -Ext.Element.addMethods(function(){ - // local style camelizing for speed - var propCache = {}, - camelRe = /(-[a-z])/gi, - classReCache = {}, - view = document.defaultView, - propFloat = Ext.isIE ? 'styleFloat' : 'cssFloat', - opacityRe = /alpha\(opacity=(.*)\)/i, - trimRe = /^\s+|\s+$/g, - EL = Ext.Element, - PADDING = "padding", - MARGIN = "margin", - BORDER = "border", - LEFT = "-left", - RIGHT = "-right", - TOP = "-top", - BOTTOM = "-bottom", - WIDTH = "-width", - MATH = Math, - HIDDEN = 'hidden', - ISCLIPPED = 'isClipped', - OVERFLOW = 'overflow', - OVERFLOWX = 'overflow-x', - OVERFLOWY = 'overflow-y', - ORIGINALCLIP = 'originalClip', - // special markup used throughout Ext when box wrapping elements - borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH}, - paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM}, - margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM}, - data = Ext.Element.data; - - - // private - function camelFn(m, a) { - return a.charAt(1).toUpperCase(); - } - - // private (needs to be called => addStyles.call(this, sides, styles)) - function addStyles(sides, styles){ - var val = 0; - - Ext.each(sides.match(/\w/g), function(s) { - if (s = parseInt(this.getStyle(styles[s]), 10)) { - val += MATH.abs(s); - } - }, - this); - return val; - } - - function chkCache(prop) { - return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : prop.replace(camelRe, camelFn)); - - } - - return { - // private ==> used by Fx - adjustWidth : function(width) { - var me = this; - var isNum = (typeof width == "number"); - if(isNum && me.autoBoxAdjust && !me.isBorderBox()){ - width -= (me.getBorderWidth("lr") + me.getPadding("lr")); - } - return (isNum && width < 0) ? 0 : width; - }, - - // private ==> used by Fx - adjustHeight : function(height) { - var me = this; - var isNum = (typeof height == "number"); - if(isNum && me.autoBoxAdjust && !me.isBorderBox()){ - height -= (me.getBorderWidth("tb") + me.getPadding("tb")); - } - return (isNum && height < 0) ? 0 : height; - }, - - - /** - * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out. - * @param {String/Array} className The CSS class to add, or an array of classes - * @return {Ext.Element} this - */ - addClass : function(className){ - var me = this; - Ext.each(className, function(v) { - me.dom.className += (!me.hasClass(v) && v ? " " + v : ""); - }); - return me; - }, - - /** - * Adds one or more CSS classes to this element and removes the same class(es) from all siblings. - * @param {String/Array} className The CSS class to add, or an array of classes - * @return {Ext.Element} this - */ - radioClass : function(className){ - Ext.each(this.dom.parentNode.childNodes, function(v) { - if(v.nodeType == 1) { - Ext.fly(v, '_internal').removeClass(className); - } - }); - return this.addClass(className); - }, - - /** - * Removes one or more CSS classes from the element. - * @param {String/Array} className The CSS class to remove, or an array of classes - * @return {Ext.Element} this - */ - removeClass : function(className){ - var me = this; - if (me.dom.className) { - Ext.each(className, function(v) { - me.dom.className = me.dom.className.replace( - classReCache[v] = classReCache[v] || new RegExp('(?:^|\\s+)' + v + '(?:\\s+|$)', "g"), - " "); - }); - } - return me; - }, - - /** - * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it). - * @param {String} className The CSS class to toggle - * @return {Ext.Element} this - */ - toggleClass : function(className){ - return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); - }, - - /** - * Checks if the specified CSS class exists on this element's DOM node. - * @param {String} className The CSS class to check for - * @return {Boolean} True if the class exists, else false - */ - hasClass : function(className){ - return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1; - }, - - /** - * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added. - * @param {String} oldClassName The CSS class to replace - * @param {String} newClassName The replacement CSS class - * @return {Ext.Element} this - */ - replaceClass : function(oldClassName, newClassName){ - return this.removeClass(oldClassName).addClass(newClassName); - }, - - isStyle : function(style, val) { - return this.getStyle(style) == val; - }, - - /** - * Normalizes currentStyle and computedStyle. - * @param {String} property The style property whose value is returned. - * @return {String} The current value of the style property for this element. - */ - getStyle : function(){ - return view && view.getComputedStyle ? - function(prop){ - var el = this.dom, - v, - cs; - if(el == document) return null; - prop = chkCache(prop); - return (v = el.style[prop]) ? v : - (cs = view.getComputedStyle(el, "")) ? cs[prop] : null; - } : - function(prop){ - var el = this.dom, - m, - cs; - - if(el == document) return null; - if (prop == 'opacity') { - if (el.style.filter.match) { - if(m = el.style.filter.match(opacityRe)){ - var fv = parseFloat(m[1]); - if(!isNaN(fv)){ - return fv ? fv / 100 : 0; - } - } - } - return 1; - } - prop = chkCache(prop); - return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null); - }; - }(), - - /** - * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values - * are convert to standard 6 digit hex color. - * @param {String} attr The css attribute - * @param {String} defaultValue The default value to use when a valid color isn't found - * @param {String} prefix (optional) defaults to #. Use an empty string when working with - * color anims. - */ - getColor : function(attr, defaultValue, prefix){ - var v = this.getStyle(attr), - color = prefix || '#', - h; - - if(!v || /transparent|inherit/.test(v)){ - return defaultValue; - } - if(/^r/.test(v)){ - Ext.each(v.slice(4, v.length -1).split(','), function(s){ - h = parseInt(s, 10); - color += (h < 16 ? '0' : '') + h.toString(16); - }); - }else{ - v = v.replace('#', ''); - color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v; - } - return(color.length > 5 ? color.toLowerCase() : defaultValue); - }, - - /** - * Wrapper for setting style properties, also takes single object parameter of multiple styles. - * @param {String/Object} property The style property to be set, or an object of multiple styles. - * @param {String} value (optional) The value to apply to the given property, or null if an object was passed. - * @return {Ext.Element} this - */ - setStyle : function(prop, value){ - var tmp, - style, - camel; - if (!Ext.isObject(prop)) { - tmp = {}; - tmp[prop] = value; - prop = tmp; - } - for (style in prop) { - value = prop[style]; - style == 'opacity' ? - this.setOpacity(value) : - this.dom.style[chkCache(style)] = value; - } - return this; - }, - - /** - * Set the opacity of the element - * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc - * @param {Boolean/Object} animate (optional) a standard Element animation config object or true for - * the default animation ({duration: .35, easing: 'easeIn'}) - * @return {Ext.Element} this - */ - setOpacity : function(opacity, animate){ - var me = this, - s = me.dom.style; - - if(!animate || !me.anim){ - if(Ext.isIE){ - var opac = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')' : '', - val = s.filter.replace(opacityRe, '').replace(trimRe, ''); - - s.zoom = 1; - s.filter = val + (val.length > 0 ? ' ' : '') + opac; - }else{ - s.opacity = opacity; - } - }else{ - me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn'); - } - return me; - }, - - /** - * Clears any opacity settings from this element. Required in some cases for IE. - * @return {Ext.Element} this - */ - clearOpacity : function(){ - var style = this.dom.style; - if(Ext.isIE){ - if(!Ext.isEmpty(style.filter)){ - style.filter = style.filter.replace(opacityRe, '').replace(trimRe, ''); - } - }else{ - style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = ''; - } - return this; - }, - - /** - * Returns the offset height of the element - * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding - * @return {Number} The element's height - */ - getHeight : function(contentHeight){ - var me = this, - dom = me.dom, - h = MATH.max(dom.offsetHeight, dom.clientHeight) || 0; - h = !contentHeight ? h : h - me.getBorderWidth("tb") - me.getPadding("tb"); - return h < 0 ? 0 : h; - }, - - /** - * Returns the offset width of the element - * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding - * @return {Number} The element's width - */ - getWidth : function(contentWidth){ - var me = this, - dom = me.dom, - w = MATH.max(dom.offsetWidth, dom.clientWidth) || 0; - w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr"); - return w < 0 ? 0 : w; - }, - - /** - * Set the width of this Element. - * @param {Mixed} width The new width. This may be one of:
- * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object - * @return {Ext.Element} this - */ - setWidth : function(width, animate){ - var me = this; - width = me.adjustWidth(width); - !animate || !me.anim ? - me.dom.style.width = me.addUnits(width) : - me.anim({width : {to : width}}, me.preanim(arguments, 1)); - return me; - }, - - /** - * Set the height of this Element. - *

-// change the height to 200px and animate with default configuration
-Ext.fly('elementId').setHeight(200, true);
-
-// change the height to 150px and animate with a custom configuration
-Ext.fly('elId').setHeight(150, {
-    duration : .5, // animation will have a duration of .5 seconds
-    // will change the content to "finished"
-    callback: function(){ this.{@link #update}("finished"); } 
-});
-         * 
- * @param {Mixed} height The new height. This may be one of:
- * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object - * @return {Ext.Element} this - */ - setHeight : function(height, animate){ - var me = this; - height = me.adjustHeight(height); - !animate || !me.anim ? - me.dom.style.height = me.addUnits(height) : - me.anim({height : {to : height}}, me.preanim(arguments, 1)); - return me; - }, - - /** - * Gets the width of the border(s) for the specified side(s) - * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example, - * passing 'lr' would get the border left width + the border right width. - * @return {Number} The width of the sides passed added together - */ - getBorderWidth : function(side){ - return addStyles.call(this, side, borders); - }, - - /** - * Gets the width of the padding(s) for the specified side(s) - * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example, - * passing 'lr' would get the padding left + the padding right. - * @return {Number} The padding of the sides passed added together - */ - getPadding : function(side){ - return addStyles.call(this, side, paddings); - }, - - /** - * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove - * @return {Ext.Element} this - */ - clip : function(){ - var me = this, - dom = me.dom; - - if(!data(dom, ISCLIPPED)){ - data(dom, ISCLIPPED, true); - data(dom, ORIGINALCLIP, { - o: me.getStyle(OVERFLOW), - x: me.getStyle(OVERFLOWX), - y: me.getStyle(OVERFLOWY) - }); - me.setStyle(OVERFLOW, HIDDEN); - me.setStyle(OVERFLOWX, HIDDEN); - me.setStyle(OVERFLOWY, HIDDEN); - } - return me; - }, - - /** - * Return clipping (overflow) to original clipping before {@link #clip} was called - * @return {Ext.Element} this - */ - unclip : function(){ - var me = this, - dom = me.dom; - - if(data(dom, ISCLIPPED)){ - data(dom, ISCLIPPED, false); - var o = data(dom, ORIGINALCLIP); - if(o.o){ - me.setStyle(OVERFLOW, o.o); - } - if(o.x){ - me.setStyle(OVERFLOWX, o.x); - } - if(o.y){ - me.setStyle(OVERFLOWY, o.y); - } - } - return me; - }, - - addStyles : addStyles, - margins : margins - } -}() -);/** +}());/** + * @class Ext.Element + */ +Ext.Element.addMethods(function(){ + // local style camelizing for speed + var propCache = {}, + camelRe = /(-[a-z])/gi, + classReCache = {}, + view = document.defaultView, + propFloat = Ext.isIE ? 'styleFloat' : 'cssFloat', + opacityRe = /alpha\(opacity=(.*)\)/i, + trimRe = /^\s+|\s+$/g, + EL = Ext.Element, + PADDING = "padding", + MARGIN = "margin", + BORDER = "border", + LEFT = "-left", + RIGHT = "-right", + TOP = "-top", + BOTTOM = "-bottom", + WIDTH = "-width", + MATH = Math, + HIDDEN = 'hidden', + ISCLIPPED = 'isClipped', + OVERFLOW = 'overflow', + OVERFLOWX = 'overflow-x', + OVERFLOWY = 'overflow-y', + ORIGINALCLIP = 'originalClip', + // special markup used throughout Ext when box wrapping elements + borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH}, + paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM}, + margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM}, + data = Ext.Element.data; + + + // private + function camelFn(m, a) { + return a.charAt(1).toUpperCase(); + } + + function chkCache(prop) { + return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : prop.replace(camelRe, camelFn)); + } + + return { + // private ==> used by Fx + adjustWidth : function(width) { + var me = this; + var isNum = Ext.isNumber(width); + if(isNum && me.autoBoxAdjust && !me.isBorderBox()){ + width -= (me.getBorderWidth("lr") + me.getPadding("lr")); + } + return (isNum && width < 0) ? 0 : width; + }, + + // private ==> used by Fx + adjustHeight : function(height) { + var me = this; + var isNum = Ext.isNumber(height); + if(isNum && me.autoBoxAdjust && !me.isBorderBox()){ + height -= (me.getBorderWidth("tb") + me.getPadding("tb")); + } + return (isNum && height < 0) ? 0 : height; + }, + + + /** + * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out. + * @param {String/Array} className The CSS class to add, or an array of classes + * @return {Ext.Element} this + */ + addClass : function(className){ + var me = this; + Ext.each(className, function(v) { + me.dom.className += (!me.hasClass(v) && v ? " " + v : ""); + }); + return me; + }, + + /** + * Adds one or more CSS classes to this element and removes the same class(es) from all siblings. + * @param {String/Array} className The CSS class to add, or an array of classes + * @return {Ext.Element} this + */ + radioClass : function(className){ + Ext.each(this.dom.parentNode.childNodes, function(v) { + if(v.nodeType == 1) { + Ext.fly(v, '_internal').removeClass(className); + } + }); + return this.addClass(className); + }, + + /** + * Removes one or more CSS classes from the element. + * @param {String/Array} className The CSS class to remove, or an array of classes + * @return {Ext.Element} this + */ + removeClass : function(className){ + var me = this; + if (me.dom && me.dom.className) { + Ext.each(className, function(v) { + me.dom.className = me.dom.className.replace( + classReCache[v] = classReCache[v] || new RegExp('(?:^|\\s+)' + v + '(?:\\s+|$)', "g"), + " "); + }); + } + return me; + }, + + /** + * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it). + * @param {String} className The CSS class to toggle + * @return {Ext.Element} this + */ + toggleClass : function(className){ + return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); + }, + + /** + * Checks if the specified CSS class exists on this element's DOM node. + * @param {String} className The CSS class to check for + * @return {Boolean} True if the class exists, else false + */ + hasClass : function(className){ + return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1; + }, + + /** + * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added. + * @param {String} oldClassName The CSS class to replace + * @param {String} newClassName The replacement CSS class + * @return {Ext.Element} this + */ + replaceClass : function(oldClassName, newClassName){ + return this.removeClass(oldClassName).addClass(newClassName); + }, + + isStyle : function(style, val) { + return this.getStyle(style) == val; + }, + + /** + * Normalizes currentStyle and computedStyle. + * @param {String} property The style property whose value is returned. + * @return {String} The current value of the style property for this element. + */ + getStyle : function(){ + return view && view.getComputedStyle ? + function(prop){ + var el = this.dom, + v, + cs, + out; + if(el == document) return null; + prop = chkCache(prop); + out = (v = el.style[prop]) ? v : + (cs = view.getComputedStyle(el, "")) ? cs[prop] : null; + + // Webkit returns rgb values for transparent. + if(Ext.isWebKit && out == 'rgba(0, 0, 0, 0)'){ + out = 'transparent'; + } + return out; + } : + function(prop){ + var el = this.dom, + m, + cs; + + if(el == document) return null; + if (prop == 'opacity') { + if (el.style.filter.match) { + if(m = el.style.filter.match(opacityRe)){ + var fv = parseFloat(m[1]); + if(!isNaN(fv)){ + return fv ? fv / 100 : 0; + } + } + } + return 1; + } + prop = chkCache(prop); + return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null); + }; + }(), + + /** + * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values + * are convert to standard 6 digit hex color. + * @param {String} attr The css attribute + * @param {String} defaultValue The default value to use when a valid color isn't found + * @param {String} prefix (optional) defaults to #. Use an empty string when working with + * color anims. + */ + getColor : function(attr, defaultValue, prefix){ + var v = this.getStyle(attr), + color = Ext.isDefined(prefix) ? prefix : '#', + h; + + if(!v || /transparent|inherit/.test(v)){ + return defaultValue; + } + if(/^r/.test(v)){ + Ext.each(v.slice(4, v.length -1).split(','), function(s){ + h = parseInt(s, 10); + color += (h < 16 ? '0' : '') + h.toString(16); + }); + }else{ + v = v.replace('#', ''); + color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v; + } + return(color.length > 5 ? color.toLowerCase() : defaultValue); + }, + + /** + * Wrapper for setting style properties, also takes single object parameter of multiple styles. + * @param {String/Object} property The style property to be set, or an object of multiple styles. + * @param {String} value (optional) The value to apply to the given property, or null if an object was passed. + * @return {Ext.Element} this + */ + setStyle : function(prop, value){ + var tmp, + style, + camel; + if (!Ext.isObject(prop)) { + tmp = {}; + tmp[prop] = value; + prop = tmp; + } + for (style in prop) { + value = prop[style]; + style == 'opacity' ? + this.setOpacity(value) : + this.dom.style[chkCache(style)] = value; + } + return this; + }, + + /** + * Set the opacity of the element + * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc + * @param {Boolean/Object} animate (optional) a standard Element animation config object or true for + * the default animation ({duration: .35, easing: 'easeIn'}) + * @return {Ext.Element} this + */ + setOpacity : function(opacity, animate){ + var me = this, + s = me.dom.style; + + if(!animate || !me.anim){ + if(Ext.isIE){ + var opac = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')' : '', + val = s.filter.replace(opacityRe, '').replace(trimRe, ''); + + s.zoom = 1; + s.filter = val + (val.length > 0 ? ' ' : '') + opac; + }else{ + s.opacity = opacity; + } + }else{ + me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn'); + } + return me; + }, + + /** + * Clears any opacity settings from this element. Required in some cases for IE. + * @return {Ext.Element} this + */ + clearOpacity : function(){ + var style = this.dom.style; + if(Ext.isIE){ + if(!Ext.isEmpty(style.filter)){ + style.filter = style.filter.replace(opacityRe, '').replace(trimRe, ''); + } + }else{ + style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = ''; + } + return this; + }, + + /** + * Returns the offset height of the element + * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding + * @return {Number} The element's height + */ + getHeight : function(contentHeight){ + var me = this, + dom = me.dom, + hidden = Ext.isIE && me.isStyle('display', 'none'), + h = MATH.max(dom.offsetHeight, hidden ? 0 : dom.clientHeight) || 0; + + h = !contentHeight ? h : h - me.getBorderWidth("tb") - me.getPadding("tb"); + return h < 0 ? 0 : h; + }, + + /** + * Returns the offset width of the element + * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding + * @return {Number} The element's width + */ + getWidth : function(contentWidth){ + var me = this, + dom = me.dom, + hidden = Ext.isIE && me.isStyle('display', 'none'), + w = MATH.max(dom.offsetWidth, hidden ? 0 : dom.clientWidth) || 0; + w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr"); + return w < 0 ? 0 : w; + }, + + /** + * Set the width of this Element. + * @param {Mixed} width The new width. This may be one of:
+ * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object + * @return {Ext.Element} this + */ + setWidth : function(width, animate){ + var me = this; + width = me.adjustWidth(width); + !animate || !me.anim ? + me.dom.style.width = me.addUnits(width) : + me.anim({width : {to : width}}, me.preanim(arguments, 1)); + return me; + }, + + /** + * Set the height of this Element. + *

+// change the height to 200px and animate with default configuration
+Ext.fly('elementId').setHeight(200, true);
+
+// change the height to 150px and animate with a custom configuration
+Ext.fly('elId').setHeight(150, {
+    duration : .5, // animation will have a duration of .5 seconds
+    // will change the content to "finished"
+    callback: function(){ this.{@link #update}("finished"); } 
+});
+         * 
+ * @param {Mixed} height The new height. This may be one of:
+ * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object + * @return {Ext.Element} this + */ + setHeight : function(height, animate){ + var me = this; + height = me.adjustHeight(height); + !animate || !me.anim ? + me.dom.style.height = me.addUnits(height) : + me.anim({height : {to : height}}, me.preanim(arguments, 1)); + return me; + }, + + /** + * Gets the width of the border(s) for the specified side(s) + * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example, + * passing 'lr' would get the border left width + the border right width. + * @return {Number} The width of the sides passed added together + */ + getBorderWidth : function(side){ + return this.addStyles(side, borders); + }, + + /** + * Gets the width of the padding(s) for the specified side(s) + * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example, + * passing 'lr' would get the padding left + the padding right. + * @return {Number} The padding of the sides passed added together + */ + getPadding : function(side){ + return this.addStyles(side, paddings); + }, + + /** + * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove + * @return {Ext.Element} this + */ + clip : function(){ + var me = this, + dom = me.dom; + + if(!data(dom, ISCLIPPED)){ + data(dom, ISCLIPPED, true); + data(dom, ORIGINALCLIP, { + o: me.getStyle(OVERFLOW), + x: me.getStyle(OVERFLOWX), + y: me.getStyle(OVERFLOWY) + }); + me.setStyle(OVERFLOW, HIDDEN); + me.setStyle(OVERFLOWX, HIDDEN); + me.setStyle(OVERFLOWY, HIDDEN); + } + return me; + }, + + /** + * Return clipping (overflow) to original clipping before {@link #clip} was called + * @return {Ext.Element} this + */ + unclip : function(){ + var me = this, + dom = me.dom; + + if(data(dom, ISCLIPPED)){ + data(dom, ISCLIPPED, false); + var o = data(dom, ORIGINALCLIP); + if(o.o){ + me.setStyle(OVERFLOW, o.o); + } + if(o.x){ + me.setStyle(OVERFLOWX, o.x); + } + if(o.y){ + me.setStyle(OVERFLOWY, o.y); + } + } + return me; + }, + + // private + addStyles : function(sides, styles){ + var val = 0; + + Ext.each(sides.match(/\w/g), function(s) { + if (s = parseInt(this.getStyle(styles[s]), 10)) { + val += MATH.abs(s); + } + }, + this); + return val; + }, + + margins : margins + } +}() +); +/** * @class Ext.Element */ @@ -5843,10 +6014,6 @@ var D = Ext.lib.Dom, AUTO = "auto", ZINDEX = "z-index"; -function animTest(args, animate, i) { - return this.preanim && !!animate ? this.preanim(args, i) : false -} - Ext.Element.addMethods({ /** * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). @@ -5890,7 +6057,7 @@ Ext.Element.addMethods({ * @return {Ext.Element} this */ setX : function(x, animate){ - return this.setXY([x, this.getY()], animTest.call(this, arguments, animate, 1)); + return this.setXY([x, this.getY()], this.animTest(arguments, animate, 1)); }, /** @@ -5900,7 +6067,7 @@ Ext.Element.addMethods({ * @return {Ext.Element} this */ setY : function(y, animate){ - return this.setXY([this.getX(), y], animTest.call(this, arguments, animate, 1)); + return this.setXY([this.getX(), y], this.animTest(arguments, animate, 1)); }, /** @@ -5969,7 +6136,7 @@ Ext.Element.addMethods({ * @return {Ext.Element} this */ setLocation : function(x, y, animate){ - return this.setXY([x, y], animTest.call(this, arguments, animate, 2)); + return this.setXY([x, y], this.animTest(arguments, animate, 2)); }, /** @@ -5981,7 +6148,7 @@ Ext.Element.addMethods({ * @return {Ext.Element} this */ moveTo : function(x, y, animate){ - return this.setXY([x, y], animTest.call(this, arguments, animate, 2)); + return this.setXY([x, y], this.animTest(arguments, animate, 2)); }, /** @@ -6122,7 +6289,9 @@ Ext.Element.addMethods({ return {left: (x - o[0] + l), top: (y - o[1] + t)}; }, - animTest : animTest + animTest : function(args, animate, i) { + return !!animate && this.preanim ? this.preanim(args, i) : false; + } }); })();/** * @class Ext.Element @@ -6345,15 +6514,15 @@ Ext.Element.addMethods({ * @return {Element} this */ scrollTo : function(side, value, animate){ - var tester = /top/i, - prop = "scroll" + (tester.test(side) ? "Top" : "Left"), - me = this, - dom = me.dom; + var top = /top/i.test(side), //check if we're scrolling top or left + prop = 'scroll' + (top ? 'Left' : 'Top'), // if scrolling top, we need to grab scrollLeft, if left, scrollTop + me = this, + dom = me.dom; if (!animate || !me.anim) { dom[prop] = value; } else { - me.anim({scroll: {to: tester.test(prop) ? [dom[prop], value] : [value, dom[prop]]}}, - me.preanim(arguments, 2), 'scroll'); + me.anim({scroll: {to: top ? [dom[prop], value] : [value, dom[prop]]}}, + me.preanim(arguments, 2), 'scroll'); } return me; }, @@ -6487,7 +6656,7 @@ Ext.Element.addMethods(function(){ /** * Sets the element's visibility mode. When setVisible() is called it * will use this to determine whether to set the visibility or the display property. - * @param visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY + * @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY * @return {Ext.Element} this */ setVisibilityMode : function(visMode){ @@ -6890,9 +7059,7 @@ function(){ shim; el.frameBorder = '0'; el.className = 'ext-shim'; - if(Ext.isIE && Ext.isSecure){ - el.src = Ext.SSL_SECURE_URL; - } + el.src = Ext.SSL_SECURE_URL; shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom)); shim.autoBoxAdjust = false; return shim; @@ -7031,7 +7198,7 @@ br The bottom right corner * The callback is intended for any additional code that should run once a particular effect has completed. The Element * being operated upon is passed as the first parameter. * - * @cfg {Object} scope The scope of the {@link #callback} function + * @cfg {Object} scope The scope (this reference) in which the {@link #callback} function is executed. Defaults to the browser window. * * @cfg {String} easing A valid Ext.lib.Easing value for the effect:

+ * + * + * + *
  • Conditional processing with basic comparison operators + *
    + *

    The tpl tag and the if operator are used + * to provide conditional checks for deciding whether or not to render specific + * parts of the template. Notes:

      + *
    • Double quotes must be encoded if used within the conditional
    • + *
    • There is no else operator — if needed, two opposite + * if statements should be used.
    • + *
    + *
    
    +<tpl if="age > 1 && age < 10">Child</tpl>
    +<tpl if="age >= 10 && age < 18">Teenager</tpl>
    +<tpl if="this.isGirl(name)">...</tpl>
    +<tpl if="id==\'download\'">...</tpl>
    +<tpl if="needsIcon"><img src="{icon}" class="{iconCls}"/></tpl>
    +// no good:
    +<tpl if="name == "Jack"">Hello</tpl>
    +// encode " if it is part of the condition, e.g.
    +<tpl if="name == &quot;Jack&quot;">Hello</tpl>
    + * 
    + * Using the sample data above: *
    
     var tpl = new Ext.XTemplate(
         '<p>Name: {name}</p>',
         '<p>Kids: ',
         '<tpl for="kids">',
    -        '<tpl if="age &gt; 1">',  // <-- Note that the > is encoded
    -            '<p>{#}: {name}</p>',  // <-- Auto-number each item
    -            '<p>In 5 Years: {age+5}</p>',  // <-- Basic math
    -            '<p>Dad: {parent.name}</p>',
    +        '<tpl if="age > 1">',
    +            '<p>{name}</p>',
             '</tpl>',
         '</tpl></p>'
     );
     tpl.overwrite(panel.body, data);
    -
    - *

    Auto-rendering of flat arrays
    Flat arrays that contain values (and not objects) can be auto-rendered - * using the special {.} variable inside a loop. This variable will represent the value of - * the array at the current index:

    - *
    
    -var tpl = new Ext.XTemplate(
    -    '<p>{name}\'s favorite beverages:</p>',
    -    '<tpl for="drinks">',
    -       '<div> - {.}</div>',
    -    '</tpl>'
    -);
    -tpl.overwrite(panel.body, data);
    -
    - *

    Basic conditional logic
    Using the tpl tag and the if - * operator you can provide conditional checks for deciding whether or not to render specific parts of the template. - * Note that there is no else operator — if needed, you should use two opposite if statements. - * Properly-encoded attributes are required as seen in the following example:

    + * + *
    + *
  • + * + * + *
  • Basic math support + *
    + *

    The following basic math operators may be applied directly on numeric + * data values:

    + * + - * /
    + * 
    + * For example: *
    
     var tpl = new Ext.XTemplate(
         '<p>Name: {name}</p>',
         '<p>Kids: ',
         '<tpl for="kids">',
             '<tpl if="age &gt; 1">',  // <-- Note that the > is encoded
    -            '<p>{name}</p>',
    +            '<p>{#}: {name}</p>',  // <-- Auto-number each item
    +            '<p>In 5 Years: {age+5}</p>',  // <-- Basic math
    +            '<p>Dad: {parent.name}</p>',
             '</tpl>',
         '</tpl></p>'
     );
     tpl.overwrite(panel.body, data);
     
    - *

    Ability to execute arbitrary inline code
    In an XTemplate, anything between {[ ... ]} is considered - * code to be executed in the scope of the template. There are some special variables available in that code: + *

    + *
  • + * + * + *
  • Execute arbitrary inline code with special built-in template variables + *
    + *

    Anything between {[ ... ]} is considered code to be executed + * in the scope of the template. There are some special variables available in that code: *

    - * This example demonstrates basic row striping using an inline code block and the xindex variable:

    + * This example demonstrates basic row striping using an inline code block and the + * xindex variable:

    *
    
     var tpl = new Ext.XTemplate(
         '<p>Name: {name}</p>',
    @@ -12159,8 +12493,13 @@ var tpl = new Ext.XTemplate(
         '</tpl></p>'
     );
     tpl.overwrite(panel.body, data);
    -
    - *

    Template member functions
    One or more member functions can be defined directly on the config + * + *

    + *
  • + * + *
  • Template member functions + *
    + *

    One or more member functions can be specified in a configuration * object passed into the XTemplate constructor for more complex processing:

    *
    
     var tpl = new Ext.XTemplate(
    @@ -12170,25 +12509,35 @@ var tpl = new Ext.XTemplate(
             '<tpl if="this.isGirl(name)">',
                 '<p>Girl: {name} - {age}</p>',
             '</tpl>',
    +        // use opposite if statement to simulate 'else' processing:
             '<tpl if="this.isGirl(name) == false">',
                 '<p>Boy: {name} - {age}</p>',
             '</tpl>',
             '<tpl if="this.isBaby(age)">',
                 '<p>{name} is a baby!</p>',
             '</tpl>',
    -    '</tpl></p>', {
    -     isGirl: function(name){
    -         return name == 'Sara Grace';
    -     },
    -     isBaby: function(age){
    -        return age < 1;
    -     }
    -});
    +    '</tpl></p>',
    +    {
    +        // XTemplate configuration:
    +        compiled: true,
    +        disableFormats: true,
    +        // member functions:
    +        isGirl: function(name){
    +            return name == 'Sara Grace';
    +        },
    +        isBaby: function(age){
    +            return age < 1;
    +        }
    +    }
    +);
     tpl.overwrite(panel.body, data);
    -
    - * @constructor - * @param {String/Array/Object} parts The HTML fragment or an array of fragments to join(""), or multiple arguments - * to join("") that can also include a config object + * + *
    + *
  • + * + * + * + * @param {Mixed} config */ Ext.XTemplate = function(){ Ext.XTemplate.superclass.constructor.apply(this, arguments); @@ -12323,7 +12672,8 @@ Ext.extend(Ext.XTemplate, Ext.Template, { } function codeFn(m, code){ - return "'"+ sep +'('+code+')'+sep+"'"; + // Single quotes get escaped when the template is compiled, however we want to undo this when running code. + return "'" + sep + '(' + code.replace(/\\'/g, "'") + ')' + sep + "'"; } // branched to use + in gecko and [].join() in others @@ -12476,7 +12826,7 @@ Ext.util.CSS = function(){ try{// try catch for cross domain access issue var ssRules = ss.cssRules || ss.rules; for(var j = ssRules.length-1; j >= 0; --j){ - rules[ssRules[j].selectorText] = ssRules[j]; + rules[ssRules[j].selectorText.toLowerCase()] = ssRules[j]; } }catch(e){} }, @@ -12508,11 +12858,11 @@ Ext.util.CSS = function(){ getRule : function(selector, refreshCache){ var rs = this.getRules(refreshCache); if(!Ext.isArray(selector)){ - return rs[selector]; + return rs[selector.toLowerCase()]; } for(var i = 0; i < selector.length; i++){ if(rs[selector[i]]){ - return rs[selector[i]]; + return rs[selector[i].toLowerCase()]; } } return null; @@ -12791,15 +13141,6 @@ Ext.KeyNav.prototype = { */ forceKeyDown : false, - // private - prepareEvent : function(e){ - var k = e.getKey(); - var h = this.keyToHandler[k]; - if(Ext.isSafari2 && h && k >= 37 && k <= 40){ - e.stopEvent(); - } - }, - // private relay : function(e){ var k = e.getKey(); @@ -12845,38 +13186,46 @@ Ext.KeyNav.prototype = { 27 : "esc", 9 : "tab" }, + + stopKeyUp: function(e) { + var k = e.getKey(); + + if (k >= 37 && k <= 40) { + // *** bugfix - safari 2.x fires 2 keyup events on cursor keys + // *** (note: this bugfix sacrifices the "keyup" event originating from keyNav elements in Safari 2) + e.stopEvent(); + } + }, /** * Enable this KeyNav */ - enable: function(){ - if(this.disabled){ - // ie won't do special keys on keypress, no one else will repeat keys with keydown - // the EventObject will normalize Safari automatically - if(this.isKeydown()){ - this.el.on("keydown", this.relay, this); - }else{ - this.el.on("keydown", this.prepareEvent, this); - this.el.on("keypress", this.relay, this); + enable: function() { + if (this.disabled) { + if (Ext.isSafari2) { + // call stopKeyUp() on "keyup" event + this.el.on('keyup', this.stopKeyUp, this); } - this.disabled = false; - } - }, + + this.el.on(this.isKeydown()? 'keydown' : 'keypress', this.relay, this); + this.disabled = false; + } + }, /** * Disable this KeyNav */ - disable: function(){ - if(!this.disabled){ - if(this.isKeydown()){ - this.el.un("keydown", this.relay, this); - }else{ - this.el.un("keydown", this.prepareEvent, this); - this.el.un("keypress", this.relay, this); + disable: function() { + if (!this.disabled) { + if (Ext.isSafari2) { + // remove "keyup" event handler + this.el.un('keyup', this.stopKeyUp, this); } - this.disabled = true; - } - }, + + this.el.un(this.isKeydown()? 'keydown' : 'keypress', this.relay, this); + this.disabled = true; + } + }, /** * Convenience function for setting disabled/enabled by boolean. @@ -13261,8 +13610,8 @@ Ext.util.Cookies = { * Create a cookie with the specified name and value. Additional settings * for the cookie may be optionally specified (for example: expiration, * access restriction, SSL). - * @param {Object} name - * @param {Object} value + * @param {String} name The name of the cookie to set. + * @param {Mixed} value The value to set for the cookie. * @param {Object} expires (Optional) Specify an expiration date the * cookie is to persist until. Note that the specified Date object will * be converted to Greenwich Mean Time (GMT). @@ -13297,7 +13646,7 @@ Ext.util.Cookies = { *
    
          * var validStatus = Ext.util.Cookies.get("valid");
          * 
    - * @param {Object} name The name of the cookie to get + * @param {String} name The name of the cookie to get * @return {Mixed} Returns the cookie value for the specified name; * null if the cookie name does not exist. */ @@ -13322,8 +13671,8 @@ Ext.util.Cookies = { /** * Removes a cookie with the provided name from the browser - * if found. - * @param {Object} name The name of the cookie to remove + * if found by setting its expiration date to sometime in the past. + * @param {String} name The name of the cookie to remove */ clear : function(name){ if(Ext.util.Cookies.get(name)){