3 * Copyright(c) 2006-2009 Ext JS, LLC
5 * http://www.extjs.com/license
8 * @class Ext.DomHelper
\r
9 * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
\r
10 * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
\r
11 * from your DOM building code.</p>
\r
13 * <p><b><u>DomHelper element specification object</u></b></p>
\r
14 * <p>A specification object is used when creating elements. Attributes of this object
\r
15 * are assumed to be element attributes, except for 4 special attributes:
\r
16 * <div class="mdetail-params"><ul>
\r
17 * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
\r
18 * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
\r
19 * same kind of element definition objects to be created and appended. These can be nested
\r
20 * as deep as you want.</div></li>
\r
21 * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
\r
22 * This will end up being either the "class" attribute on a HTML fragment or className
\r
23 * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
\r
24 * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
\r
27 * <p><b><u>Insertion methods</u></b></p>
\r
28 * <p>Commonly used insertion methods:
\r
29 * <div class="mdetail-params"><ul>
\r
30 * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>
\r
31 * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>
\r
32 * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>
\r
33 * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>
\r
34 * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>
\r
35 * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>
\r
38 * <p><b><u>Example</u></b></p>
\r
39 * <p>This is an example, where an unordered list with 3 children items is appended to an existing
\r
40 * element with id <tt>'my-div'</tt>:<br>
\r
42 var dh = Ext.DomHelper; // create shorthand alias
\r
43 // specification object
\r
48 // append children after creating
\r
49 children: [ // may also specify 'cn' instead of 'children'
\r
50 {tag: 'li', id: 'item0', html: 'List Item 0'},
\r
51 {tag: 'li', id: 'item1', html: 'List Item 1'},
\r
52 {tag: 'li', id: 'item2', html: 'List Item 2'}
\r
55 var list = dh.append(
\r
56 'my-div', // the context element 'my-div' can either be the id or the actual node
\r
57 spec // the specification object
\r
60 * <p>Element creation specification parameters in this class may also be passed as an Array of
\r
61 * specification objects. This can be used to insert multiple sibling nodes into an existing
\r
62 * container very efficiently. For example, to add more list items to the example above:<pre><code>
\r
63 dh.append('my-ul', [
\r
64 {tag: 'li', id: 'item3', html: 'List Item 3'},
\r
65 {tag: 'li', id: 'item4', html: 'List Item 4'}
\r
69 * <p><b><u>Templating</u></b></p>
\r
70 * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
\r
71 * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
\r
72 * insert new elements. Revisiting the example above, we could utilize templating this time:
\r
75 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
\r
77 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
\r
79 for(var i = 0; i < 5, i++){
\r
80 tpl.append(list, [i]); // use template to append to the actual node
\r
83 * <p>An example using a template:<pre><code>
\r
84 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
\r
86 var tpl = new Ext.DomHelper.createTemplate(html);
\r
87 tpl.append('blog-roll', ['link1', 'http://www.jackslocum.com/', "Jack's Site"]);
\r
88 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin's Site"]);
\r
91 * <p>The same example using named parameters:<pre><code>
\r
92 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
\r
94 var tpl = new Ext.DomHelper.createTemplate(html);
\r
95 tpl.append('blog-roll', {
\r
97 url: 'http://www.jackslocum.com/',
\r
98 text: "Jack's Site"
\r
100 tpl.append('blog-roll', {
\r
102 url: 'http://www.dustindiaz.com/',
\r
103 text: "Dustin's Site"
\r
105 * </code></pre></p>
\r
107 * <p><b><u>Compiling Templates</u></b></p>
\r
108 * <p>Templates are applied using regular expressions. The performance is great, but if
\r
109 * you are adding a bunch of DOM elements using the same template, you can increase
\r
110 * performance even further by {@link Ext.Template#compile "compiling"} the template.
\r
111 * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
\r
112 * broken up at the different variable points and a dynamic function is created and eval'ed.
\r
113 * The generated function performs string concatenation of these parts and the passed
\r
114 * variables instead of using regular expressions.
\r
116 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
\r
118 var tpl = new Ext.DomHelper.createTemplate(html);
\r
121 //... use template like normal
\r
122 * </code></pre></p>
\r
124 * <p><b><u>Performance Boost</u></b></p>
\r
125 * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
\r
126 * of DOM can significantly boost performance.</p>
\r
127 * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
\r
128 * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
\r
129 * results in the creation of a text node. Usage:</p>
\r
131 Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
\r
135 Ext.DomHelper = function(){
\r
136 var tempTableEl = null,
\r
137 emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
\r
138 tableRe = /^table|tbody|tr|td$/i,
\r
140 // kill repeat to save bytes
\r
141 afterbegin = 'afterbegin',
\r
142 afterend = 'afterend',
\r
143 beforebegin = 'beforebegin',
\r
144 beforeend = 'beforeend',
\r
147 tbs = ts+'<tbody>',
\r
148 tbe = '</tbody>'+te,
\r
149 trs = tbs + '<tr>',
\r
153 function doInsert(el, o, returnElement, pos, sibling, append){
\r
154 var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));
\r
155 return returnElement ? Ext.get(newNode, true) : newNode;
\r
158 // build as innerHTML where available
\r
159 function createHtml(o){
\r
167 if(Ext.isString(o)){
\r
169 } else if (Ext.isArray(o)) {
\r
170 Ext.each(o, function(v) {
\r
171 b += createHtml(v);
\r
174 b += '<' + (o.tag = o.tag || 'div');
\r
175 Ext.iterate(o, function(attr, val){
\r
176 if(!/tag|children|cn|html$/i.test(attr)){
\r
177 if (Ext.isObject(val)) {
\r
178 b += ' ' + attr + '="';
\r
179 Ext.iterate(val, function(key, keyVal){
\r
180 b += key + ':' + keyVal + ';';
\r
184 b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
\r
188 // Now either just close the tag or try to add children and close the tag.
\r
189 if (emptyTags.test(o.tag)) {
\r
193 if ((cn = o.children || o.cn)) {
\r
194 b += createHtml(cn);
\r
198 b += '</' + o.tag + '>';
\r
204 function ieTable(depth, s, h, e){
\r
205 tempTableEl.innerHTML = [s, h, e].join('');
\r
209 while(++i < depth){
\r
210 el = el.firstChild;
\r
212 // If the result is multiple siblings, then encapsulate them into one fragment.
\r
213 if(ns = el.nextSibling){
\r
214 var df = document.createDocumentFragment();
\r
216 ns = el.nextSibling;
\r
217 df.appendChild(el);
\r
227 * Nasty code for IE's broken table implementation
\r
229 function insertIntoTable(tag, where, el, html) {
\r
233 tempTableEl = tempTableEl || document.createElement('div');
\r
235 if(tag == 'td' && (where == afterbegin || where == beforeend) ||
\r
236 !/td|tr|tbody/i.test(tag) && (where == beforebegin || where == afterend)) {
\r
239 before = where == beforebegin ? el :
\r
240 where == afterend ? el.nextSibling :
\r
241 where == afterbegin ? el.firstChild : null;
\r
243 if (where == beforebegin || where == afterend) {
\r
244 el = el.parentNode;
\r
247 if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
\r
248 node = ieTable(4, trs, html, tre);
\r
249 } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
\r
250 (tag == 'tr' && (where == beforebegin || where == afterend))) {
\r
251 node = ieTable(3, tbs, html, tbe);
\r
253 node = ieTable(2, ts, html, te);
\r
255 el.insertBefore(node, before);
\r
262 * Returns the markup for the passed Element(s) config.
\r
263 * @param {Object} o The DOM object spec (and children)
\r
266 markup : function(o){
\r
267 return createHtml(o);
\r
271 * Applies a style specification to an element.
\r
272 * @param {String/HTMLElement} el The element to apply styles to
\r
273 * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
\r
274 * a function which returns such a specification.
\r
276 applyStyles : function(el, styles){
\r
283 if(Ext.isFunction(styles)){
\r
284 styles = styles.call();
\r
286 if(Ext.isString(styles)){
\r
287 styles = styles.trim().split(/\s*(?::|;)\s*/);
\r
288 for(len = styles.length; i < len;){
\r
289 el.setStyle(styles[i++], styles[i++]);
\r
291 }else if (Ext.isObject(styles)){
\r
292 el.setStyle(styles);
\r
298 * Inserts an HTML fragment into the DOM.
\r
299 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
\r
300 * @param {HTMLElement} el The context element
\r
301 * @param {String} html The HTML fragment
\r
302 * @return {HTMLElement} The new node
\r
304 insertHtml : function(where, el, html){
\r
313 where = where.toLowerCase();
\r
314 // add these here because they are used in both branches of the condition.
\r
315 hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
\r
316 hash[afterend] = ['AfterEnd', 'nextSibling'];
\r
318 if (el.insertAdjacentHTML) {
\r
319 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
\r
322 // add these two to the hash.
\r
323 hash[afterbegin] = ['AfterBegin', 'firstChild'];
\r
324 hash[beforeend] = ['BeforeEnd', 'lastChild'];
\r
325 if ((hashVal = hash[where])) {
\r
326 el.insertAdjacentHTML(hashVal[0], html);
\r
327 return el[hashVal[1]];
\r
330 range = el.ownerDocument.createRange();
\r
331 setStart = 'setStart' + (/end/i.test(where) ? 'After' : 'Before');
\r
333 range[setStart](el);
\r
334 frag = range.createContextualFragment(html);
\r
335 el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
\r
336 return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
\r
338 rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
\r
339 if (el.firstChild) {
\r
340 range[setStart](el[rangeEl]);
\r
341 frag = range.createContextualFragment(html);
\r
342 if(where == afterbegin){
\r
343 el.insertBefore(frag, el.firstChild);
\r
345 el.appendChild(frag);
\r
348 el.innerHTML = html;
\r
350 return el[rangeEl];
\r
353 throw 'Illegal insertion point -> "' + where + '"';
\r
357 * Creates new DOM element(s) and inserts them before el.
\r
358 * @param {Mixed} el The context element
\r
359 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
\r
360 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
361 * @return {HTMLElement/Ext.Element} The new node
\r
363 insertBefore : function(el, o, returnElement){
\r
364 return doInsert(el, o, returnElement, beforebegin);
\r
368 * Creates new DOM element(s) and inserts them after el.
\r
369 * @param {Mixed} el The context element
\r
370 * @param {Object} o The DOM object spec (and children)
\r
371 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
372 * @return {HTMLElement/Ext.Element} The new node
\r
374 insertAfter : function(el, o, returnElement){
\r
375 return doInsert(el, o, returnElement, afterend, 'nextSibling');
\r
379 * Creates new DOM element(s) and inserts them as the first child of el.
\r
380 * @param {Mixed} el The context element
\r
381 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
\r
382 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
383 * @return {HTMLElement/Ext.Element} The new node
\r
385 insertFirst : function(el, o, returnElement){
\r
386 return doInsert(el, o, returnElement, afterbegin, 'firstChild');
\r
390 * Creates new DOM element(s) and appends them to el.
\r
391 * @param {Mixed} el The context element
\r
392 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
\r
393 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
394 * @return {HTMLElement/Ext.Element} The new node
\r
396 append : function(el, o, returnElement){
\r
397 return doInsert(el, o, returnElement, beforeend, '', true);
\r
401 * Creates new DOM element(s) and overwrites the contents of el with them.
\r
402 * @param {Mixed} el The context element
\r
403 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
\r
404 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
405 * @return {HTMLElement/Ext.Element} The new node
\r
407 overwrite : function(el, o, returnElement){
\r
408 el = Ext.getDom(el);
\r
409 el.innerHTML = createHtml(o);
\r
410 return returnElement ? Ext.get(el.firstChild) : el.firstChild;
\r
413 createHtml : createHtml
\r
417 * @class Ext.DomHelper
\r
419 Ext.apply(Ext.DomHelper,
\r
422 afterbegin = 'afterbegin',
\r
423 afterend = 'afterend',
\r
424 beforebegin = 'beforebegin',
\r
425 beforeend = 'beforeend';
\r
428 function doInsert(el, o, returnElement, pos, sibling, append){
\r
429 el = Ext.getDom(el);
\r
432 newNode = createDom(o, null);
\r
434 el.appendChild(newNode);
\r
436 (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
\r
439 newNode = Ext.DomHelper.insertHtml(pos, el, Ext.DomHelper.createHtml(o));
\r
441 return returnElement ? Ext.get(newNode, true) : newNode;
\r
446 function createDom(o, parentNode){
\r
454 if (Ext.isArray(o)) { // Allow Arrays of siblings to be inserted
\r
455 el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
\r
456 Ext.each(o, function(v) {
\r
459 } else if (Ext.isString(o)) { // Allow a string as a child spec.
\r
460 el = doc.createTextNode(o);
\r
462 el = doc.createElement( o.tag || 'div' );
\r
463 useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
\r
464 Ext.iterate(o, function(attr, val){
\r
465 if(!/tag|children|cn|html|style/.test(attr)){
\r
467 el.className = val;
\r
470 el.setAttribute(attr, val);
\r
477 Ext.DomHelper.applyStyles(el, o.style);
\r
479 if ((cn = o.children || o.cn)) {
\r
481 } else if (o.html) {
\r
482 el.innerHTML = o.html;
\r
486 parentNode.appendChild(el);
\r
493 * Creates a new Ext.Template from the DOM object spec.
\r
494 * @param {Object} o The DOM object spec (and children)
\r
495 * @return {Ext.Template} The new template
\r
497 createTemplate : function(o){
\r
498 var html = Ext.DomHelper.createHtml(o);
\r
499 return new Ext.Template(html);
\r
502 /** True to force the use of DOM instead of html fragments @type Boolean */
\r
506 * Creates new DOM element(s) and inserts them before el.
\r
507 * @param {Mixed} el The context element
\r
508 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
\r
509 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
510 * @return {HTMLElement/Ext.Element} The new node
\r
513 insertBefore : function(el, o, returnElement){
\r
514 return doInsert(el, o, returnElement, beforebegin);
\r
518 * Creates new DOM element(s) and inserts them after el.
\r
519 * @param {Mixed} el The context element
\r
520 * @param {Object} o The DOM object spec (and children)
\r
521 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
522 * @return {HTMLElement/Ext.Element} The new node
\r
525 insertAfter : function(el, o, returnElement){
\r
526 return doInsert(el, o, returnElement, afterend, 'nextSibling');
\r
530 * Creates new DOM element(s) and inserts them as the first child of el.
\r
531 * @param {Mixed} el The context element
\r
532 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
\r
533 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
534 * @return {HTMLElement/Ext.Element} The new node
\r
537 insertFirst : function(el, o, returnElement){
\r
538 return doInsert(el, o, returnElement, afterbegin, 'firstChild');
\r
542 * Creates new DOM element(s) and appends them to el.
\r
543 * @param {Mixed} el The context element
\r
544 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
\r
545 * @param {Boolean} returnElement (optional) true to return a Ext.Element
\r
546 * @return {HTMLElement/Ext.Element} The new node
\r
549 append: function(el, o, returnElement){
\r
550 return doInsert(el, o, returnElement, beforeend, '', true);
\r
554 * Creates new DOM element(s) without inserting them to the document.
\r
555 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
\r
556 * @return {HTMLElement} The new uninserted node
\r
558 createDom: createDom
\r
562 * @class Ext.Template
563 * <p>Represents an HTML fragment template. Templates may be {@link #compile precompiled}
564 * for greater performance.</p>
565 * <p>For example usage {@link #Template see the constructor}.</p>
568 * An instance of this class may be created by passing to the constructor either
569 * a single argument, or multiple arguments:
570 * <div class="mdetail-params"><ul>
571 * <li><b>single argument</b> : String/Array
572 * <div class="sub-desc">
573 * The single argument may be either a String or an Array:<ul>
574 * <li><tt>String</tt> : </li><pre><code>
575 var t = new Ext.Template("<div>Hello {0}.</div>");
576 t.{@link #append}('some-element', ['foo']);
578 * <li><tt>Array</tt> : </li>
579 * An Array will be combined with <code>join('')</code>.
581 var t = new Ext.Template([
582 '<div name="{id}">',
583 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
586 t.{@link #compile}();
587 t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
590 * <li><b>multiple arguments</b> : String, Object, Array, ...
591 * <div class="sub-desc">
592 * Multiple arguments will be combined with <code>join('')</code>.
594 var t = new Ext.Template(
595 '<div name="{id}">',
596 '<span class="{cls}">{name} {value}</span>',
598 // a configuration object:
600 compiled: true, // {@link #compile} immediately
601 disableFormats: true // See Notes below.
605 * <p><b>Notes</b>:</p>
606 * <div class="mdetail-params"><ul>
607 * <li>Formatting and <code>disableFormats</code> are not applicable for Ext Core.</li>
608 * <li>For a list of available format functions, see {@link Ext.util.Format}.</li>
609 * <li><code>disableFormats</code> reduces <code>{@link #apply}</code> time
610 * when no formatting is required.</li>
614 * @param {Mixed} config
616 Ext.Template = function(html){
621 if (Ext.isArray(html)) {
622 html = html.join("");
623 } else if (a.length > 1) {
624 Ext.each(a, function(v) {
625 if (Ext.isObject(v)) {
637 * @cfg {Boolean} compiled Specify <tt>true</tt> to compile the template
638 * immediately (see <code>{@link #compile}</code>).
639 * Defaults to <tt>false</tt>.
645 Ext.Template.prototype = {
647 * @cfg {RegExp} re The regular expression used to match template variables.
648 * Defaults to:<pre><code>
649 * re : /\{([\w-]+)\}/g // for Ext Core
650 * re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g // for Ext JS
653 re : /\{([\w-]+)\}/g,
655 * See <code>{@link #re}</code>.
661 * Returns an HTML fragment of this template with the specified <code>values</code> applied.
662 * @param {Object/Array} values
663 * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
664 * or an object (i.e. <code>{foo: 'bar'}</code>).
665 * @return {String} The HTML fragment
667 applyTemplate : function(values){
671 me.compiled(values) :
672 me.html.replace(me.re, function(m, name){
673 return values[name] !== undefined ? values[name] : "";
678 * Sets the HTML used as the template and optionally compiles it.
679 * @param {String} html
680 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
681 * @return {Ext.Template} this
683 set : function(html, compile){
687 return compile ? me.compile() : me;
691 * Compiles the template into an internal function, eliminating the RegEx overhead.
692 * @return {Ext.Template} this
694 compile : function(){
696 sep = Ext.isGecko ? "+" : ",";
698 function fn(m, name){
699 name = "values['" + name + "']";
700 return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";
703 eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +
704 me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
705 (Ext.isGecko ? "';};" : "'].join('');};"));
710 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
711 * @param {Mixed} el The context element
712 * @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'})
713 * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
714 * @return {HTMLElement/Ext.Element} The new node or Element
716 insertFirst: function(el, values, returnElement){
717 return this.doInsert('afterBegin', el, values, returnElement);
721 * Applies the supplied values to the template and inserts the new node(s) before el.
722 * @param {Mixed} el The context element
723 * @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'})
724 * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
725 * @return {HTMLElement/Ext.Element} The new node or Element
727 insertBefore: function(el, values, returnElement){
728 return this.doInsert('beforeBegin', el, values, returnElement);
732 * Applies the supplied values to the template and inserts the new node(s) after el.
733 * @param {Mixed} el The context element
734 * @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'})
735 * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
736 * @return {HTMLElement/Ext.Element} The new node or Element
738 insertAfter : function(el, values, returnElement){
739 return this.doInsert('afterEnd', el, values, returnElement);
743 * Applies the supplied <code>values</code> to the template and appends
744 * the new node(s) to the specified <code>el</code>.
745 * <p>For example usage {@link #Template see the constructor}.</p>
746 * @param {Mixed} el The context element
747 * @param {Object/Array} values
748 * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
749 * or an object (i.e. <code>{foo: 'bar'}</code>).
750 * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined)
751 * @return {HTMLElement/Ext.Element} The new node or Element
753 append : function(el, values, returnElement){
754 return this.doInsert('beforeEnd', el, values, returnElement);
757 doInsert : function(where, el, values, returnEl){
759 var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
760 return returnEl ? Ext.get(newNode, true) : newNode;
764 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
765 * @param {Mixed} el The context element
766 * @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'})
767 * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
768 * @return {HTMLElement/Ext.Element} The new node or Element
770 overwrite : function(el, values, returnElement){
772 el.innerHTML = this.applyTemplate(values);
773 return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
777 * Alias for {@link #applyTemplate}
778 * Returns an HTML fragment of this template with the specified <code>values</code> applied.
779 * @param {Object/Array} values
780 * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
781 * or an object (i.e. <code>{foo: 'bar'}</code>).
782 * @return {String} The HTML fragment
783 * @member Ext.Template
786 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
789 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
790 * @param {String/HTMLElement} el A DOM element or its id
791 * @param {Object} config A configuration object
792 * @return {Ext.Template} The created template
795 Ext.Template.from = function(el, config){
797 return new Ext.Template(el.value || el.innerHTML, config || '');
799 * @class Ext.Template
\r
801 Ext.apply(Ext.Template.prototype, {
\r
803 * @cfg {Boolean} disableFormats Specify <tt>true</tt> to disable format
\r
804 * functions in the template. If the template does not contain
\r
805 * {@link Ext.util.Format format functions}, setting <code>disableFormats</code>
\r
806 * to true will reduce <code>{@link #apply}</code> time. Defaults to <tt>false</tt>.
\r
808 var t = new Ext.Template(
\r
809 '<div name="{id}">',
\r
810 '<span class="{cls}">{name} {value}</span>',
\r
813 compiled: true, // {@link #compile} immediately
\r
814 disableFormats: true // reduce <code>{@link #apply}</code> time since no formatting
\r
818 * For a list of available format functions, see {@link Ext.util.Format}.
\r
820 disableFormats : false,
\r
822 * See <code>{@link #disableFormats}</code>.
\r
824 * @property disableFormats
\r
828 * The regular expression used to match template variables
\r
833 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
\r
836 * Returns an HTML fragment of this template with the specified values applied.
\r
837 * @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'})
\r
838 * @return {String} The HTML fragment
\r
841 applyTemplate : function(values){
\r
843 useF = me.disableFormats !== true,
\r
844 fm = Ext.util.Format,
\r
848 return me.compiled(values);
\r
850 function fn(m, name, format, args){
\r
851 if (format && useF) {
\r
852 if (format.substr(0, 5) == "this.") {
\r
853 return tpl.call(format.substr(5), values[name], values);
\r
856 // quoted values are required for strings in compiled templates,
\r
857 // but for non compiled we need to strip them
\r
858 // quoted reversed for jsmin
\r
859 var re = /^\s*['"](.*)["']\s*$/;
\r
860 args = args.split(',');
\r
861 for(var i = 0, len = args.length; i < len; i++){
\r
862 args[i] = args[i].replace(re, "$1");
\r
864 args = [values[name]].concat(args);
\r
866 args = [values[name]];
\r
868 return fm[format].apply(fm, args);
\r
871 return values[name] !== undefined ? values[name] : "";
\r
874 return me.html.replace(me.re, fn);
\r
878 * Compiles the template into an internal function, eliminating the RegEx overhead.
\r
879 * @return {Ext.Template} this
\r
882 compile : function(){
\r
884 fm = Ext.util.Format,
\r
885 useF = me.disableFormats !== true,
\r
886 sep = Ext.isGecko ? "+" : ",",
\r
889 function fn(m, name, format, args){
\r
890 if(format && useF){
\r
891 args = args ? ',' + args : "";
\r
892 if(format.substr(0, 5) != "this."){
\r
893 format = "fm." + format + '(';
\r
895 format = 'this.call("'+ format.substr(5) + '", ';
\r
899 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
\r
901 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
\r
904 // branched to use + in gecko and [].join() in others
\r
906 body = "this.compiled = function(values){ return '" +
\r
907 me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
\r
910 body = ["this.compiled = function(values){ return ['"];
\r
911 body.push(me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
\r
912 body.push("'].join('');};");
\r
913 body = body.join('');
\r
919 // private function used to call members
\r
920 call : function(fnName, value, allValues){
\r
921 return this[fnName](value, allValues);
\r
924 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate; /*
\r
925 * This is code is also distributed under MIT license for use
\r
926 * with jQuery and prototype JavaScript libraries.
\r
929 * @class Ext.DomQuery
\r
930 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
\r
932 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/#selectors">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
\r
935 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
\r
937 <h4>Element Selectors:</h4>
\r
939 <li> <b>*</b> any element</li>
\r
940 <li> <b>E</b> an element with the tag E</li>
\r
941 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
\r
942 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
\r
943 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
\r
944 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
\r
946 <h4>Attribute Selectors:</h4>
\r
947 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
\r
949 <li> <b>E[foo]</b> has an attribute "foo"</li>
\r
950 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
\r
951 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
\r
952 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
\r
953 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
\r
954 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
\r
955 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
\r
957 <h4>Pseudo Classes:</h4>
\r
959 <li> <b>E:first-child</b> E is the first child of its parent</li>
\r
960 <li> <b>E:last-child</b> E is the last child of its parent</li>
\r
961 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
\r
962 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
\r
963 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
\r
964 <li> <b>E:only-child</b> E is the only child of its parent</li>
\r
965 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
\r
966 <li> <b>E:first</b> the first E in the resultset</li>
\r
967 <li> <b>E:last</b> the last E in the resultset</li>
\r
968 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
\r
969 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
\r
970 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
\r
971 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
\r
972 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
\r
973 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
\r
974 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
\r
975 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
\r
976 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
\r
978 <h4>CSS Value Selectors:</h4>
\r
980 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
\r
981 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
\r
982 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
\r
983 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
\r
984 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
\r
985 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
\r
989 Ext.DomQuery = function(){
\r
994 trimRe = /^\s+|\s+$/g,
\r
995 tplRe = /\{(\d+)\}/g,
\r
996 modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
\r
997 tagTokenRe = /^(#)?([\w-\*]+)/,
\r
998 nthRe = /(\d*)n\+?(\d*)/,
\r
1000 // This is for IE MSXML which does not support expandos.
\r
1001 // IE runs the same speed using setAttribute, however FF slows way down
\r
1002 // and Safari completely fails so they need to continue to use expandos.
\r
1003 isIE = window.ActiveXObject ? true : false,
\r
1004 isOpera = Ext.isOpera,
\r
1007 // this eval is stop the compressor from
\r
1008 // renaming the variable to something shorter
\r
1009 eval("var batch = 30803;");
\r
1011 function child(p, index){
\r
1015 if(n.nodeType == 1){
\r
1020 n = n.nextSibling;
\r
1026 while((n = n.nextSibling) && n.nodeType != 1);
\r
1031 while((n = n.previousSibling) && n.nodeType != 1);
\r
1035 function children(d){
\r
1036 var n = d.firstChild, ni = -1,
\r
1039 nx = n.nextSibling;
\r
1040 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
\r
1043 n.nodeIndex = ++ni;
\r
1050 function byClassName(c, a, v){
\r
1054 var r = [], ri = -1, cn;
\r
1055 for(var i = 0, ci; ci = c[i]; i++){
\r
1056 if((' '+ci.className+' ').indexOf(v) != -1){
\r
1063 function attrValue(n, attr){
\r
1064 if(!n.tagName && typeof n.length != "undefined"){
\r
1070 if(attr == "for"){
\r
1073 if(attr == "class" || attr == "className"){
\r
1074 return n.className;
\r
1076 return n.getAttribute(attr) || n[attr];
\r
1080 function getNodes(ns, mode, tagName){
\r
1081 var result = [], ri = -1, cs;
\r
1085 tagName = tagName || "*";
\r
1086 if(typeof ns.getElementsByTagName != "undefined"){
\r
1090 for(var i = 0, ni; ni = ns[i]; i++){
\r
1091 cs = ni.getElementsByTagName(tagName);
\r
1092 for(var j = 0, ci; ci = cs[j]; j++){
\r
1093 result[++ri] = ci;
\r
1096 }else if(mode == "/" || mode == ">"){
\r
1097 var utag = tagName.toUpperCase();
\r
1098 for(var i = 0, ni, cn; ni = ns[i]; i++){
\r
1099 cn = isOpera ? ni.childNodes : (ni.children || ni.childNodes);
\r
1100 for(var j = 0, cj; cj = cn[j]; j++){
\r
1101 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
\r
1102 result[++ri] = cj;
\r
1106 }else if(mode == "+"){
\r
1107 var utag = tagName.toUpperCase();
\r
1108 for(var i = 0, n; n = ns[i]; i++){
\r
1109 while((n = n.nextSibling) && n.nodeType != 1);
\r
1110 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
\r
1114 }else if(mode == "~"){
\r
1115 var utag = tagName.toUpperCase();
\r
1116 for(var i = 0, n; n = ns[i]; i++){
\r
1117 while((n = n.nextSibling)){
\r
1118 if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
\r
1127 function concat(a, b){
\r
1129 return a.concat(b);
\r
1131 for(var i = 0, l = b.length; i < l; i++){
\r
1132 a[a.length] = b[i];
\r
1137 function byTag(cs, tagName){
\r
1138 if(cs.tagName || cs == document){
\r
1144 var r = [], ri = -1;
\r
1145 tagName = tagName.toLowerCase();
\r
1146 for(var i = 0, ci; ci = cs[i]; i++){
\r
1147 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
\r
1154 function byId(cs, attr, id){
\r
1155 if(cs.tagName || cs == document){
\r
1161 var r = [], ri = -1;
\r
1162 for(var i = 0,ci; ci = cs[i]; i++){
\r
1163 if(ci && ci.id == id){
\r
1171 function byAttribute(cs, attr, value, op, custom){
\r
1175 f = Ext.DomQuery.operators[op];
\r
1176 for(var i = 0, ci; ci = cs[i]; i++){
\r
1177 if(ci.nodeType != 1){
\r
1182 a = Ext.DomQuery.getStyle(ci, attr);
\r
1184 else if(attr == "class" || attr == "className"){
\r
1186 }else if(attr == "for"){
\r
1188 }else if(attr == "href"){
\r
1189 a = ci.getAttribute("href", 2);
\r
1191 a = ci.getAttribute(attr);
\r
1193 if((f && f(a, value)) || (!f && a)){
\r
1200 function byPseudo(cs, name, value){
\r
1201 return Ext.DomQuery.pseudos[name](cs, value);
\r
1204 function nodupIEXml(cs){
\r
1207 cs[0].setAttribute("_nodup", d);
\r
1209 for(var i = 1, len = cs.length; i < len; i++){
\r
1211 if(!c.getAttribute("_nodup") != d){
\r
1212 c.setAttribute("_nodup", d);
\r
1216 for(var i = 0, len = cs.length; i < len; i++){
\r
1217 cs[i].removeAttribute("_nodup");
\r
1222 function nodup(cs){
\r
1226 var len = cs.length, c, i, r = cs, cj, ri = -1;
\r
1227 if(!len || typeof cs.nodeType != "undefined" || len == 1){
\r
1230 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
\r
1231 return nodupIEXml(cs);
\r
1235 for(i = 1; c = cs[i]; i++){
\r
1236 if(c._nodup != d){
\r
1240 for(var j = 0; j < i; j++){
\r
1243 for(j = i+1; cj = cs[j]; j++){
\r
1244 if(cj._nodup != d){
\r
1255 function quickDiffIEXml(c1, c2){
\r
1258 for(var i = 0, len = c1.length; i < len; i++){
\r
1259 c1[i].setAttribute("_qdiff", d);
\r
1261 for(var i = 0, len = c2.length; i < len; i++){
\r
1262 if(c2[i].getAttribute("_qdiff") != d){
\r
1263 r[r.length] = c2[i];
\r
1266 for(var i = 0, len = c1.length; i < len; i++){
\r
1267 c1[i].removeAttribute("_qdiff");
\r
1272 function quickDiff(c1, c2){
\r
1273 var len1 = c1.length,
\r
1279 if(isIE && c1[0].selectSingleNode){
\r
1280 return quickDiffIEXml(c1, c2);
\r
1282 for(var i = 0; i < len1; i++){
\r
1285 for(var i = 0, len = c2.length; i < len; i++){
\r
1286 if(c2[i]._qdiff != d){
\r
1287 r[r.length] = c2[i];
\r
1293 function quickId(ns, mode, root, id){
\r
1295 var d = root.ownerDocument || root;
\r
1296 return d.getElementById(id);
\r
1298 ns = getNodes(ns, mode, "*");
\r
1299 return byId(ns, null, id);
\r
1303 getStyle : function(el, name){
\r
1304 return Ext.fly(el).getStyle(name);
\r
1307 * Compiles a selector/xpath query into a reusable function. The returned function
\r
1308 * takes one parameter "root" (optional), which is the context node from where the query should start.
\r
1309 * @param {String} selector The selector/xpath query
\r
1310 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
\r
1311 * @return {Function}
\r
1313 compile : function(path, type){
\r
1314 type = type || "select";
\r
1316 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
\r
1317 q = path, mode, lq,
\r
1318 tk = Ext.DomQuery.matchers,
\r
1319 tklen = tk.length,
\r
1321 // accept leading mode switch
\r
1322 lmode = q.match(modeRe);
\r
1324 if(lmode && lmode[1]){
\r
1325 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
\r
1326 q = q.replace(lmode[1], "");
\r
1328 // strip leading slashes
\r
1329 while(path.substr(0, 1)=="/"){
\r
1330 path = path.substr(1);
\r
1333 while(q && lq != q){
\r
1335 var tm = q.match(tagTokenRe);
\r
1336 if(type == "select"){
\r
1339 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
\r
1341 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
\r
1343 q = q.replace(tm[0], "");
\r
1344 }else if(q.substr(0, 1) != '@'){
\r
1345 fn[fn.length] = 'n = getNodes(n, mode, "*");';
\r
1350 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
\r
1352 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
\r
1354 q = q.replace(tm[0], "");
\r
1357 while(!(mm = q.match(modeRe))){
\r
1358 var matched = false;
\r
1359 for(var j = 0; j < tklen; j++){
\r
1361 var m = q.match(t.re);
\r
1363 fn[fn.length] = t.select.replace(tplRe, function(x, i){
\r
1366 q = q.replace(m[0], "");
\r
1371 // prevent infinite loop on bad selector
\r
1373 throw 'Error parsing selector, parsing failed at "' + q + '"';
\r
1377 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
\r
1378 q = q.replace(mm[1], "");
\r
1381 fn[fn.length] = "return nodup(n);\n}";
\r
1382 eval(fn.join(""));
\r
1387 * Selects a group of elements.
\r
1388 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
\r
1389 * @param {Node} root (optional) The start of the query (defaults to document).
\r
1390 * @return {Array} An Array of DOM elements which match the selector. If there are
\r
1391 * no matches, and empty Array is returned.
\r
1393 select : function(path, root, type){
\r
1394 if(!root || root == document){
\r
1397 if(typeof root == "string"){
\r
1398 root = document.getElementById(root);
\r
1400 var paths = path.split(","),
\r
1402 for(var i = 0, len = paths.length; i < len; i++){
\r
1403 var p = paths[i].replace(trimRe, "");
\r
1405 cache[p] = Ext.DomQuery.compile(p);
\r
1407 throw p + " is not a valid selector";
\r
1410 var result = cache[p](root);
\r
1411 if(result && result != document){
\r
1412 results = results.concat(result);
\r
1415 if(paths.length > 1){
\r
1416 return nodup(results);
\r
1422 * Selects a single element.
\r
1423 * @param {String} selector The selector/xpath query
\r
1424 * @param {Node} root (optional) The start of the query (defaults to document).
\r
1425 * @return {Element} The DOM element which matched the selector.
\r
1427 selectNode : function(path, root){
\r
1428 return Ext.DomQuery.select(path, root)[0];
\r
1432 * Selects the value of a node, optionally replacing null with the defaultValue.
\r
1433 * @param {String} selector The selector/xpath query
\r
1434 * @param {Node} root (optional) The start of the query (defaults to document).
\r
1435 * @param {String} defaultValue
\r
1436 * @return {String}
\r
1438 selectValue : function(path, root, defaultValue){
\r
1439 path = path.replace(trimRe, "");
\r
1440 if(!valueCache[path]){
\r
1441 valueCache[path] = Ext.DomQuery.compile(path, "select");
\r
1443 var n = valueCache[path](root),
\r
1445 n = n[0] ? n[0] : n;
\r
1446 v = (n && n.firstChild ? n.firstChild.nodeValue : null);
\r
1447 return ((v === null||v === undefined||v==='') ? defaultValue : v);
\r
1451 * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
\r
1452 * @param {String} selector The selector/xpath query
\r
1453 * @param {Node} root (optional) The start of the query (defaults to document).
\r
1454 * @param {Number} defaultValue
\r
1455 * @return {Number}
\r
1457 selectNumber : function(path, root, defaultValue){
\r
1458 var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
\r
1459 return parseFloat(v);
\r
1463 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
\r
1464 * @param {String/HTMLElement/Array} el An element id, element or array of elements
\r
1465 * @param {String} selector The simple selector to test
\r
1466 * @return {Boolean}
\r
1468 is : function(el, ss){
\r
1469 if(typeof el == "string"){
\r
1470 el = document.getElementById(el);
\r
1472 var isArray = Ext.isArray(el),
\r
1473 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
\r
1474 return isArray ? (result.length == el.length) : (result.length > 0);
\r
1478 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
\r
1479 * @param {Array} el An array of elements to filter
\r
1480 * @param {String} selector The simple selector to test
\r
1481 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
\r
1482 * the selector instead of the ones that match
\r
1483 * @return {Array} An Array of DOM elements which match the selector. If there are
\r
1484 * no matches, and empty Array is returned.
\r
1486 filter : function(els, ss, nonMatches){
\r
1487 ss = ss.replace(trimRe, "");
\r
1488 if(!simpleCache[ss]){
\r
1489 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
\r
1491 var result = simpleCache[ss](els);
\r
1492 return nonMatches ? quickDiff(result, els) : result;
\r
1496 * Collection of matching regular expressions and code snippets.
\r
1499 re: /^\.([\w-]+)/,
\r
1500 select: 'n = byClassName(n, null, " {1} ");'
\r
1502 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
\r
1503 select: 'n = byPseudo(n, "{1}", "{2}");'
\r
1505 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
\r
1506 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
\r
1509 select: 'n = byId(n, null, "{1}");'
\r
1512 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
\r
1517 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
\r
1518 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
\r
1521 "=" : function(a, v){
\r
1524 "!=" : function(a, v){
\r
1527 "^=" : function(a, v){
\r
1528 return a && a.substr(0, v.length) == v;
\r
1530 "$=" : function(a, v){
\r
1531 return a && a.substr(a.length-v.length) == v;
\r
1533 "*=" : function(a, v){
\r
1534 return a && a.indexOf(v) !== -1;
\r
1536 "%=" : function(a, v){
\r
1537 return (a % v) == 0;
\r
1539 "|=" : function(a, v){
\r
1540 return a && (a == v || a.substr(0, v.length+1) == v+'-');
\r
1542 "~=" : function(a, v){
\r
1543 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
\r
1548 * <p>Object hash of "pseudo class" filter functions which are used when filtering selections. Each function is passed
\r
1549 * two parameters:</p><div class="mdetail-params"><ul>
\r
1550 * <li><b>c</b> : Array<div class="sub-desc">An Array of DOM elements to filter.</div></li>
\r
1551 * <li><b>v</b> : String<div class="sub-desc">The argument (if any) supplied in the selector.</div></li>
\r
1553 * <p>A filter function returns an Array of DOM elements which conform to the pseudo class.</p>
\r
1554 * <p>In addition to the provided pseudo classes listed above such as <code>first-child</code> and <code>nth-child</code>,
\r
1555 * developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.</p>
\r
1556 * <p>For example, to filter <code><a></code> elements to only return links to <i>external</i> resources:</p>
\r
1558 Ext.DomQuery.pseudos.external = function(c, v){
\r
1559 var r = [], ri = -1;
\r
1560 for(var i = 0, ci; ci = c[i]; i++){
\r
1561 // Include in result set only if it's a link to an external resource
\r
1562 if(ci.hostname != location.hostname){
\r
1568 * Then external links could be gathered with the following statement:<code><pre>
\r
1569 var externalLinks = Ext.select("a:external");
\r
1573 "first-child" : function(c){
\r
1574 var r = [], ri = -1, n;
\r
1575 for(var i = 0, ci; ci = n = c[i]; i++){
\r
1576 while((n = n.previousSibling) && n.nodeType != 1);
\r
1584 "last-child" : function(c){
\r
1585 var r = [], ri = -1, n;
\r
1586 for(var i = 0, ci; ci = n = c[i]; i++){
\r
1587 while((n = n.nextSibling) && n.nodeType != 1);
\r
1595 "nth-child" : function(c, a) {
\r
1596 var r = [], ri = -1,
\r
1597 m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
\r
1598 f = (m[1] || 1) - 0, l = m[2] - 0;
\r
1599 for(var i = 0, n; n = c[i]; i++){
\r
1600 var pn = n.parentNode;
\r
1601 if (batch != pn._batch) {
\r
1603 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
\r
1604 if(cn.nodeType == 1){
\r
1605 cn.nodeIndex = ++j;
\r
1608 pn._batch = batch;
\r
1611 if (l == 0 || n.nodeIndex == l){
\r
1614 } else if ((n.nodeIndex + l) % f == 0){
\r
1622 "only-child" : function(c){
\r
1623 var r = [], ri = -1;;
\r
1624 for(var i = 0, ci; ci = c[i]; i++){
\r
1625 if(!prev(ci) && !next(ci)){
\r
1632 "empty" : function(c){
\r
1633 var r = [], ri = -1;
\r
1634 for(var i = 0, ci; ci = c[i]; i++){
\r
1635 var cns = ci.childNodes, j = 0, cn, empty = true;
\r
1636 while(cn = cns[j]){
\r
1638 if(cn.nodeType == 1 || cn.nodeType == 3){
\r
1650 "contains" : function(c, v){
\r
1651 var r = [], ri = -1;
\r
1652 for(var i = 0, ci; ci = c[i]; i++){
\r
1653 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
\r
1660 "nodeValue" : function(c, v){
\r
1661 var r = [], ri = -1;
\r
1662 for(var i = 0, ci; ci = c[i]; i++){
\r
1663 if(ci.firstChild && ci.firstChild.nodeValue == v){
\r
1670 "checked" : function(c){
\r
1671 var r = [], ri = -1;
\r
1672 for(var i = 0, ci; ci = c[i]; i++){
\r
1673 if(ci.checked == true){
\r
1680 "not" : function(c, ss){
\r
1681 return Ext.DomQuery.filter(c, ss, true);
\r
1684 "any" : function(c, selectors){
\r
1685 var ss = selectors.split('|'),
\r
1686 r = [], ri = -1, s;
\r
1687 for(var i = 0, ci; ci = c[i]; i++){
\r
1688 for(var j = 0; s = ss[j]; j++){
\r
1689 if(Ext.DomQuery.is(ci, s)){
\r
1698 "odd" : function(c){
\r
1699 return this["nth-child"](c, "odd");
\r
1702 "even" : function(c){
\r
1703 return this["nth-child"](c, "even");
\r
1706 "nth" : function(c, a){
\r
1707 return c[a-1] || [];
\r
1710 "first" : function(c){
\r
1711 return c[0] || [];
\r
1714 "last" : function(c){
\r
1715 return c[c.length-1] || [];
\r
1718 "has" : function(c, ss){
\r
1719 var s = Ext.DomQuery.select,
\r
1721 for(var i = 0, ci; ci = c[i]; i++){
\r
1722 if(s(ss, ci).length > 0){
\r
1729 "next" : function(c, ss){
\r
1730 var is = Ext.DomQuery.is,
\r
1732 for(var i = 0, ci; ci = c[i]; i++){
\r
1734 if(n && is(n, ss)){
\r
1741 "prev" : function(c, ss){
\r
1742 var is = Ext.DomQuery.is,
\r
1744 for(var i = 0, ci; ci = c[i]; i++){
\r
1746 if(n && is(n, ss)){
\r
1757 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
\r
1758 * @param {String} path The selector/xpath query
\r
1759 * @param {Node} root (optional) The start of the query (defaults to document).
\r
1764 Ext.query = Ext.DomQuery.select;
\r
1767 var EXTUTIL = Ext.util,
1768 TOARRAY = Ext.toArray,
1770 ISOBJECT = Ext.isObject,
1774 * @class Ext.util.Observable
1775 * Base class that provides a common interface for publishing events. Subclasses are expected to
1776 * to have a property "events" with all the events defined, and, optionally, a property "listeners"
1777 * with configured listeners defined.<br>
1780 Employee = Ext.extend(Ext.util.Observable, {
1781 constructor: function(config){
1782 this.name = config.name;
1788 // Copy configured listeners into *this* object so that the base class's
1789 // constructor will add them.
1790 this.listeners = config.listeners;
1792 // Call our superclass constructor to complete construction process.
1793 Employee.superclass.constructor.call(config)
1797 * This could then be used like this:<pre><code>
1798 var newEmployee = new Employee({
1802 // By default, "this" will be the object that fired the event.
1803 alert(this.name + " has quit!");
1809 EXTUTIL.Observable = function(){
1811 * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
1812 * object during initialization. This should be a valid listeners config object as specified in the
1813 * {@link #addListener} example for attaching multiple handlers at once.</p>
1814 * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
1815 * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
1816 * is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
1817 * <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
1818 * events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
1819 * has been rendered. A plugin can simplify this step:<pre><code>
1820 // Plugin is configured with a listeners config object.
1821 // The Component is appended to the argument list of all handler functions.
1822 Ext.DomObserver = Ext.extend(Object, {
1823 constructor: function(config) {
1824 this.listeners = config.listeners ? config.listeners : config;
1827 // Component passes itself into plugin's init method
1829 var p, l = this.listeners;
1831 if (Ext.isFunction(l[p])) {
1832 l[p] = this.createHandler(l[p], c);
1834 l[p].fn = this.createHandler(l[p].fn, c);
1838 // Add the listeners to the Element immediately following the render call
1839 c.render = c.render.{@link Function#createSequence createSequence}(function() {
1847 createHandler: function(fn, c) {
1848 return function(e) {
1849 fn.call(this, e, c);
1854 var combo = new Ext.form.ComboBox({
1856 // Collapse combo when its element is clicked on
1857 plugins: [ new Ext.DomObserver({
1858 click: function(evt, comp) {
1865 triggerAction: 'all'
1869 var me = this, e = me.events;
1871 me.on(me.listeners);
1872 delete me.listeners;
1874 me.events = e || {};
1877 EXTUTIL.Observable.prototype = {
1879 filterOptRe : /^(?:scope|delay|buffer|single)$/,
1882 * <p>Fires the specified event with the passed parameters (minus the event name).</p>
1883 * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
1884 * by calling {@link #enableBubble}.</p>
1885 * @param {String} eventName The name of the event to fire.
1886 * @param {Object...} args Variable number of parameters are passed to handlers.
1887 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
1889 fireEvent : function(){
1890 var a = TOARRAY(arguments),
1891 ename = a[0].toLowerCase(),
1894 ce = me.events[ename],
1897 if (me.eventsSuspended === TRUE) {
1898 if (q = me.eventQueue) {
1902 else if(ISOBJECT(ce) && ce.bubble){
1903 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
1906 c = me.getBubbleTarget && me.getBubbleTarget();
1907 if(c && c.enableBubble) {
1908 if(!c.events[ename] || !Ext.isObject(c.events[ename]) || !c.events[ename].bubble) {
1909 c.enableBubble(ename);
1911 return c.fireEvent.apply(c, a);
1917 ret = ce.fire.apply(ce, a);
1924 * Appends an event handler to this object.
1925 * @param {String} eventName The name of the event to listen for.
1926 * @param {Function} handler The method the event invokes.
1927 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
1928 * <b>If omitted, defaults to the object which fired the event.</b>
1929 * @param {Object} options (optional) An object containing handler configuration.
1930 * properties. This may contain any of the following properties:<ul>
1931 * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
1932 * <b>If omitted, defaults to the object which fired the event.</b></div></li>
1933 * <li><b>delay</b> : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
1934 * <li><b>single</b> : Boolean<div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
1935 * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
1936 * by the specified number of milliseconds. If the event fires again within that time, the original
1937 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
1938 * <li><b>target</b> : Observable<div class="sub-desc">Only call the handler if the event was fired on the target Observable, <i>not</i>
1939 * if the event was bubbled up from a child Observable.</div></li>
1942 * <b>Combining Options</b><br>
1943 * Using the options argument, it is possible to combine different types of listeners:<br>
1945 * A delayed, one-time listener.
1947 myDataView.on('click', this.onClick, this, {
1952 * <b>Attaching multiple handlers in 1 call</b><br>
1953 * The method also allows for a single argument to be passed which is a config object containing properties
1954 * which specify multiple handlers.
1964 fn: this.onMouseOver,
1968 fn: this.onMouseOut,
1973 * Or a shorthand syntax:<br>
1976 'click' : this.onClick,
1977 'mouseover' : this.onMouseOver,
1978 'mouseout' : this.onMouseOut,
1982 addListener : function(eventName, fn, scope, o){
1988 if (ISOBJECT(eventName)) {
1992 if (!me.filterOptRe.test(e)) {
1993 me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
1997 eventName = eventName.toLowerCase();
1998 ce = me.events[eventName] || TRUE;
1999 if (Ext.isBoolean(ce)) {
2000 me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
2002 ce.addListener(fn, scope, ISOBJECT(o) ? o : {});
2007 * Removes an event handler.
2008 * @param {String} eventName The type of event the handler was associated with.
2009 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2010 * @param {Object} scope (optional) The scope originally specified for the handler.
2012 removeListener : function(eventName, fn, scope){
2013 var ce = this.events[eventName.toLowerCase()];
2015 ce.removeListener(fn, scope);
2020 * Removes all listeners for this object
2022 purgeListeners : function(){
2023 var events = this.events,
2029 evt.clearListeners();
2035 * Adds the specified events to the list of events which this Observable may fire.
2036 * @param {Object|String} o Either an object with event names as properties with a value of <code>true</code>
2037 * or the first event name string if multiple event names are being passed as separate parameters.
2038 * @param {string} Optional. Event name if multiple event names are being passed as separate parameters.
2040 this.addEvents('storeloaded', 'storecleared');
2043 addEvents : function(o){
2045 me.events = me.events || {};
2046 if (Ext.isString(o)) {
2047 EACH(arguments, function(a) {
2048 me.events[a] = me.events[a] || TRUE;
2051 Ext.applyIf(me.events, o);
2056 * Checks to see if this object has any listeners for a specified event
2057 * @param {String} eventName The name of the event to check for
2058 * @return {Boolean} True if the event is being listened for, else false
2060 hasListener : function(eventName){
2061 var e = this.events[eventName];
2062 return ISOBJECT(e) && e.listeners.length > 0;
2066 * Suspend the firing of all events. (see {@link #resumeEvents})
2067 * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
2068 * after the {@link #resumeEvents} call instead of discarding all suspended events;
2070 suspendEvents : function(queueSuspended){
2071 this.eventsSuspended = TRUE;
2072 if(queueSuspended && !this.eventQueue){
2073 this.eventQueue = [];
2078 * Resume firing events. (see {@link #suspendEvents})
2079 * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
2080 * events fired during event suspension will be sent to any listeners now.
2082 resumeEvents : function(){
2084 queued = me.eventQueue || [];
2085 me.eventsSuspended = FALSE;
2086 delete me.eventQueue;
2087 EACH(queued, function(e) {
2088 me.fireEvent.apply(me, e);
2093 var OBSERVABLE = EXTUTIL.Observable.prototype;
2095 * Appends an event handler to this object (shorthand for {@link #addListener}.)
2096 * @param {String} eventName The type of event to listen for
2097 * @param {Function} handler The method the event invokes
2098 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2099 * <b>If omitted, defaults to the object which fired the event.</b>
2100 * @param {Object} options (optional) An object containing handler configuration.
2103 OBSERVABLE.on = OBSERVABLE.addListener;
2105 * Removes an event handler (shorthand for {@link #removeListener}.)
2106 * @param {String} eventName The type of event the handler was associated with.
2107 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2108 * @param {Object} scope (optional) The scope originally specified for the handler.
2111 OBSERVABLE.un = OBSERVABLE.removeListener;
2114 * Removes <b>all</b> added captures from the Observable.
2115 * @param {Observable} o The Observable to release
2118 EXTUTIL.Observable.releaseCapture = function(o){
2119 o.fireEvent = OBSERVABLE.fireEvent;
2122 function createTargeted(h, o, scope){
2124 if(o.target == arguments[0]){
2125 h.apply(scope, TOARRAY(arguments));
2130 function createBuffered(h, o, scope){
2131 var task = new EXTUTIL.DelayedTask();
2133 task.delay(o.buffer, h, scope, TOARRAY(arguments));
2137 function createSingle(h, e, fn, scope){
2139 e.removeListener(fn, scope);
2140 return h.apply(scope, arguments);
2144 function createDelayed(h, o, scope){
2146 var args = TOARRAY(arguments);
2148 h.apply(scope, args);
2149 }).defer(o.delay || 10);
2153 EXTUTIL.Event = function(obj, name){
2156 this.listeners = [];
2159 EXTUTIL.Event.prototype = {
2160 addListener : function(fn, scope, options){
2163 scope = scope || me.obj;
2164 if(!me.isListening(fn, scope)){
2165 l = me.createListener(fn, scope, options);
2166 if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
2167 me.listeners = me.listeners.slice(0);
2169 me.listeners.push(l);
2173 createListener: function(fn, scope, o){
2174 o = o || {}, scope = scope || this.obj;
2181 h = createTargeted(h, o, scope);
2184 h = createDelayed(h, o, scope);
2187 h = createSingle(h, this, fn, scope);
2190 h = createBuffered(h, o, scope);
2196 findListener : function(fn, scope){
2198 EACH(this.listeners, function(l, i) {
2200 if(l.fn == fn && (s == scope || s == this.obj)){
2209 isListening : function(fn, scope){
2210 return this.findListener(fn, scope) != -1;
2213 removeListener : function(fn, scope){
2217 if((index = me.findListener(fn, scope)) != -1){
2219 me.listeners = me.listeners.slice(0);
2221 me.listeners.splice(index, 1);
2227 clearListeners : function(){
2228 this.listeners = [];
2233 args = TOARRAY(arguments),
2236 EACH(me.listeners, function(l) {
2238 if (l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
2239 return ret = me.firing = FALSE;
2247 * @class Ext.util.Observable
\r
2249 Ext.apply(Ext.util.Observable.prototype, function(){
\r
2250 // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
\r
2251 // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
\r
2253 function getMethodEvent(method){
\r
2254 var e = (this.methodEvents = this.methodEvents ||
\r
2255 {})[method], returnValue, v, cancel, obj = this;
\r
2258 this.methodEvents[method] = e = {};
\r
2259 e.originalFn = this[method];
\r
2260 e.methodName = method;
\r
2264 var makeCall = function(fn, scope, args){
\r
2265 if (!Ext.isEmpty(v = fn.apply(scope || obj, args))) {
\r
2266 if (Ext.isObject(v)) {
\r
2267 returnValue = !Ext.isEmpty(v.returnValue) ? v.returnValue : v;
\r
2268 cancel = !!v.cancel;
\r
2271 if (v === false) {
\r
2280 this[method] = function(){
\r
2281 var args = Ext.toArray(arguments);
\r
2282 returnValue = v = undefined;
\r
2285 Ext.each(e.before, function(b){
\r
2286 makeCall(b.fn, b.scope, args);
\r
2288 return returnValue;
\r
2292 if (!Ext.isEmpty(v = e.originalFn.apply(obj, args))) {
\r
2295 Ext.each(e.after, function(a){
\r
2296 makeCall(a.fn, a.scope, args);
\r
2298 return returnValue;
\r
2301 return returnValue;
\r
2308 // these are considered experimental
\r
2309 // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
\r
2310 // adds an "interceptor" called before the original method
\r
2311 beforeMethod: function(method, fn, scope){
\r
2312 getMethodEvent.call(this, method).before.push({
\r
2318 // adds a "sequence" called after the original method
\r
2319 afterMethod: function(method, fn, scope){
\r
2320 getMethodEvent.call(this, method).after.push({
\r
2326 removeMethodListener: function(method, fn, scope){
\r
2327 var e = getMethodEvent.call(this, method), found = false;
\r
2328 Ext.each(e.before, function(b, i, arr){
\r
2329 if (b.fn == fn && b.scope == scope) {
\r
2336 Ext.each(e.after, function(a, i, arr){
\r
2337 if (a.fn == fn && a.scope == scope) {
\r
2346 * Relays selected events from the specified Observable as if the events were fired by <tt><b>this</b></tt>.
\r
2347 * @param {Object} o The Observable whose events this object is to relay.
\r
2348 * @param {Array} events Array of event names to relay.
\r
2350 relayEvents: function(o, events){
\r
2352 function createHandler(ename){
\r
2353 return function(){
\r
2354 return me.fireEvent.apply(me, [ename].concat(Ext.toArray(arguments)));
\r
2357 Ext.each(events, function(ename){
\r
2358 me.events[ename] = me.events[ename] || true;
\r
2359 o.on(ename, createHandler(ename), me);
\r
2364 * <p>Enables events fired by this Observable to bubble up an owner hierarchy by calling
\r
2365 * <code>this.getBubbleTarget()</code> if present. There is no implementation in the Observable base class.</p>
\r
2366 * <p>This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component.getBubbleTarget}. The default
\r
2367 * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to
\r
2368 * access the required target more quickly.</p>
\r
2369 * <p>Example:</p><pre><code>
\r
2370 Ext.override(Ext.form.Field, {
\r
2371 // Add functionality to Field's initComponent to enable the change event to bubble
\r
2372 initComponent: Ext.form.Field.prototype.initComponent.createSequence(function() {
\r
2373 this.enableBubble('change');
\r
2376 // We know that we want Field's events to bubble directly to the FormPanel.
\r
2377 getBubbleTarget: function() {
\r
2378 if (!this.formPanel) {
\r
2379 this.formPanel = this.findParentByType('form');
\r
2381 return this.formPanel;
\r
2385 var myForm = new Ext.formPanel({
\r
2386 title: 'User Details',
\r
2391 change: function() {
\r
2392 // Title goes red if form has been modified.
\r
2393 myForm.header.setStyle("color", "red");
\r
2398 * @param {Object} events The event name to bubble, or an Array of event names.
\r
2400 enableBubble: function(events){
\r
2402 if(!Ext.isEmpty(events)){
\r
2403 events = Ext.isArray(events) ? events : Ext.toArray(arguments);
\r
2404 Ext.each(events, function(ename){
\r
2405 ename = ename.toLowerCase();
\r
2406 var ce = me.events[ename] || true;
\r
2407 if (Ext.isBoolean(ce)) {
\r
2408 ce = new Ext.util.Event(me, ename);
\r
2409 me.events[ename] = ce;
\r
2420 * Starts capture on the specified Observable. All events will be passed
\r
2421 * to the supplied function with the event name + standard signature of the event
\r
2422 * <b>before</b> the event is fired. If the supplied function returns false,
\r
2423 * the event will not fire.
\r
2424 * @param {Observable} o The Observable to capture
\r
2425 * @param {Function} fn The function to call
\r
2426 * @param {Object} scope (optional) The scope (this object) for the fn
\r
2429 Ext.util.Observable.capture = function(o, fn, scope){
\r
2430 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
\r
2435 * Sets observability on the passed class constructor.<p>
\r
2436 * <p>This makes any event fired on any instance of the passed class also fire a single event through
\r
2437 * the <i>class</i> allowing for central handling of events on many instances at once.</p>
\r
2438 * <p>Usage:</p><pre><code>
\r
2439 Ext.util.Observable.observeClass(Ext.data.Connection);
\r
2440 Ext.data.Connection.on('beforerequest', function(con, options) {
\r
2441 console.log("Ajax request made to " + options.url);
\r
2443 * @param {Function} c The class constructor to make observable.
\r
2446 Ext.util.Observable.observeClass = function(c){
\r
2447 Ext.apply(c, new Ext.util.Observable());
\r
2448 c.prototype.fireEvent = function(){
\r
2449 return (c.fireEvent.apply(c, arguments) !== false) &&
\r
2450 (Ext.util.Observable.prototype.fireEvent.apply(this, arguments) !== false);
\r
2453 * @class Ext.EventManager
2454 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
2455 * several useful events directly.
2456 * See {@link Ext.EventObject} for more details on normalized event objects.
2459 Ext.EventManager = function(){
2462 docReadyState = false,
2467 IEDEFERED = "ie-deferred-loader",
2468 DOMCONTENTLOADED = "DOMContentLoaded",
2470 propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
2472 /// There is some jquery work around stuff here that isn't needed in Ext Core.
2473 function addListener(el, ename, fn, wrap, scope){
2474 var id = Ext.id(el),
2475 es = elHash[id] = elHash[id] || {};
2477 (es[ename] = es[ename] || []).push([fn, wrap, scope]);
2478 E.on(el, ename, wrap);
2480 // this is a workaround for jQuery and should somehow be removed from Ext Core in the future
2481 // without breaking ExtJS.
2482 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
2483 var args = ["DOMMouseScroll", wrap, false];
2484 el.addEventListener.apply(el, args);
2485 E.on(window, 'unload', function(){
2486 el.removeEventListener.apply(el, args);
2489 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
2490 Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
2494 function fireDocReady(){
2496 Ext.isReady = docReadyState = true;
2498 clearInterval(docReadyProcId);
2500 if(Ext.isGecko || Ext.isOpera) {
2501 DOC.removeEventListener(DOMCONTENTLOADED, fireDocReady, false);
2504 var defer = DOC.getElementById(IEDEFERED);
2506 defer.onreadystatechange = null;
2507 defer.parentNode.removeChild(defer);
2511 docReadyEvent.fire();
2512 docReadyEvent.clearListeners();
2517 function initDocReady(){
2518 var COMPLETE = "complete";
2520 docReadyEvent = new Ext.util.Event();
2521 if (Ext.isGecko || Ext.isOpera) {
2522 DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false);
2523 } else if (Ext.isIE){
2524 DOC.write("<s"+'cript id=' + IEDEFERED + ' defer="defer" src="/'+'/:"></s'+"cript>");
2525 DOC.getElementById(IEDEFERED).onreadystatechange = function(){
2526 if(this.readyState == COMPLETE){
2530 } else if (Ext.isWebKit){
2531 docReadyProcId = setInterval(function(){
2532 if(DOC.readyState == COMPLETE) {
2537 // no matter what, make sure it fires on load
2538 E.on(WINDOW, "load", fireDocReady);
2541 function createTargeted(h, o){
2543 var args = Ext.toArray(arguments);
2544 if(o.target == Ext.EventObject.setEvent(args[0]).target){
2545 h.apply(this, args);
2550 function createBuffered(h, o){
2551 var task = new Ext.util.DelayedTask(h);
2553 // create new event object impl so new events don't wipe out properties
2554 task.delay(o.buffer, h, null, [new Ext.EventObjectImpl(e)]);
2558 function createSingle(h, el, ename, fn, scope){
2560 Ext.EventManager.removeListener(el, ename, fn, scope);
2565 function createDelayed(h, o){
2567 // create new event object impl so new events don't wipe out properties
2568 e = new Ext.EventObjectImpl(e);
2569 setTimeout(function(){
2575 function listen(element, ename, opt, fn, scope){
2576 var o = !Ext.isObject(opt) ? {} : opt,
2577 el = Ext.getDom(element);
2580 scope = scope || o.scope;
2583 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
2586 // prevent errors while unload occurring
2587 if(!Ext){// !window[xname]){ ==> can't we do this?
2590 e = Ext.EventObject.setEvent(e);
2593 if(!(t = e.getTarget(o.delegate, el))){
2602 if (o.preventDefault) {
2605 if (o.stopPropagation) {
2606 e.stopPropagation();
2612 fn.call(scope || el, e, t, o);
2615 h = createTargeted(h, o);
2618 h = createDelayed(h, o);
2621 h = createSingle(h, el, ename, fn, scope);
2624 h = createBuffered(h, o);
2627 addListener(el, ename, fn, h, scope);
2633 * Appends an event handler to an element. The shorthand version {@link #on} is equivalent. Typically you will
2634 * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
2635 * @param {String/HTMLElement} el The html element or id to assign the event handler to.
2636 * @param {String} eventName The name of the event to listen for.
2637 * @param {Function} handler The handler function the event invokes. This function is passed
2638 * the following parameters:<ul>
2639 * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
2640 * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
2641 * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
2642 * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
2644 * @param {Object} scope (optional) The scope (<b><code>this</code></b> reference) in which the handler function is executed. <b>Defaults to the Element</b>.
2645 * @param {Object} options (optional) An object containing handler configuration properties.
2646 * This may contain any of the following properties:<ul>
2647 * <li>scope : Object<div class="sub-desc">The scope (<b><code>this</code></b> reference) in which the handler function is executed. <b>Defaults to the Element</b>.</div></li>
2648 * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
2649 * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
2650 * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
2651 * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
2652 * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
2653 * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
2654 * <li>single : Boolean<div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
2655 * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
2656 * by the specified number of milliseconds. If the event fires again within that time, the original
2657 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
2658 * <li>target : Element<div class="sub-desc">Only call the handler if the event was fired on the target Element, <i>not</i> if the event was bubbled up from a child node.</div></li>
2660 * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
2662 addListener : function(element, eventName, fn, scope, options){
2663 if(Ext.isObject(eventName)){
2664 var o = eventName, e, val;
2667 if(!propRe.test(e)){
2668 if(Ext.isFunction(val)){
2670 listen(element, e, o, val, o.scope);
2672 // individual options
2673 listen(element, e, val);
2678 listen(element, eventName, options, fn, scope);
2683 * Removes an event handler from an element. The shorthand version {@link #un} is equivalent. Typically
2684 * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
2685 * @param {String/HTMLElement} el The id or html element from which to remove the listener.
2686 * @param {String} eventName The name of the event.
2687 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2688 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
2689 * then this must refer to the same object.
2691 removeListener : function(element, eventName, fn, scope){
2692 var el = Ext.getDom(element),
2696 Ext.each((elHash[id] || {})[eventName], function (v,i,a) {
2697 if (Ext.isArray(v) && v[0] == fn && (!scope || v[2] == scope)) {
2698 E.un(el, eventName, wrap = v[1]);
2704 // jQuery workaround that should be removed from Ext Core
2705 if(eventName == "mousewheel" && el.addEventListener && wrap){
2706 el.removeEventListener("DOMMouseScroll", wrap, false);
2709 if(eventName == "mousedown" && el == DOC && wrap){ // fix stopped mousedowns on the document
2710 Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
2715 * Removes all event handers from an element. Typically you will use {@link Ext.Element#removeAllListeners}
2716 * directly on an Element in favor of calling this version.
2717 * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
2719 removeAll : function(el){
2720 var id = Ext.id(el = Ext.getDom(el)),
2725 if(es.hasOwnProperty(ename)){
2726 Ext.each(es[ename], function(v) {
2727 E.un(el, ename, v.wrap);
2735 * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
2736 * accessed shorthanded as Ext.onReady().
2737 * @param {Function} fn The method the event invokes.
2738 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
2739 * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
2740 * <code>{single: true}</code> be used so that the handler is removed on first invocation.
2742 onDocumentReady : function(fn, scope, options){
2743 if(docReadyState){ // if it already fired
2744 docReadyEvent.addListener(fn, scope, options);
2745 docReadyEvent.fire();
2746 docReadyEvent.clearListeners();
2748 if(!docReadyEvent) initDocReady();
2749 options = options || {};
2750 options.delay = options.delay || 1;
2751 docReadyEvent.addListener(fn, scope, options);
2758 * Appends an event handler to an element. Shorthand for {@link #addListener}.
2759 * @param {String/HTMLElement} el The html element or id to assign the event handler to
2760 * @param {String} eventName The name of the event to listen for.
2761 * @param {Function} handler The handler function the event invokes.
2762 * @param {Object} scope (optional) (<code>this</code> reference) in which the handler function executes. <b>Defaults to the Element</b>.
2763 * @param {Object} options (optional) An object containing standard {@link #addListener} options
2764 * @member Ext.EventManager
2767 pub.on = pub.addListener;
2769 * Removes an event handler from an element. Shorthand for {@link #removeListener}.
2770 * @param {String/HTMLElement} el The id or html element from which to remove the listener.
2771 * @param {String} eventName The name of the event.
2772 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #on} call.</b>
2773 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
2774 * then this must refer to the same object.
2775 * @member Ext.EventManager
2778 pub.un = pub.removeListener;
2780 pub.stoppedMouseDownEvent = new Ext.util.Event();
2784 * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}.
2785 * @param {Function} fn The method the event invokes.
2786 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
2787 * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
2788 * <code>{single: true}</code> be used so that the handler is removed on first invocation.
2792 Ext.onReady = Ext.EventManager.onDocumentReady;
2795 //Initialize doc classes
2798 var initExtCss = function(){
2799 // find the body element
2800 var bd = document.body || document.getElementsByTagName('body')[0];
2801 if(!bd){ return false; }
2803 Ext.isIE ? "ext-ie " + (Ext.isIE6 ? 'ext-ie6' : (Ext.isIE7 ? 'ext-ie7' : 'ext-ie8'))
2804 : Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? 'ext-gecko2' : 'ext-gecko3')
2805 : Ext.isOpera ? "ext-opera"
2806 : Ext.isWebKit ? "ext-webkit" : ""];
2809 cls.push("ext-safari " + (Ext.isSafari2 ? 'ext-safari2' : (Ext.isSafari3 ? 'ext-safari3' : 'ext-safari4')));
2810 }else if(Ext.isChrome){
2811 cls.push("ext-chrome");
2815 cls.push("ext-mac");
2818 cls.push("ext-linux");
2821 if(Ext.isStrict || Ext.isBorderBox){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
2822 var p = bd.parentNode;
2824 p.className += Ext.isStrict ? ' ext-strict' : ' ext-border-box';
2827 bd.className += cls.join(' ');
2832 Ext.onReady(initExtCss);
2838 * @class Ext.EventObject
2839 * Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject
2840 * wraps the browser's native event-object normalizing cross-browser differences,
2841 * such as which mouse button is clicked, keys pressed, mechanisms to stop
2842 * event-propagation along with a method to prevent default actions from taking place.
2843 * <p>For example:</p>
2845 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
2847 var target = e.getTarget(); // same as t (the target HTMLElement)
2850 var myDiv = {@link Ext#get Ext.get}("myDiv"); // get reference to an {@link Ext.Element}
2851 myDiv.on( // 'on' is shorthand for addListener
2852 "click", // perform an action on click of myDiv
2853 handleClick // reference to the action handler
2855 // other methods to do the same:
2856 Ext.EventManager.on("myDiv", 'click', handleClick);
2857 Ext.EventManager.addListener("myDiv", 'click', handleClick);
2861 Ext.EventObject = function(){
2862 var E = Ext.lib.Event,
2863 // safari keypress events for special keys return bad keycodes
2867 63235 : 39, // right
2870 63276 : 33, // page up
2871 63277 : 34, // page down
2872 63272 : 46, // delete
2876 // normalize button clicks
2877 btnMap = Ext.isIE ? {1:0,4:1,2:2} :
2878 (Ext.isWebKit ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
2880 Ext.EventObjectImpl = function(e){
2882 this.setEvent(e.browserEvent || e);
2886 Ext.EventObjectImpl.prototype = {
2888 setEvent : function(e){
2890 if(e == me || (e && e.browserEvent)){ // already wrapped
2893 me.browserEvent = e;
2895 // normalize buttons
2896 me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);
2897 if(e.type == 'click' && me.button == -1){
2901 me.shiftKey = e.shiftKey;
2902 // mac metaKey behaves like ctrlKey
2903 me.ctrlKey = e.ctrlKey || e.metaKey || false;
2904 me.altKey = e.altKey;
2905 // in getKey these will be normalized for the mac
2906 me.keyCode = e.keyCode;
2907 me.charCode = e.charCode;
2908 // cache the target for the delayed and or buffered events
2909 me.target = E.getTarget(e);
2914 me.shiftKey = false;
2926 * Stop the event (preventDefault and stopPropagation)
2928 stopEvent : function(){
2930 if(me.browserEvent){
2931 if(me.browserEvent.type == 'mousedown'){
2932 Ext.EventManager.stoppedMouseDownEvent.fire(me);
2934 E.stopEvent(me.browserEvent);
2939 * Prevents the browsers default handling of the event.
2941 preventDefault : function(){
2942 if(this.browserEvent){
2943 E.preventDefault(this.browserEvent);
2948 * Cancels bubbling of the event.
2950 stopPropagation : function(){
2952 if(me.browserEvent){
2953 if(me.browserEvent.type == 'mousedown'){
2954 Ext.EventManager.stoppedMouseDownEvent.fire(me);
2956 E.stopPropagation(me.browserEvent);
2961 * Gets the character code for the event.
2964 getCharCode : function(){
2965 return this.charCode || this.keyCode;
2969 * Returns a normalized keyCode for the event.
2970 * @return {Number} The key code
2972 getKey : function(){
2973 return this.normalizeKey(this.keyCode || this.charCode)
2977 normalizeKey: function(k){
2978 return Ext.isSafari ? (safariKeys[k] || k) : k;
2982 * Gets the x coordinate of the event.
2985 getPageX : function(){
2990 * Gets the y coordinate of the event.
2993 getPageY : function(){
2998 * Gets the page coordinates of the event.
2999 * @return {Array} The xy values like [x, y]
3006 * Gets the target for the event.
3007 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
3008 * @param {Number/Mixed} maxDepth (optional) The max depth to
3009 search as a number or element (defaults to 10 || document.body)
3010 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
3011 * @return {HTMLelement}
3013 getTarget : function(selector, maxDepth, returnEl){
3014 return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);
3018 * Gets the related target.
3019 * @return {HTMLElement}
3021 getRelatedTarget : function(){
3022 return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;
3026 * Normalizes mouse wheel delta across browsers
3027 * @return {Number} The delta
3029 getWheelDelta : function(){
3030 var e = this.browserEvent;
3032 if(e.wheelDelta){ /* IE/Opera. */
3033 delta = e.wheelDelta/120;
3034 }else if(e.detail){ /* Mozilla case. */
3035 delta = -e.detail/3;
3041 * 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.
3042 * Example usage:<pre><code>
3043 // Handle click on any child of an element
3044 Ext.getBody().on('click', function(e){
3045 if(e.within('some-el')){
3046 alert('Clicked on a child of some-el!');
3050 // Handle click directly on an element, ignoring clicks on child nodes
3051 Ext.getBody().on('click', function(e,t){
3052 if((t.id == 'some-el') && !e.within(t, true)){
3053 alert('Clicked directly on some-el!');
3057 * @param {Mixed} el The id, DOM element or Ext.Element to check
3058 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
3059 * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
3062 within : function(el, related, allowEl){
3064 var t = this[related ? "getRelatedTarget" : "getTarget"]();
3065 return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));
3071 return new Ext.EventObjectImpl();
3073 * @class Ext.EventManager
\r
3075 Ext.apply(Ext.EventManager, function(){
\r
3081 E = Ext.lib.Event,
\r
3082 propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
\r
3085 // note 1: IE fires ONLY the keydown event on specialkey autorepeat
\r
3086 // note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat
\r
3087 // (research done by @Jan Wolter at http://unixpapa.com/js/key.html)
\r
3088 useKeydown = Ext.isWebKit ?
\r
3089 Ext.num(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1]) >= 525 :
\r
3090 !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera);
\r
3094 doResizeEvent: function(){
\r
3095 var h = D.getViewHeight(),
\r
3096 w = D.getViewWidth();
\r
3098 //whacky problem in IE where the resize event will fire even though the w/h are the same.
\r
3099 if(curHeight != h || curWidth != w){
\r
3100 resizeEvent.fire(curWidth = w, curHeight = h);
\r
3105 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
\r
3106 * @param {Function} fn The method the event invokes
\r
3107 * @param {Object} scope An object that becomes the scope of the handler
\r
3108 * @param {boolean} options
\r
3110 onWindowResize : function(fn, scope, options){
\r
3112 resizeEvent = new Ext.util.Event();
\r
3113 resizeTask = new Ext.util.DelayedTask(this.doResizeEvent);
\r
3114 E.on(window, "resize", this.fireWindowResize, this);
\r
3116 resizeEvent.addListener(fn, scope, options);
\r
3119 // exposed only to allow manual firing
\r
3120 fireWindowResize : function(){
\r
3122 if((Ext.isIE||Ext.isAir) && resizeTask){
\r
3123 resizeTask.delay(50);
\r
3125 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
\r
3131 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
\r
3132 * @param {Function} fn The method the event invokes
\r
3133 * @param {Object} scope An object that becomes the scope of the handler
\r
3134 * @param {boolean} options
\r
3136 onTextResize : function(fn, scope, options){
\r
3138 textEvent = new Ext.util.Event();
\r
3139 var textEl = new Ext.Element(document.createElement('div'));
\r
3140 textEl.dom.className = 'x-text-resize';
\r
3141 textEl.dom.innerHTML = 'X';
\r
3142 textEl.appendTo(document.body);
\r
3143 textSize = textEl.dom.offsetHeight;
\r
3144 setInterval(function(){
\r
3145 if(textEl.dom.offsetHeight != textSize){
\r
3146 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
\r
3148 }, this.textResizeInterval);
\r
3150 textEvent.addListener(fn, scope, options);
\r
3154 * Removes the passed window resize listener.
\r
3155 * @param {Function} fn The method the event invokes
\r
3156 * @param {Object} scope The scope of handler
\r
3158 removeResizeListener : function(fn, scope){
\r
3160 resizeEvent.removeListener(fn, scope);
\r
3165 fireResize : function(){
\r
3167 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
\r
3172 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
\r
3174 textResizeInterval : 50,
\r
3177 * Url used for onDocumentReady with using SSL (defaults to Ext.SSL_SECURE_URL)
\r
3179 ieDeferSrc : false,
\r
3181 // protected for use inside the framework
\r
3182 // detects whether we should use keydown or keypress based on the browser.
\r
3183 useKeydown: useKeydown
\r
3187 Ext.EventManager.on = Ext.EventManager.addListener;
\r
3190 Ext.apply(Ext.EventObjectImpl.prototype, {
\r
3191 /** Key constant @type Number */
\r
3193 /** Key constant @type Number */
\r
3195 /** Key constant @type Number */
\r
3197 /** Key constant @type Number */
\r
3199 /** Key constant @type Number */
\r
3201 /** Key constant @type Number */
\r
3203 /** Key constant @type Number */
\r
3205 CONTROL : 17, // legacy
\r
3206 /** Key constant @type Number */
\r
3208 /** Key constant @type Number */
\r
3210 /** Key constant @type Number */
\r
3212 /** Key constant @type Number */
\r
3214 /** Key constant @type Number */
\r
3216 /** Key constant @type Number */
\r
3218 PAGEUP : 33, // legacy
\r
3219 /** Key constant @type Number */
\r
3221 PAGEDOWN : 34, // legacy
\r
3222 /** Key constant @type Number */
\r
3224 /** Key constant @type Number */
\r
3226 /** Key constant @type Number */
\r
3228 /** Key constant @type Number */
\r
3230 /** Key constant @type Number */
\r
3232 /** Key constant @type Number */
\r
3234 /** Key constant @type Number */
\r
3236 /** Key constant @type Number */
\r
3238 /** Key constant @type Number */
\r
3240 /** Key constant @type Number */
\r
3242 /** Key constant @type Number */
\r
3244 /** Key constant @type Number */
\r
3246 /** Key constant @type Number */
\r
3248 /** Key constant @type Number */
\r
3250 /** Key constant @type Number */
\r
3252 /** Key constant @type Number */
\r
3254 /** Key constant @type Number */
\r
3256 /** Key constant @type Number */
\r
3258 /** Key constant @type Number */
\r
3260 /** Key constant @type Number */
\r
3262 /** Key constant @type Number */
\r
3264 /** Key constant @type Number */
\r
3266 /** Key constant @type Number */
\r
3268 /** Key constant @type Number */
\r
3270 /** Key constant @type Number */
\r
3272 /** Key constant @type Number */
\r
3274 /** Key constant @type Number */
\r
3276 /** Key constant @type Number */
\r
3278 /** Key constant @type Number */
\r
3280 /** Key constant @type Number */
\r
3282 /** Key constant @type Number */
\r
3284 /** Key constant @type Number */
\r
3286 /** Key constant @type Number */
\r
3288 /** Key constant @type Number */
\r
3290 /** Key constant @type Number */
\r
3292 /** Key constant @type Number */
\r
3294 /** Key constant @type Number */
\r
3296 /** Key constant @type Number */
\r
3298 /** Key constant @type Number */
\r
3300 /** Key constant @type Number */
\r
3302 /** Key constant @type Number */
\r
3304 /** Key constant @type Number */
\r
3306 /** Key constant @type Number */
\r
3308 /** Key constant @type Number */
\r
3310 /** Key constant @type Number */
\r
3312 /** Key constant @type Number */
\r
3314 /** Key constant @type Number */
\r
3316 /** Key constant @type Number */
\r
3318 /** Key constant @type Number */
\r
3320 /** Key constant @type Number */
\r
3322 /** Key constant @type Number */
\r
3324 /** Key constant @type Number */
\r
3326 /** Key constant @type Number */
\r
3328 /** Key constant @type Number */
\r
3330 /** Key constant @type Number */
\r
3332 /** Key constant @type Number */
\r
3334 /** Key constant @type Number */
\r
3335 NUM_MULTIPLY: 106,
\r
3336 /** Key constant @type Number */
\r
3338 /** Key constant @type Number */
\r
3340 /** Key constant @type Number */
\r
3342 /** Key constant @type Number */
\r
3343 NUM_DIVISION: 111,
\r
3344 /** Key constant @type Number */
\r
3346 /** Key constant @type Number */
\r
3348 /** Key constant @type Number */
\r
3350 /** Key constant @type Number */
\r
3352 /** Key constant @type Number */
\r
3354 /** Key constant @type Number */
\r
3356 /** Key constant @type Number */
\r
3358 /** Key constant @type Number */
\r
3360 /** Key constant @type Number */
\r
3362 /** Key constant @type Number */
\r
3364 /** Key constant @type Number */
\r
3366 /** Key constant @type Number */
\r
3370 isNavKeyPress : function(){
\r
3372 k = this.normalizeKey(me.keyCode);
\r
3373 return (k >= 33 && k <= 40) || // Page Up/Down, End, Home, Left, Up, Right, Down
\r
3379 isSpecialKey : function(){
\r
3380 var k = this.normalizeKey(this.keyCode);
\r
3381 return (this.type == 'keypress' && this.ctrlKey) ||
\r
3382 this.isNavKeyPress() ||
\r
3383 (k == this.BACKSPACE) || // Backspace
\r
3384 (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
\r
3385 (k >= 44 && k <= 45); // Print Screen, Insert
\r
3388 getPoint : function(){
\r
3389 return new Ext.lib.Point(this.xy[0], this.xy[1]);
\r
3393 * Returns true if the control, meta, shift or alt key was pressed during this event.
\r
3394 * @return {Boolean}
\r
3396 hasModifier : function(){
\r
3397 return ((this.ctrlKey || this.altKey) || this.shiftKey);
\r
3400 * @class Ext.Element
\r
3401 * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>
\r
3402 * <p>All instances of this class inherit the methods of {@link Ext.Fx} making visual effects easily available to all DOM elements.</p>
\r
3403 * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To
\r
3404 * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older
\r
3405 * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>
\r
3409 var el = Ext.get("my-div");
\r
3411 // by DOM element reference
\r
3412 var el = Ext.get(myDivElement);
\r
3414 * <b>Animations</b><br />
\r
3415 * <p>When an element is manipulated, by default there is no animation.</p>
\r
3417 var el = Ext.get("my-div");
\r
3422 * <p>Many of the functions for manipulating an element have an optional "animate" parameter. This
\r
3423 * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>
\r
3425 // default animation
\r
3426 el.setWidth(100, true);
\r
3429 * <p>To configure the effects, an object literal with animation options to use as the Element animation
\r
3430 * configuration object can also be specified. Note that the supported Element animation configuration
\r
3431 * options are a subset of the {@link Ext.Fx} animation options specific to Fx effects. The supported
\r
3432 * Element animation configuration options are:</p>
\r
3434 Option Default Description
\r
3435 --------- -------- ---------------------------------------------
\r
3436 {@link Ext.Fx#duration duration} .35 The duration of the animation in seconds
\r
3437 {@link Ext.Fx#easing easing} easeOut The easing method
\r
3438 {@link Ext.Fx#callback callback} none A function to execute when the anim completes
\r
3439 {@link Ext.Fx#scope scope} this The scope (this) of the callback function
\r
3443 // Element animation options object
\r
3445 {@link Ext.Fx#duration duration}: 1,
\r
3446 {@link Ext.Fx#easing easing}: 'elasticIn',
\r
3447 {@link Ext.Fx#callback callback}: this.foo,
\r
3448 {@link Ext.Fx#scope scope}: this
\r
3450 // animation with some options set
\r
3451 el.setWidth(100, opt);
\r
3453 * <p>The Element animation object being used for the animation will be set on the options
\r
3454 * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>
\r
3456 // using the "anim" property to get the Anim object
\r
3457 if(opt.anim.isAnimated()){
\r
3461 * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>
\r
3462 * <p><b> Composite (Collections of) Elements</b></p>
\r
3463 * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>
\r
3464 * @constructor Create a new Element directly.
\r
3465 * @param {String/HTMLElement} element
\r
3466 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
\r
3469 var DOC = document;
\r
3471 Ext.Element = function(element, forceNew){
\r
3472 var dom = typeof element == "string" ?
\r
3473 DOC.getElementById(element) : element,
\r
3476 if(!dom) return null;
\r
3480 if(!forceNew && id && Ext.Element.cache[id]){ // element object already exists
\r
3481 return Ext.Element.cache[id];
\r
3486 * @type HTMLElement
\r
3491 * The DOM element ID
\r
3494 this.id = id || Ext.id(dom);
\r
3497 var D = Ext.lib.Dom,
\r
3498 DH = Ext.DomHelper,
\r
3499 E = Ext.lib.Event,
\r
3505 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
\r
3506 * @param {Object} o The object with the attributes
\r
3507 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
\r
3508 * @return {Ext.Element} this
\r
3510 set : function(o, useSet){
\r
3511 var el = this.dom,
\r
3517 if (attr != "style" && !Ext.isFunction(val)) {
\r
3518 if (attr == "cls" ) {
\r
3519 el.className = val;
\r
3520 } else if (o.hasOwnProperty(attr)) {
\r
3521 if (useSet || !!el.setAttribute) el.setAttribute(attr, val);
\r
3522 else el[attr] = val;
\r
3527 DH.applyStyles(el, o.style);
\r
3535 * Fires when a mouse click is detected within the element.
\r
3536 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3537 * @param {HtmlElement} t The target of the event.
\r
3538 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3541 * @event contextmenu
\r
3542 * Fires when a right click is detected within the element.
\r
3543 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3544 * @param {HtmlElement} t The target of the event.
\r
3545 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3549 * Fires when a mouse double click is detected within the element.
\r
3550 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3551 * @param {HtmlElement} t The target of the event.
\r
3552 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3555 * @event mousedown
\r
3556 * Fires when a mousedown is detected within the element.
\r
3557 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3558 * @param {HtmlElement} t The target of the event.
\r
3559 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3563 * Fires when a mouseup is detected within the element.
\r
3564 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3565 * @param {HtmlElement} t The target of the event.
\r
3566 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3569 * @event mouseover
\r
3570 * Fires when a mouseover is detected within the element.
\r
3571 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3572 * @param {HtmlElement} t The target of the event.
\r
3573 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3576 * @event mousemove
\r
3577 * Fires when a mousemove is detected with the element.
\r
3578 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3579 * @param {HtmlElement} t The target of the event.
\r
3580 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3584 * Fires when a mouseout is detected with the element.
\r
3585 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3586 * @param {HtmlElement} t The target of the event.
\r
3587 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3590 * @event mouseenter
\r
3591 * Fires when the mouse enters the element.
\r
3592 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3593 * @param {HtmlElement} t The target of the event.
\r
3594 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3597 * @event mouseleave
\r
3598 * Fires when the mouse leaves the element.
\r
3599 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3600 * @param {HtmlElement} t The target of the event.
\r
3601 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3604 // Keyboard events
\r
3607 * Fires when a keypress is detected within the element.
\r
3608 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3609 * @param {HtmlElement} t The target of the event.
\r
3610 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3614 * Fires when a keydown is detected within the element.
\r
3615 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3616 * @param {HtmlElement} t The target of the event.
\r
3617 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3621 * Fires when a keyup is detected within the element.
\r
3622 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3623 * @param {HtmlElement} t The target of the event.
\r
3624 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3628 // HTML frame/object events
\r
3631 * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.
\r
3632 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3633 * @param {HtmlElement} t The target of the event.
\r
3634 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3638 * Fires when the user agent removes all content from a window or frame. For elements, it fires when the target element or any of its content has been removed.
\r
3639 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3640 * @param {HtmlElement} t The target of the event.
\r
3641 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3645 * Fires when an object/image is stopped from loading before completely loaded.
\r
3646 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3647 * @param {HtmlElement} t The target of the event.
\r
3648 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3652 * Fires when an object/image/frame cannot be loaded properly.
\r
3653 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3654 * @param {HtmlElement} t The target of the event.
\r
3655 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3659 * Fires when a document view is resized.
\r
3660 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3661 * @param {HtmlElement} t The target of the event.
\r
3662 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3666 * Fires when a document view is scrolled.
\r
3667 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3668 * @param {HtmlElement} t The target of the event.
\r
3669 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3675 * Fires when a user selects some text in a text field, including input and textarea.
\r
3676 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3677 * @param {HtmlElement} t The target of the event.
\r
3678 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3682 * Fires when a control loses the input focus and its value has been modified since gaining focus.
\r
3683 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3684 * @param {HtmlElement} t The target of the event.
\r
3685 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3689 * Fires when a form is submitted.
\r
3690 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3691 * @param {HtmlElement} t The target of the event.
\r
3692 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3696 * Fires when a form is reset.
\r
3697 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3698 * @param {HtmlElement} t The target of the event.
\r
3699 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3703 * Fires when an element receives focus either via the pointing device or by tab navigation.
\r
3704 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3705 * @param {HtmlElement} t The target of the event.
\r
3706 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3710 * Fires when an element loses focus either via the pointing device or by tabbing navigation.
\r
3711 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3712 * @param {HtmlElement} t The target of the event.
\r
3713 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3716 // User Interface events
\r
3718 * @event DOMFocusIn
\r
3719 * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
\r
3720 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3721 * @param {HtmlElement} t The target of the event.
\r
3722 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3725 * @event DOMFocusOut
\r
3726 * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
\r
3727 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3728 * @param {HtmlElement} t The target of the event.
\r
3729 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3732 * @event DOMActivate
\r
3733 * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
\r
3734 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3735 * @param {HtmlElement} t The target of the event.
\r
3736 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3739 // DOM Mutation events
\r
3741 * @event DOMSubtreeModified
\r
3742 * Where supported. Fires when the subtree is modified.
\r
3743 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3744 * @param {HtmlElement} t The target of the event.
\r
3745 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3748 * @event DOMNodeInserted
\r
3749 * Where supported. Fires when a node has been added as a child of another node.
\r
3750 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3751 * @param {HtmlElement} t The target of the event.
\r
3752 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3755 * @event DOMNodeRemoved
\r
3756 * Where supported. Fires when a descendant node of the element is removed.
\r
3757 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3758 * @param {HtmlElement} t The target of the event.
\r
3759 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3762 * @event DOMNodeRemovedFromDocument
\r
3763 * Where supported. Fires when a node is being removed from a document.
\r
3764 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3765 * @param {HtmlElement} t The target of the event.
\r
3766 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3769 * @event DOMNodeInsertedIntoDocument
\r
3770 * Where supported. Fires when a node is being inserted into a document.
\r
3771 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3772 * @param {HtmlElement} t The target of the event.
\r
3773 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3776 * @event DOMAttrModified
\r
3777 * Where supported. Fires when an attribute has been modified.
\r
3778 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3779 * @param {HtmlElement} t The target of the event.
\r
3780 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3783 * @event DOMCharacterDataModified
\r
3784 * Where supported. Fires when the character data has been modified.
\r
3785 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
\r
3786 * @param {HtmlElement} t The target of the event.
\r
3787 * @param {Object} o The options configuration passed to the {@link #addListener} call.
\r
3791 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
\r
3794 defaultUnit : "px",
\r
3797 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
\r
3798 * @param {String} selector The simple selector to test
\r
3799 * @return {Boolean} True if this element matches the selector, else false
\r
3801 is : function(simpleSelector){
\r
3802 return Ext.DomQuery.is(this.dom, simpleSelector);
\r
3806 * Tries to focus the element. Any exceptions are caught and ignored.
\r
3807 * @param {Number} defer (optional) Milliseconds to defer the focus
\r
3808 * @return {Ext.Element} this
\r
3810 focus : function(defer, /* private */ dom) {
\r
3812 dom = dom || me.dom;
\r
3814 if(Number(defer)){
\r
3815 me.focus.defer(defer, null, [null, dom]);
\r
3824 * Tries to blur the element. Any exceptions are caught and ignored.
\r
3825 * @return {Ext.Element} this
\r
3827 blur : function() {
\r
3835 * Returns the value of the "value" attribute
\r
3836 * @param {Boolean} asNumber true to parse the value as a number
\r
3837 * @return {String/Number}
\r
3839 getValue : function(asNumber){
\r
3840 var val = this.dom.value;
\r
3841 return asNumber ? parseInt(val, 10) : val;
\r
3845 * Appends an event handler to this element. The shorthand version {@link #on} is equivalent.
\r
3846 * @param {String} eventName The name of event to handle.
\r
3847 * @param {Function} fn The handler function the event invokes. This function is passed
\r
3848 * the following parameters:<ul>
\r
3849 * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
\r
3850 * <li><b>el</b> : HtmlElement<div class="sub-desc">The DOM element which was the target of the event.
\r
3851 * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
\r
3852 * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>
\r
3854 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
\r
3855 * <b>If omitted, defaults to this Element.</b>.
\r
3856 * @param {Object} options (optional) An object containing handler configuration properties.
\r
3857 * This may contain any of the following properties:<ul>
\r
3858 * <li><b>scope</b> Object : <div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
\r
3859 * <b>If omitted, defaults to this Element.</b></div></li>
\r
3860 * <li><b>delegate</b> String: <div class="sub-desc">A simple selector to filter the target or look for a descendant of the target. See below for additional details.</div></li>
\r
3861 * <li><b>stopEvent</b> Boolean: <div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
\r
3862 * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>
\r
3863 * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>
\r
3864 * <li><b>normalized</b> Boolean: <div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
\r
3865 * <li><b>target</b> Ext.Element: <div class="sub-desc">Only call the handler if the event was fired on the target Element, <i>not</i> if the event was bubbled up from a child node.</div></li>
\r
3866 * <li><b>delay</b> Number: <div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
\r
3867 * <li><b>single</b> Boolean: <div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
\r
3868 * <li><b>buffer</b> Number: <div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
\r
3869 * by the specified number of milliseconds. If the event fires again within that time, the original
\r
3870 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
\r
3873 * <b>Combining Options</b><br>
\r
3874 * In the following examples, the shorthand form {@link #on} is used rather than the more verbose
\r
3875 * addListener. The two are equivalent. Using the options argument, it is possible to combine different
\r
3876 * types of listeners:<br>
\r
3878 * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the
\r
3879 * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">
\r
3880 * Code:<pre><code>
\r
3881 el.on('click', this.onClick, this, {
\r
3886 });</code></pre></p>
\r
3888 * <b>Attaching multiple handlers in 1 call</b><br>
\r
3889 * The method also allows for a single argument to be passed which is a config object containing properties
\r
3890 * which specify multiple handlers.</p>
\r
3892 * Code:<pre><code>
\r
3900 fn: this.onMouseOver,
\r
3904 fn: this.onMouseOut,
\r
3909 * Or a shorthand syntax:<br>
\r
3910 * Code:<pre><code></p>
\r
3912 'click' : this.onClick,
\r
3913 'mouseover' : this.onMouseOver,
\r
3914 'mouseout' : this.onMouseOut,
\r
3917 * </code></pre></p>
\r
3918 * <p><b>delegate</b></p>
\r
3919 * <p>This is a configuration option that you can pass along when registering a handler for
\r
3920 * an event to assist with event delegation. Event delegation is a technique that is used to
\r
3921 * reduce memory consumption and prevent exposure to memory-leaks. By registering an event
\r
3922 * for a container element as opposed to each element within a container. By setting this
\r
3923 * configuration option to a simple selector, the target element will be filtered to look for
\r
3924 * a descendant of the target.
\r
3925 * For example:<pre><code>
\r
3926 // using this markup:
\r
3927 <div id='elId'>
\r
3928 <p id='p1'>paragraph one</p>
\r
3929 <p id='p2' class='clickable'>paragraph two</p>
\r
3930 <p id='p3'>paragraph three</p>
\r
3932 // utilize event delegation to registering just one handler on the container element:
\r
3933 el = Ext.get('elId');
\r
3938 console.info(t.id); // 'p2'
\r
3942 // filter the target element to be a descendant with the class 'clickable'
\r
3943 delegate: '.clickable'
\r
3946 * </code></pre></p>
\r
3947 * @return {Ext.Element} this
\r
3949 addListener : function(eventName, fn, scope, options){
\r
3950 Ext.EventManager.on(this.dom, eventName, fn, scope || this, options);
\r
3955 * Removes an event handler from this element. The shorthand version {@link #un} is equivalent.
\r
3956 * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the
\r
3957 * listener, the same scope must be specified here.
\r
3960 el.removeListener('click', this.handlerFn);
\r
3962 el.un('click', this.handlerFn);
\r
3964 * @param {String} eventName The name of the event from which to remove the handler.
\r
3965 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
\r
3966 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
\r
3967 * then this must refer to the same object.
\r
3968 * @return {Ext.Element} this
\r
3970 removeListener : function(eventName, fn, scope){
\r
3971 Ext.EventManager.removeListener(this.dom, eventName, fn, scope || this);
\r
3976 * Removes all previous added listeners from this element
\r
3977 * @return {Ext.Element} this
\r
3979 removeAllListeners : function(){
\r
3980 Ext.EventManager.removeAll(this.dom);
\r
3985 * @private Test if size has a unit, otherwise appends the default
\r
3987 addUnits : function(size){
\r
3988 if(size === "" || size == "auto" || size === undefined){
\r
3989 size = size || '';
\r
3990 } else if(!isNaN(size) || !unitPattern.test(size)){
\r
3991 size = size + (this.defaultUnit || 'px');
\r
3997 * <p>Updates the <a href="http://developer.mozilla.org/en/DOM/element.innerHTML">innerHTML</a> of this Element
\r
3998 * from a specified URL. Note that this is subject to the <a href="http://en.wikipedia.org/wiki/Same_origin_policy">Same Origin Policy</a></p>
\r
3999 * <p>Updating innerHTML of an element will <b>not</b> execute embedded <tt><script></tt> elements. This is a browser restriction.</p>
\r
4000 * @param {Mixed} options. Either a sring containing the URL from which to load the HTML, or an {@link Ext.Ajax#request} options object specifying
\r
4001 * exactly how to request the HTML.
\r
4002 * @return {Ext.Element} this
\r
4004 load : function(url, params, cb){
\r
4005 Ext.Ajax.request(Ext.apply({
\r
4007 url: url.url || url,
\r
4010 indicatorText: url.indicatorText || ''
\r
4011 }, Ext.isObject(url) ? url : {}));
\r
4016 * Tests various css rules/browsers to determine if this element uses a border box
\r
4017 * @return {Boolean}
\r
4019 isBorderBox : function(){
\r
4020 return noBoxAdjust[(this.dom.tagName || "").toLowerCase()] || Ext.isBorderBox;
\r
4024 * Removes this element from the DOM and deletes it from the cache
\r
4026 remove : function(){
\r
4030 me.removeAllListeners();
\r
4033 delete El.cache[dom.id];
\r
4034 delete El.dataCache[dom.id];
\r
4035 Ext.removeNode(dom);
\r
4040 * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
\r
4041 * @param {Function} overFn The function to call when the mouse enters the Element.
\r
4042 * @param {Function} outFn The function to call when the mouse leaves the Element.
\r
4043 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the functions are executed. Defaults to the Element's DOM element.
\r
4044 * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.
\r
4045 * @return {Ext.Element} this
\r
4047 hover : function(overFn, outFn, scope, options){
\r
4049 me.on('mouseenter', overFn, scope || me.dom, options);
\r
4050 me.on('mouseleave', outFn, scope || me.dom, options);
\r
4055 * Returns true if this element is an ancestor of the passed element
\r
4056 * @param {HTMLElement/String} el The element to check
\r
4057 * @return {Boolean} True if this element is an ancestor of el, else false
\r
4059 contains : function(el){
\r
4060 return !el ? false : Ext.lib.Dom.isAncestor(this.dom, el.dom ? el.dom : el);
\r
4064 * Returns the value of a namespaced attribute from the element's underlying DOM node.
\r
4065 * @param {String} namespace The namespace in which to look for the attribute
\r
4066 * @param {String} name The attribute name
\r
4067 * @return {String} The attribute value
\r
4070 getAttributeNS : function(ns, name){
\r
4071 return this.getAttribute(name, ns);
\r
4075 * Returns the value of an attribute from the element's underlying DOM node.
\r
4076 * @param {String} name The attribute name
\r
4077 * @param {String} namespace (optional) The namespace in which to look for the attribute
\r
4078 * @return {String} The attribute value
\r
4080 getAttribute : Ext.isIE ? function(name, ns){
\r
4082 type = typeof d[ns + ":" + name];
\r
4084 if(['undefined', 'unknown'].indexOf(type) == -1){
\r
4085 return d[ns + ":" + name];
\r
4088 } : function(name, ns){
\r
4090 return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name) || d.getAttribute(name) || d[name];
\r
4094 * Update the innerHTML of this element
\r
4095 * @param {String} html The new HTML
\r
4096 * @return {Ext.Element} this
\r
4098 update : function(html) {
\r
4100 this.dom.innerHTML = html;
\r
4106 var ep = El.prototype;
\r
4108 El.addMethods = function(o){
\r
4113 * Appends an event handler (shorthand for {@link #addListener}).
\r
4114 * @param {String} eventName The name of event to handle.
\r
4115 * @param {Function} fn The handler function the event invokes.
\r
4116 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
\r
4117 * @param {Object} options (optional) An object containing standard {@link #addListener} options
\r
4118 * @member Ext.Element
\r
4121 ep.on = ep.addListener;
\r
4124 * Removes an event handler from this element (see {@link #removeListener} for additional notes).
\r
4125 * @param {String} eventName The name of the event from which to remove the handler.
\r
4126 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
\r
4127 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
\r
4128 * then this must refer to the same object.
\r
4129 * @return {Ext.Element} this
\r
4130 * @member Ext.Element
\r
4133 ep.un = ep.removeListener;
\r
4136 * true to automatically adjust width and height settings for box-model issues (default to true)
\r
4138 ep.autoBoxAdjust = true;
\r
4141 var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
\r
4148 El.dataCache = {};
\r
4151 * Retrieves Ext.Element objects.
\r
4152 * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
\r
4153 * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by
\r
4154 * its ID, use {@link Ext.ComponentMgr#get}.</p>
\r
4155 * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
\r
4156 * object was recreated with the same id via AJAX or DOM.</p>
\r
4157 * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
\r
4158 * @return {Element} The Element object (or null if no matching element was found)
\r
4160 * @member Ext.Element
\r
4163 El.get = function(el){
\r
4167 if(!el){ return null; }
\r
4168 if (typeof el == "string") { // element id
\r
4169 if (!(elm = DOC.getElementById(el))) {
\r
4172 if (ex = El.cache[el]) {
\r
4175 ex = El.cache[el] = new El(elm);
\r
4178 } else if (el.tagName) { // dom element
\r
4179 if(!(id = el.id)){
\r
4182 if(ex = El.cache[id]){
\r
4185 ex = El.cache[id] = new El(el);
\r
4188 } else if (el instanceof El) {
\r
4190 el.dom = DOC.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
\r
4191 // catch case where it hasn't been appended
\r
4192 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
\r
4195 } else if(el.isComposite) {
\r
4197 } else if(Ext.isArray(el)) {
\r
4198 return El.select(el);
\r
4199 } else if(el == DOC) {
\r
4200 // create a bogus element object representing the document object
\r
4202 var f = function(){};
\r
4203 f.prototype = El.prototype;
\r
4212 // private method for getting and setting element data
\r
4213 El.data = function(el, key, value){
\r
4214 var c = El.dataCache[el.id];
\r
4216 c = El.dataCache[el.id] = {};
\r
4218 if(arguments.length == 2){
\r
4221 return (c[key] = value);
\r
4226 // Garbage collection - uncache elements/purge listeners on orphaned elements
\r
4227 // so we don't hold a reference and cause the browser to retain them
\r
4228 function garbageCollect(){
\r
4229 if(!Ext.enableGarbageCollector){
\r
4230 clearInterval(El.collectorThread);
\r
4236 for(eid in El.cache){
\r
4237 el = El.cache[eid];
\r
4239 // -------------------------------------------------------
\r
4240 // Determining what is garbage:
\r
4241 // -------------------------------------------------------
\r
4243 // dom node is null, definitely garbage
\r
4244 // -------------------------------------------------------
\r
4246 // no parentNode == direct orphan, definitely garbage
\r
4247 // -------------------------------------------------------
\r
4248 // !d.offsetParent && !document.getElementById(eid)
\r
4249 // display none elements have no offsetParent so we will
\r
4250 // also try to look it up by it's id. However, check
\r
4251 // offsetParent first so we don't do unneeded lookups.
\r
4252 // This enables collection of elements that are not orphans
\r
4253 // directly, but somewhere up the line they have an orphan
\r
4255 // -------------------------------------------------------
\r
4256 if(!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))){
\r
4257 delete El.cache[eid];
\r
4258 if(d && Ext.enableListenerCollection){
\r
4259 Ext.EventManager.removeAll(d);
\r
4265 El.collectorThreadId = setInterval(garbageCollect, 30000);
\r
4267 var flyFn = function(){};
\r
4268 flyFn.prototype = El.prototype;
\r
4270 // dom is optional
\r
4271 El.Flyweight = function(dom){
\r
4275 El.Flyweight.prototype = new flyFn();
\r
4276 El.Flyweight.prototype.isFlyweight = true;
\r
4277 El._flyweights = {};
\r
4280 * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
\r
4281 * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>
\r
4282 * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
\r
4283 * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}
\r
4284 * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>
\r
4285 * @param {String/HTMLElement} el The dom node or id
\r
4286 * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
\r
4287 * (e.g. internally Ext uses "_global")
\r
4288 * @return {Element} The shared Element object (or null if no matching element was found)
\r
4289 * @member Ext.Element
\r
4292 El.fly = function(el, named){
\r
4294 named = named || '_global';
\r
4296 if (el = Ext.getDom(el)) {
\r
4297 (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
\r
4298 ret = El._flyweights[named];
\r
4304 * Retrieves Ext.Element objects.
\r
4305 * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
\r
4306 * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by
\r
4307 * its ID, use {@link Ext.ComponentMgr#get}.</p>
\r
4308 * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
\r
4309 * object was recreated with the same id via AJAX or DOM.</p>
\r
4310 * Shorthand of {@link Ext.Element#get}
\r
4311 * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
\r
4312 * @return {Element} The Element object (or null if no matching element was found)
\r
4319 * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
\r
4320 * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>
\r
4321 * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
\r
4322 * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}
\r
4323 * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>
\r
4324 * @param {String/HTMLElement} el The dom node or id
\r
4325 * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
\r
4326 * (e.g. internally Ext uses "_global")
\r
4327 * @return {Element} The shared Element object (or null if no matching element was found)
\r
4333 // speedy lookup for elements never to box adjust
\r
4334 var noBoxAdjust = Ext.isStrict ? {
\r
4337 input:1, select:1, textarea:1
\r
4339 if(Ext.isIE || Ext.isGecko){
\r
4340 noBoxAdjust['button'] = 1;
\r
4344 Ext.EventManager.on(window, 'unload', function(){
\r
4346 delete El.dataCache;
\r
4347 delete El._flyweights;
\r
4351 * @class Ext.Element
\r
4353 Ext.Element.addMethods({
\r
4355 * Stops the specified event(s) from bubbling and optionally prevents the default action
\r
4356 * @param {String/Array} eventName an event / array of events to stop from bubbling
\r
4357 * @param {Boolean} preventDefault (optional) true to prevent the default action too
\r
4358 * @return {Ext.Element} this
\r
4360 swallowEvent : function(eventName, preventDefault){
\r
4363 e.stopPropagation();
\r
4364 if(preventDefault){
\r
4365 e.preventDefault();
\r
4368 if(Ext.isArray(eventName)){
\r
4369 Ext.each(eventName, function(e) {
\r
4374 me.on(eventName, fn);
\r
4379 * Create an event handler on this element such that when the event fires and is handled by this element,
\r
4380 * it will be relayed to another object (i.e., fired again as if it originated from that object instead).
\r
4381 * @param {String} eventName The type of event to relay
\r
4382 * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
\r
4383 * for firing the relayed event
\r
4385 relayEvent : function(eventName, observable){
\r
4386 this.on(eventName, function(e){
\r
4387 observable.fireEvent(eventName, e);
\r
4392 * Removes worthless text nodes
\r
4393 * @param {Boolean} forceReclean (optional) By default the element
\r
4394 * keeps track if it has been cleaned already so
\r
4395 * you can call this over and over. However, if you update the element and
\r
4396 * need to force a reclean, you can pass true.
\r
4398 clean : function(forceReclean){
\r
4401 n = dom.firstChild,
\r
4404 if(Ext.Element.data(dom, 'isCleaned') && forceReclean !== true){
\r
4409 var nx = n.nextSibling;
\r
4410 if(n.nodeType == 3 && !/\S/.test(n.nodeValue)){
\r
4411 dom.removeChild(n);
\r
4413 n.nodeIndex = ++ni;
\r
4417 Ext.Element.data(dom, 'isCleaned', true);
\r
4422 * Direct access to the Updater {@link Ext.Updater#update} method. The method takes the same object
\r
4423 * parameter as {@link Ext.Updater#update}
\r
4424 * @return {Ext.Element} this
\r
4426 load : function(){
\r
4427 var um = this.getUpdater();
\r
4428 um.update.apply(um, arguments);
\r
4433 * Gets this element's {@link Ext.Updater Updater}
\r
4434 * @return {Ext.Updater} The Updater
\r
4436 getUpdater : function(){
\r
4437 return this.updateManager || (this.updateManager = new Ext.Updater(this));
\r
4441 * Update the innerHTML of this element, optionally searching for and processing scripts
\r
4442 * @param {String} html The new HTML
\r
4443 * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)
\r
4444 * @param {Function} callback (optional) For async script loading you can be notified when the update completes
\r
4445 * @return {Ext.Element} this
\r
4447 update : function(html, loadScripts, callback){
\r
4448 html = html || "";
\r
4450 if(loadScripts !== true){
\r
4451 this.dom.innerHTML = html;
\r
4452 if(Ext.isFunction(callback)){
\r
4458 var id = Ext.id(),
\r
4461 html += '<span id="' + id + '"></span>';
\r
4463 Ext.lib.Event.onAvailable(id, function(){
\r
4464 var DOC = document,
\r
4465 hd = DOC.getElementsByTagName("head")[0],
\r
4466 re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
\r
4467 srcRe = /\ssrc=([\'\"])(.*?)\1/i,
\r
4468 typeRe = /\stype=([\'\"])(.*?)\1/i,
\r
4476 while((match = re.exec(html))){
\r
4478 srcMatch = attrs ? attrs.match(srcRe) : false;
\r
4479 if(srcMatch && srcMatch[2]){
\r
4480 s = DOC.createElement("script");
\r
4481 s.src = srcMatch[2];
\r
4482 typeMatch = attrs.match(typeRe);
\r
4483 if(typeMatch && typeMatch[2]){
\r
4484 s.type = typeMatch[2];
\r
4486 hd.appendChild(s);
\r
4487 }else if(match[2] && match[2].length > 0){
\r
4488 if(window.execScript) {
\r
4489 window.execScript(match[2]);
\r
4491 window.eval(match[2]);
\r
4495 el = DOC.getElementById(id);
\r
4496 if(el){Ext.removeNode(el);}
\r
4497 if(Ext.isFunction(callback)){
\r
4501 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
\r
4506 * Creates a proxy element of this element
\r
4507 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
\r
4508 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
\r
4509 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
\r
4510 * @return {Ext.Element} The new proxy element
\r
4512 createProxy : function(config, renderTo, matchBox){
\r
4513 config = Ext.isObject(config) ? config : {tag : "div", cls: config};
\r
4516 proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) :
\r
4517 Ext.DomHelper.insertBefore(me.dom, config, true);
\r
4519 if(matchBox && me.setBox && me.getBox){ // check to make sure Element.position.js is loaded
\r
4520 proxy.setBox(me.getBox());
\r
4526 Ext.Element.prototype.getUpdateManager = Ext.Element.prototype.getUpdater;
\r
4529 Ext.Element.uncache = function(el){
\r
4530 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
\r
4532 delete Ext.Element.cache[a[i].id || a[i]];
\r
4536 * @class Ext.Element
\r
4538 Ext.Element.addMethods({
\r
4540 * Gets the x,y coordinates specified by the anchor position on the element.
\r
4541 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo}
\r
4542 * for details on supported anchor positions.
\r
4543 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead
\r
4544 * of page coordinates
\r
4545 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
\r
4546 * {width: (target width), height: (target height)} (defaults to the element's current size)
\r
4547 * @return {Array} [x, y] An array containing the element's x and y coordinates
\r
4549 getAnchorXY : function(anchor, local, s){
\r
4550 //Passing a different size is useful for pre-calculating anchors,
\r
4551 //especially for anchored animations that change the el size.
\r
4552 anchor = (anchor || "tl").toLowerCase();
\r
4556 vp = me.dom == document.body || me.dom == document,
\r
4557 w = s.width || vp ? Ext.lib.Dom.getViewWidth() : me.getWidth(),
\r
4558 h = s.height || vp ? Ext.lib.Dom.getViewHeight() : me.getHeight(),
\r
4562 scroll = me.getScroll(),
\r
4563 extraX = vp ? scroll.left : !local ? o[0] : 0,
\r
4564 extraY = vp ? scroll.top : !local ? o[1] : 0,
\r
4566 c : [r(w * 0.5), r(h * 0.5)],
\r
4567 t : [r(w * 0.5), 0],
\r
4568 l : [0, r(h * 0.5)],
\r
4569 r : [w, r(h * 0.5)],
\r
4570 b : [r(w * 0.5), h],
\r
4577 xy = hash[anchor];
\r
4578 return [xy[0] + extraX, xy[1] + extraY];
\r
4582 * Anchors an element to another element and realigns it when the window is resized.
\r
4583 * @param {Mixed} element The element to align to.
\r
4584 * @param {String} position The position to align to.
\r
4585 * @param {Array} offsets (optional) Offset the positioning by [x, y]
\r
4586 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
\r
4587 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
\r
4588 * is a number, it is used as the buffer delay (defaults to 50ms).
\r
4589 * @param {Function} callback The function to call after the animation finishes
\r
4590 * @return {Ext.Element} this
\r
4592 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
\r
4596 function action(){
\r
4597 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
\r
4598 Ext.callback(callback, Ext.fly(dom));
\r
4601 Ext.EventManager.onWindowResize(action, me);
\r
4603 if(!Ext.isEmpty(monitorScroll)){
\r
4604 Ext.EventManager.on(window, 'scroll', action, me,
\r
4605 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
\r
4607 action.call(me); // align immediately
\r
4612 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
\r
4613 * supported position values.
\r
4614 * @param {Mixed} element The element to align to.
\r
4615 * @param {String} position The position to align to.
\r
4616 * @param {Array} offsets (optional) Offset the positioning by [x, y]
\r
4617 * @return {Array} [x, y]
\r
4619 getAlignToXY : function(el, p, o){
\r
4622 if(!el || !el.dom){
\r
4623 throw "Element.alignToXY with an element that doesn't exist";
\r
4627 p = (p == "?" ? "tl-bl?" : (!/-/.test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();
\r
4635 //constrain the aligned el to viewport if necessary
\r
4639 dw = Ext.lib.Dom.getViewWidth() -10, // 10px of margin for ie
\r
4640 dh = Ext.lib.Dom.getViewHeight()-10, // 10px of margin for ie
\r
4648 docElement = doc.documentElement,
\r
4649 docBody = doc.body,
\r
4650 scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
\r
4651 scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
\r
4652 c = false, //constrain to viewport
\r
4655 m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
\r
4658 throw "Element.alignTo with an invalid alignment " + p;
\r
4665 //Subtract the aligned el's internal xy from the target's offset xy
\r
4666 //plus custom offset to get the aligned el's new offset xy
\r
4667 a1 = me.getAnchorXY(p1, true);
\r
4668 a2 = el.getAnchorXY(p2, false);
\r
4670 x = a2[0] - a1[0] + o[0];
\r
4671 y = a2[1] - a1[1] + o[1];
\r
4674 w = me.getWidth();
\r
4675 h = me.getHeight();
\r
4676 r = el.getRegion();
\r
4677 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
\r
4678 //perpendicular to the vp border, allow the aligned el to slide on that border,
\r
4679 //otherwise swap the aligned el to the opposite border of the target.
\r
4680 p1y = p1.charAt(0);
\r
4681 p1x = p1.charAt(p1.length-1);
\r
4682 p2y = p2.charAt(0);
\r
4683 p2x = p2.charAt(p2.length-1);
\r
4684 swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
\r
4685 swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
\r
4688 if (x + w > dw + scrollX) {
\r
4689 x = swapX ? r.left-w : dw+scrollX-w;
\r
4691 if (x < scrollX) {
\r
4692 x = swapX ? r.right : scrollX;
\r
4694 if (y + h > dh + scrollY) {
\r
4695 y = swapY ? r.top-h : dh+scrollY-h;
\r
4698 y = swapY ? r.bottom : scrollY;
\r
4705 * Aligns this element with another element relative to the specified anchor points. If the other element is the
\r
4706 * document it aligns it to the viewport.
\r
4707 * The position parameter is optional, and can be specified in any one of the following formats:
\r
4709 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
\r
4710 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
\r
4711 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
\r
4712 * deprecated in favor of the newer two anchor syntax below</i>.</li>
\r
4713 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
\r
4714 * element's anchor point, and the second value is used as the target's anchor point.</li>
\r
4716 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
\r
4717 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
\r
4718 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
\r
4719 * that specified in order to enforce the viewport constraints.
\r
4720 * Following are all of the supported anchor positions:
\r
4723 ----- -----------------------------
\r
4724 tl The top left corner (default)
\r
4725 t The center of the top edge
\r
4726 tr The top right corner
\r
4727 l The center of the left edge
\r
4728 c In the center of the element
\r
4729 r The center of the right edge
\r
4730 bl The bottom left corner
\r
4731 b The center of the bottom edge
\r
4732 br The bottom right corner
\r
4736 // align el to other-el using the default positioning ("tl-bl", non-constrained)
\r
4737 el.alignTo("other-el");
\r
4739 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
\r
4740 el.alignTo("other-el", "tr?");
\r
4742 // align the bottom right corner of el with the center left edge of other-el
\r
4743 el.alignTo("other-el", "br-l?");
\r
4745 // align the center of el with the bottom left corner of other-el and
\r
4746 // adjust the x position by -6 pixels (and the y position by 0)
\r
4747 el.alignTo("other-el", "c-bl", [-6, 0]);
\r
4749 * @param {Mixed} element The element to align to.
\r
4750 * @param {String} position The position to align to.
\r
4751 * @param {Array} offsets (optional) Offset the positioning by [x, y]
\r
4752 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
4753 * @return {Ext.Element} this
\r
4755 alignTo : function(element, position, offsets, animate){
\r
4757 return me.setXY(me.getAlignToXY(element, position, offsets),
\r
4758 me.preanim && !!animate ? me.preanim(arguments, 3) : false);
\r
4761 // private ==> used outside of core
\r
4762 adjustForConstraints : function(xy, parent, offsets){
\r
4763 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
\r
4766 // private ==> used outside of core
\r
4767 getConstrainToXY : function(el, local, offsets, proposedXY){
\r
4768 var os = {top:0, left:0, bottom:0, right: 0};
\r
4770 return function(el, local, offsets, proposedXY){
\r
4772 offsets = offsets ? Ext.applyIf(offsets, os) : os;
\r
4774 var vw, vh, vx = 0, vy = 0;
\r
4775 if(el.dom == document.body || el.dom == document){
\r
4776 vw =Ext.lib.Dom.getViewWidth();
\r
4777 vh = Ext.lib.Dom.getViewHeight();
\r
4779 vw = el.dom.clientWidth;
\r
4780 vh = el.dom.clientHeight;
\r
4782 var vxy = el.getXY();
\r
4788 var s = el.getScroll();
\r
4790 vx += offsets.left + s.left;
\r
4791 vy += offsets.top + s.top;
\r
4793 vw -= offsets.right;
\r
4794 vh -= offsets.bottom;
\r
4799 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
\r
4800 var x = xy[0], y = xy[1];
\r
4801 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
\r
4803 // only move it if it needs it
\r
4804 var moved = false;
\r
4806 // first validate right/bottom
\r
4815 // then make sure top/left isn't negative
\r
4824 return moved ? [x, y] : false;
\r
4830 // el = Ext.get(el);
\r
4831 // offsets = Ext.applyIf(offsets || {}, {top : 0, left : 0, bottom : 0, right : 0});
\r
4834 // doc = document,
\r
4835 // s = el.getScroll(),
\r
4836 // vxy = el.getXY(),
\r
4837 // vx = offsets.left + s.left,
\r
4838 // vy = offsets.top + s.top,
\r
4839 // vw = -offsets.right,
\r
4840 // vh = -offsets.bottom,
\r
4843 // xy = proposedXY || (!local ? me.getXY() : [me.getLeft(true), me.getTop(true)]),
\r
4846 // w = me.dom.offsetWidth, h = me.dom.offsetHeight,
\r
4847 // moved = false; // only move it if it needs it
\r
4850 // if(el.dom == doc.body || el.dom == doc){
\r
4851 // vw += Ext.lib.Dom.getViewWidth();
\r
4852 // vh += Ext.lib.Dom.getViewHeight();
\r
4854 // vw += el.dom.clientWidth;
\r
4855 // vh += el.dom.clientHeight;
\r
4862 // // first validate right/bottom
\r
4863 // if(x + w > vx + vw){
\r
4864 // x = vx + vw - w;
\r
4867 // if(y + h > vy + vh){
\r
4868 // y = vy + vh - h;
\r
4871 // // then make sure top/left isn't negative
\r
4880 // return moved ? [x, y] : false;
\r
4884 * Calculates the x, y to center this element on the screen
\r
4885 * @return {Array} The x, y values [x, y]
\r
4887 getCenterXY : function(){
\r
4888 return this.getAlignToXY(document, 'c-c');
\r
4892 * Centers the Element in either the viewport, or another Element.
\r
4893 * @param {Mixed} centerIn (optional) The element in which to center the element.
\r
4895 center : function(centerIn){
\r
4896 return this.alignTo(centerIn || document, 'c-c');
\r
4900 * @class Ext.Element
\r
4902 Ext.Element.addMethods(function(){
\r
4903 var PARENTNODE = 'parentNode',
\r
4904 NEXTSIBLING = 'nextSibling',
\r
4905 PREVIOUSSIBLING = 'previousSibling',
\r
4906 DQ = Ext.DomQuery,
\r
4911 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
\r
4912 * @param {String} selector The simple selector to test
\r
4913 * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
\r
4914 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
\r
4915 * @return {HTMLElement} The matching DOM node (or null if no match was found)
\r
4917 findParent : function(simpleSelector, maxDepth, returnEl){
\r
4919 b = document.body,
\r
4922 if(Ext.isGecko && Object.prototype.toString.call(p) == '[object XULElement]') {
\r
4925 maxDepth = maxDepth || 50;
\r
4926 if (isNaN(maxDepth)) {
\r
4927 stopEl = Ext.getDom(maxDepth);
\r
4928 maxDepth = Number.MAX_VALUE;
\r
4930 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
\r
4931 if(DQ.is(p, simpleSelector)){
\r
4932 return returnEl ? GET(p) : p;
\r
4941 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
\r
4942 * @param {String} selector The simple selector to test
\r
4943 * @param {Number/Mixed} maxDepth (optional) The max depth to
\r
4944 search as a number or element (defaults to 10 || document.body)
\r
4945 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
\r
4946 * @return {HTMLElement} The matching DOM node (or null if no match was found)
\r
4948 findParentNode : function(simpleSelector, maxDepth, returnEl){
\r
4949 var p = Ext.fly(this.dom.parentNode, '_internal');
\r
4950 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
\r
4954 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
\r
4955 * This is a shortcut for findParentNode() that always returns an Ext.Element.
\r
4956 * @param {String} selector The simple selector to test
\r
4957 * @param {Number/Mixed} maxDepth (optional) The max depth to
\r
4958 search as a number or element (defaults to 10 || document.body)
\r
4959 * @return {Ext.Element} The matching DOM node (or null if no match was found)
\r
4961 up : function(simpleSelector, maxDepth){
\r
4962 return this.findParentNode(simpleSelector, maxDepth, true);
\r
4966 * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
\r
4967 * @param {String} selector The CSS selector
\r
4968 * @param {Boolean} unique (optional) True to create a unique Ext.Element for each child (defaults to false, which creates a single shared flyweight object)
\r
4969 * @return {CompositeElement/CompositeElementLite} The composite element
\r
4971 select : function(selector, unique){
\r
4972 return Ext.Element.select(selector, unique, this.dom);
\r
4976 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
\r
4977 * @param {String} selector The CSS selector
\r
4978 * @return {Array} An array of the matched nodes
\r
4980 query : function(selector, unique){
\r
4981 return DQ.select(selector, this.dom);
\r
4985 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
\r
4986 * @param {String} selector The CSS selector
\r
4987 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
\r
4988 * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
\r
4990 child : function(selector, returnDom){
\r
4991 var n = DQ.selectNode(selector, this.dom);
\r
4992 return returnDom ? n : GET(n);
\r
4996 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
\r
4997 * @param {String} selector The CSS selector
\r
4998 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
\r
4999 * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
\r
5001 down : function(selector, returnDom){
\r
5002 var n = DQ.selectNode(" > " + selector, this.dom);
\r
5003 return returnDom ? n : GET(n);
\r
5007 * Gets the parent node for this element, optionally chaining up trying to match a selector
\r
5008 * @param {String} selector (optional) Find a parent node that matches the passed simple selector
\r
5009 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
\r
5010 * @return {Ext.Element/HTMLElement} The parent node or null
\r
5012 parent : function(selector, returnDom){
\r
5013 return this.matchNode(PARENTNODE, PARENTNODE, selector, returnDom);
\r
5017 * Gets the next sibling, skipping text nodes
\r
5018 * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
\r
5019 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
\r
5020 * @return {Ext.Element/HTMLElement} The next sibling or null
\r
5022 next : function(selector, returnDom){
\r
5023 return this.matchNode(NEXTSIBLING, NEXTSIBLING, selector, returnDom);
\r
5027 * Gets the previous sibling, skipping text nodes
\r
5028 * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
\r
5029 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
\r
5030 * @return {Ext.Element/HTMLElement} The previous sibling or null
\r
5032 prev : function(selector, returnDom){
\r
5033 return this.matchNode(PREVIOUSSIBLING, PREVIOUSSIBLING, selector, returnDom);
\r
5038 * Gets the first child, skipping text nodes
\r
5039 * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
\r
5040 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
\r
5041 * @return {Ext.Element/HTMLElement} The first child or null
\r
5043 first : function(selector, returnDom){
\r
5044 return this.matchNode(NEXTSIBLING, 'firstChild', selector, returnDom);
\r
5048 * Gets the last child, skipping text nodes
\r
5049 * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
\r
5050 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
\r
5051 * @return {Ext.Element/HTMLElement} The last child or null
\r
5053 last : function(selector, returnDom){
\r
5054 return this.matchNode(PREVIOUSSIBLING, 'lastChild', selector, returnDom);
\r
5057 matchNode : function(dir, start, selector, returnDom){
\r
5058 var n = this.dom[start];
\r
5060 if(n.nodeType == 1 && (!selector || DQ.is(n, selector))){
\r
5061 return !returnDom ? GET(n) : n;
\r
5069 * @class Ext.Element
\r
5071 Ext.Element.addMethods(
\r
5073 var GETDOM = Ext.getDom,
\r
5075 DH = Ext.DomHelper;
\r
5079 * Appends the passed element(s) to this element
\r
5080 * @param {String/HTMLElement/Array/Element/CompositeElement} el
\r
5081 * @return {Ext.Element} this
\r
5083 appendChild: function(el){
\r
5084 return GET(el).appendTo(this);
\r
5088 * Appends this element to the passed element
\r
5089 * @param {Mixed} el The new parent element
\r
5090 * @return {Ext.Element} this
\r
5092 appendTo: function(el){
\r
5093 GETDOM(el).appendChild(this.dom);
\r
5098 * Inserts this element before the passed element in the DOM
\r
5099 * @param {Mixed} el The element before which this element will be inserted
\r
5100 * @return {Ext.Element} this
\r
5102 insertBefore: function(el){
\r
5103 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el);
\r
5108 * Inserts this element after the passed element in the DOM
\r
5109 * @param {Mixed} el The element to insert after
\r
5110 * @return {Ext.Element} this
\r
5112 insertAfter: function(el){
\r
5113 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el.nextSibling);
\r
5118 * Inserts (or creates) an element (or DomHelper config) as the first child of this element
\r
5119 * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
\r
5120 * @return {Ext.Element} The new child
\r
5122 insertFirst: function(el, returnDom){
\r
5124 if(el.nodeType || el.dom || typeof el == 'string'){ // element
\r
5126 this.dom.insertBefore(el, this.dom.firstChild);
\r
5127 return !returnDom ? GET(el) : el;
\r
5128 }else{ // dh config
\r
5129 return this.createChild(el, this.dom.firstChild, returnDom);
\r
5134 * Replaces the passed element with this element
\r
5135 * @param {Mixed} el The element to replace
\r
5136 * @return {Ext.Element} this
\r
5138 replace: function(el){
\r
5140 this.insertBefore(el);
\r
5146 * Replaces this element with the passed element
\r
5147 * @param {Mixed/Object} el The new element or a DomHelper config of an element to create
\r
5148 * @return {Ext.Element} this
\r
5150 replaceWith: function(el){
\r
5152 Element = Ext.Element;
\r
5153 if(el.nodeType || el.dom || typeof el == 'string'){
\r
5155 me.dom.parentNode.insertBefore(el, me.dom);
\r
5157 el = DH.insertBefore(me.dom, el);
\r
5160 delete Element.cache[me.id];
\r
5161 Ext.removeNode(me.dom);
\r
5162 me.id = Ext.id(me.dom = el);
\r
5163 return Element.cache[me.id] = me;
\r
5167 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
\r
5168 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
\r
5169 * automatically generated with the specified attributes.
\r
5170 * @param {HTMLElement} insertBefore (optional) a child element of this element
\r
5171 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
\r
5172 * @return {Ext.Element} The new child element
\r
5174 createChild: function(config, insertBefore, returnDom){
\r
5175 config = config || {tag:'div'};
\r
5176 return insertBefore ?
\r
5177 DH.insertBefore(insertBefore, config, returnDom !== true) :
\r
5178 DH[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
\r
5182 * Creates and wraps this element with another element
\r
5183 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
\r
5184 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
\r
5185 * @return {HTMLElement/Element} The newly created wrapper element
\r
5187 wrap: function(config, returnDom){
\r
5188 var newEl = DH.insertBefore(this.dom, config || {tag: "div"}, !returnDom);
\r
5189 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
\r
5194 * Inserts an html fragment into this element
\r
5195 * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
\r
5196 * @param {String} html The HTML fragment
\r
5197 * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)
\r
5198 * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)
\r
5200 insertHtml : function(where, html, returnEl){
\r
5201 var el = DH.insertHtml(where, this.dom, html);
\r
5202 return returnEl ? Ext.get(el) : el;
\r
5206 * @class Ext.Element
\r
5208 Ext.apply(Ext.Element.prototype, function() {
\r
5209 var GETDOM = Ext.getDom,
\r
5211 DH = Ext.DomHelper;
\r
5215 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
\r
5216 * @param {Mixed/Object/Array} el The id, element to insert or a DomHelper config to create and insert *or* an array of any of those.
\r
5217 * @param {String} where (optional) 'before' or 'after' defaults to before
\r
5218 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
\r
5219 * @return {Ext.Element} the inserted Element
\r
5221 insertSibling: function(el, where, returnDom){
\r
5225 if(Ext.isArray(el)){
\r
5226 Ext.each(el, function(e) {
\r
5227 rt = me.insertSibling(e, where, returnDom);
\r
5232 where = (where || 'before').toLowerCase();
\r
5235 if(el.nodeType || el.dom){
\r
5236 rt = me.dom.parentNode.insertBefore(GETDOM(el), where == 'before' ? me.dom : me.dom.nextSibling);
\r
5241 if (where == 'after' && !me.dom.nextSibling) {
\r
5242 rt = DH.append(me.dom.parentNode, el, !returnDom);
\r
5244 rt = DH[where == 'after' ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);
\r
5251 * @class Ext.Element
5253 Ext.Element.addMethods(function(){
5254 // local style camelizing for speed
5256 camelRe = /(-[a-z])/gi,
5258 view = document.defaultView,
5259 propFloat = Ext.isIE ? 'styleFloat' : 'cssFloat',
5260 opacityRe = /alpha\(opacity=(.*)\)/i,
5261 trimRe = /^\s+|\s+$/g,
5263 PADDING = "padding",
5273 ISCLIPPED = 'isClipped',
5274 OVERFLOW = 'overflow',
5275 OVERFLOWX = 'overflow-x',
5276 OVERFLOWY = 'overflow-y',
5277 ORIGINALCLIP = 'originalClip',
5278 // special markup used throughout Ext when box wrapping elements
5279 borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
5280 paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
5281 margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
5282 data = Ext.Element.data;
5286 function camelFn(m, a) {
5287 return a.charAt(1).toUpperCase();
5290 function chkCache(prop) {
5291 return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : prop.replace(camelRe, camelFn));
5295 // private ==> used by Fx
5296 adjustWidth : function(width) {
5298 var isNum = Ext.isNumber(width);
5299 if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
5300 width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
5302 return (isNum && width < 0) ? 0 : width;
5305 // private ==> used by Fx
5306 adjustHeight : function(height) {
5308 var isNum = Ext.isNumber(height);
5309 if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
5310 height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
5312 return (isNum && height < 0) ? 0 : height;
5317 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
5318 * @param {String/Array} className The CSS class to add, or an array of classes
5319 * @return {Ext.Element} this
5321 addClass : function(className){
5323 Ext.each(className, function(v) {
5324 me.dom.className += (!me.hasClass(v) && v ? " " + v : "");
5330 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
5331 * @param {String/Array} className The CSS class to add, or an array of classes
5332 * @return {Ext.Element} this
5334 radioClass : function(className){
5335 Ext.each(this.dom.parentNode.childNodes, function(v) {
5336 if(v.nodeType == 1) {
5337 Ext.fly(v, '_internal').removeClass(className);
5340 return this.addClass(className);
5344 * Removes one or more CSS classes from the element.
5345 * @param {String/Array} className The CSS class to remove, or an array of classes
5346 * @return {Ext.Element} this
5348 removeClass : function(className){
5350 if (me.dom && me.dom.className) {
5351 Ext.each(className, function(v) {
5352 me.dom.className = me.dom.className.replace(
5353 classReCache[v] = classReCache[v] || new RegExp('(?:^|\\s+)' + v + '(?:\\s+|$)', "g"),
5361 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
5362 * @param {String} className The CSS class to toggle
5363 * @return {Ext.Element} this
5365 toggleClass : function(className){
5366 return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
5370 * Checks if the specified CSS class exists on this element's DOM node.
5371 * @param {String} className The CSS class to check for
5372 * @return {Boolean} True if the class exists, else false
5374 hasClass : function(className){
5375 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
5379 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
5380 * @param {String} oldClassName The CSS class to replace
5381 * @param {String} newClassName The replacement CSS class
5382 * @return {Ext.Element} this
5384 replaceClass : function(oldClassName, newClassName){
5385 return this.removeClass(oldClassName).addClass(newClassName);
5388 isStyle : function(style, val) {
5389 return this.getStyle(style) == val;
5393 * Normalizes currentStyle and computedStyle.
5394 * @param {String} property The style property whose value is returned.
5395 * @return {String} The current value of the style property for this element.
5397 getStyle : function(){
5398 return view && view.getComputedStyle ?
5404 if(el == document) return null;
5405 prop = chkCache(prop);
5406 out = (v = el.style[prop]) ? v :
5407 (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
5409 // Webkit returns rgb values for transparent.
5410 if(Ext.isWebKit && out == 'rgba(0, 0, 0, 0)'){
5411 out = 'transparent';
5420 if(el == document) return null;
5421 if (prop == 'opacity') {
5422 if (el.style.filter.match) {
5423 if(m = el.style.filter.match(opacityRe)){
5424 var fv = parseFloat(m[1]);
5426 return fv ? fv / 100 : 0;
5432 prop = chkCache(prop);
5433 return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
5438 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
5439 * are convert to standard 6 digit hex color.
5440 * @param {String} attr The css attribute
5441 * @param {String} defaultValue The default value to use when a valid color isn't found
5442 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
5445 getColor : function(attr, defaultValue, prefix){
5446 var v = this.getStyle(attr),
5447 color = Ext.isDefined(prefix) ? prefix : '#',
5450 if(!v || /transparent|inherit/.test(v)){
5451 return defaultValue;
5454 Ext.each(v.slice(4, v.length -1).split(','), function(s){
5455 h = parseInt(s, 10);
5456 color += (h < 16 ? '0' : '') + h.toString(16);
5459 v = v.replace('#', '');
5460 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
5462 return(color.length > 5 ? color.toLowerCase() : defaultValue);
5466 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
5467 * @param {String/Object} property The style property to be set, or an object of multiple styles.
5468 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
5469 * @return {Ext.Element} this
5471 setStyle : function(prop, value){
5475 if (!Ext.isObject(prop)) {
5480 for (style in prop) {
5481 value = prop[style];
5482 style == 'opacity' ?
5483 this.setOpacity(value) :
5484 this.dom.style[chkCache(style)] = value;
5490 * Set the opacity of the element
5491 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
5492 * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
5493 * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
5494 * @return {Ext.Element} this
5496 setOpacity : function(opacity, animate){
5500 if(!animate || !me.anim){
5502 var opac = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')' : '',
5503 val = s.filter.replace(opacityRe, '').replace(trimRe, '');
5506 s.filter = val + (val.length > 0 ? ' ' : '') + opac;
5508 s.opacity = opacity;
5511 me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn');
5517 * Clears any opacity settings from this element. Required in some cases for IE.
5518 * @return {Ext.Element} this
5520 clearOpacity : function(){
5521 var style = this.dom.style;
5523 if(!Ext.isEmpty(style.filter)){
5524 style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
5527 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
5533 * Returns the offset height of the element
5534 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
5535 * @return {Number} The element's height
5537 getHeight : function(contentHeight){
5540 hidden = Ext.isIE && me.isStyle('display', 'none'),
5541 h = MATH.max(dom.offsetHeight, hidden ? 0 : dom.clientHeight) || 0;
5543 h = !contentHeight ? h : h - me.getBorderWidth("tb") - me.getPadding("tb");
5544 return h < 0 ? 0 : h;
5548 * Returns the offset width of the element
5549 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
5550 * @return {Number} The element's width
5552 getWidth : function(contentWidth){
5555 hidden = Ext.isIE && me.isStyle('display', 'none'),
5556 w = MATH.max(dom.offsetWidth, hidden ? 0 : dom.clientWidth) || 0;
5557 w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");
5558 return w < 0 ? 0 : w;
5562 * Set the width of this Element.
5563 * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
5564 * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
5565 * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
5567 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
5568 * @return {Ext.Element} this
5570 setWidth : function(width, animate){
5572 width = me.adjustWidth(width);
5573 !animate || !me.anim ?
5574 me.dom.style.width = me.addUnits(width) :
5575 me.anim({width : {to : width}}, me.preanim(arguments, 1));
5580 * Set the height of this Element.
5582 // change the height to 200px and animate with default configuration
5583 Ext.fly('elementId').setHeight(200, true);
5585 // change the height to 150px and animate with a custom configuration
5586 Ext.fly('elId').setHeight(150, {
5587 duration : .5, // animation will have a duration of .5 seconds
5588 // will change the content to "finished"
5589 callback: function(){ this.{@link #update}("finished"); }
5592 * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
5593 * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
5594 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
5596 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
5597 * @return {Ext.Element} this
5599 setHeight : function(height, animate){
5601 height = me.adjustHeight(height);
5602 !animate || !me.anim ?
5603 me.dom.style.height = me.addUnits(height) :
5604 me.anim({height : {to : height}}, me.preanim(arguments, 1));
5609 * Gets the width of the border(s) for the specified side(s)
5610 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
5611 * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
5612 * @return {Number} The width of the sides passed added together
5614 getBorderWidth : function(side){
5615 return this.addStyles(side, borders);
5619 * Gets the width of the padding(s) for the specified side(s)
5620 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
5621 * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
5622 * @return {Number} The padding of the sides passed added together
5624 getPadding : function(side){
5625 return this.addStyles(side, paddings);
5629 * Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
5630 * @return {Ext.Element} this
5636 if(!data(dom, ISCLIPPED)){
5637 data(dom, ISCLIPPED, true);
5638 data(dom, ORIGINALCLIP, {
5639 o: me.getStyle(OVERFLOW),
5640 x: me.getStyle(OVERFLOWX),
5641 y: me.getStyle(OVERFLOWY)
5643 me.setStyle(OVERFLOW, HIDDEN);
5644 me.setStyle(OVERFLOWX, HIDDEN);
5645 me.setStyle(OVERFLOWY, HIDDEN);
5651 * Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
5652 * @return {Ext.Element} this
5654 unclip : function(){
5658 if(data(dom, ISCLIPPED)){
5659 data(dom, ISCLIPPED, false);
5660 var o = data(dom, ORIGINALCLIP);
5662 me.setStyle(OVERFLOW, o.o);
5665 me.setStyle(OVERFLOWX, o.x);
5668 me.setStyle(OVERFLOWY, o.y);
5675 addStyles : function(sides, styles){
5678 Ext.each(sides.match(/\w/g), function(s) {
5679 if (s = parseInt(this.getStyle(styles[s]), 10)) {
5692 * @class Ext.Element
\r
5695 // special markup used throughout Ext when box wrapping elements
\r
5696 Ext.Element.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
\r
5698 Ext.Element.addMethods(function(){
\r
5699 var INTERNAL = "_internal";
\r
5702 * More flexible version of {@link #setStyle} for setting style properties.
\r
5703 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
\r
5704 * a function which returns such a specification.
\r
5705 * @return {Ext.Element} this
\r
5707 applyStyles : function(style){
\r
5708 Ext.DomHelper.applyStyles(this.dom, style);
\r
5713 * Returns an object with properties matching the styles requested.
\r
5714 * For example, el.getStyles('color', 'font-size', 'width') might return
\r
5715 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
\r
5716 * @param {String} style1 A style name
\r
5717 * @param {String} style2 A style name
\r
5718 * @param {String} etc.
\r
5719 * @return {Object} The style object
\r
5721 getStyles : function(){
\r
5723 Ext.each(arguments, function(v) {
\r
5724 ret[v] = this.getStyle(v);
\r
5730 getStyleSize : function(){
\r
5736 if(s.width && s.width != 'auto'){
\r
5737 w = parseInt(s.width, 10);
\r
5738 if(me.isBorderBox()){
\r
5739 w -= me.getFrameWidth('lr');
\r
5742 if(s.height && s.height != 'auto'){
\r
5743 h = parseInt(s.height, 10);
\r
5744 if(me.isBorderBox()){
\r
5745 h -= me.getFrameWidth('tb');
\r
5748 return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
\r
5751 // private ==> used by ext full
\r
5752 setOverflow : function(v){
\r
5753 var dom = this.dom;
\r
5754 if(v=='auto' && Ext.isMac && Ext.isGecko2){ // work around stupid FF 2.0/Mac scroll bar bug
\r
5755 dom.style.overflow = 'hidden';
\r
5756 (function(){dom.style.overflow = 'auto';}).defer(1);
\r
5758 dom.style.overflow = v;
\r
5763 * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as
\r
5764 * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>
\r
5765 * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.Button},
\r
5766 * {@link Ext.Panel} when <tt>{@link Ext.Panel#frame frame=true}</tt>, {@link Ext.Window}). The markup
\r
5767 * is of this form:</p>
\r
5769 Ext.Element.boxMarkup =
\r
5770 '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div>
\r
5771 <div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div>
\r
5772 <div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
\r
5774 * <p>Example usage:</p>
\r
5777 Ext.get("foo").boxWrap();
\r
5779 // You can also add a custom class and use CSS inheritance rules to customize the box look.
\r
5780 // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
\r
5781 // for how to create a custom box wrap style.
\r
5782 Ext.get("foo").boxWrap().addClass("x-box-blue");
\r
5784 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
\r
5785 * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on
\r
5786 * this name to make the overall effect work, so if you supply an alternate base class, make sure you
\r
5787 * also supply all of the necessary rules.
\r
5788 * @return {Ext.Element} this
\r
5790 boxWrap : function(cls){
\r
5791 cls = cls || 'x-box';
\r
5792 var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + String.format(Ext.Element.boxMarkup, cls) + "</div>")); //String.format('<div class="{0}">'+Ext.Element.boxMarkup+'</div>', cls)));
\r
5793 Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
\r
5798 * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
\r
5799 * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
\r
5800 * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
\r
5801 * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
\r
5802 * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
\r
5804 * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
\r
5805 * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>
\r
5806 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
\r
5808 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
5809 * @return {Ext.Element} this
\r
5811 setSize : function(width, height, animate){
\r
5813 if(Ext.isObject(width)){ // in case of object from getSize()
\r
5814 height = width.height;
\r
5815 width = width.width;
\r
5817 width = me.adjustWidth(width);
\r
5818 height = me.adjustHeight(height);
\r
5819 if(!animate || !me.anim){
\r
5820 me.dom.style.width = me.addUnits(width);
\r
5821 me.dom.style.height = me.addUnits(height);
\r
5823 me.anim({width: {to: width}, height: {to: height}}, me.preanim(arguments, 2));
\r
5829 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
\r
5830 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
\r
5831 * if a height has not been set using CSS.
\r
5832 * @return {Number}
\r
5834 getComputedHeight : function(){
\r
5836 h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
\r
5838 h = parseInt(me.getStyle('height'), 10) || 0;
\r
5839 if(!me.isBorderBox()){
\r
5840 h += me.getFrameWidth('tb');
\r
5847 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
\r
5848 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
\r
5849 * if a width has not been set using CSS.
\r
5850 * @return {Number}
\r
5852 getComputedWidth : function(){
\r
5853 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
\r
5855 w = parseInt(this.getStyle('width'), 10) || 0;
\r
5856 if(!this.isBorderBox()){
\r
5857 w += this.getFrameWidth('lr');
\r
5864 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
\r
5865 for more information about the sides.
\r
5866 * @param {String} sides
\r
5867 * @return {Number}
\r
5869 getFrameWidth : function(sides, onlyContentBox){
\r
5870 return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
\r
5874 * Sets up event handlers to add and remove a css class when the mouse is over this element
\r
5875 * @param {String} className
\r
5876 * @return {Ext.Element} this
\r
5878 addClassOnOver : function(className){
\r
5881 Ext.fly(this, INTERNAL).addClass(className);
\r
5884 Ext.fly(this, INTERNAL).removeClass(className);
\r
5891 * Sets up event handlers to add and remove a css class when this element has the focus
\r
5892 * @param {String} className
\r
5893 * @return {Ext.Element} this
\r
5895 addClassOnFocus : function(className){
\r
5896 this.on("focus", function(){
\r
5897 Ext.fly(this, INTERNAL).addClass(className);
\r
5899 this.on("blur", function(){
\r
5900 Ext.fly(this, INTERNAL).removeClass(className);
\r
5906 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
\r
5907 * @param {String} className
\r
5908 * @return {Ext.Element} this
\r
5910 addClassOnClick : function(className){
\r
5911 var dom = this.dom;
\r
5912 this.on("mousedown", function(){
\r
5913 Ext.fly(dom, INTERNAL).addClass(className);
\r
5914 var d = Ext.getDoc(),
\r
5916 Ext.fly(dom, INTERNAL).removeClass(className);
\r
5917 d.removeListener("mouseup", fn);
\r
5919 d.on("mouseup", fn);
\r
5925 * Returns the width and height of the viewport.
\r
5927 var vpSize = Ext.getBody().getViewSize();
\r
5929 // all Windows created afterwards will have a default value of 90% height and 95% width
\r
5930 Ext.Window.override({
\r
5931 width: vpSize.width * 0.9,
\r
5932 height: vpSize.height * 0.95
\r
5934 // To handle window resizing you would have to hook onto onWindowResize.
\r
5936 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
\r
5938 getViewSize : function(){
\r
5939 var doc = document,
\r
5941 extdom = Ext.lib.Dom,
\r
5942 isDoc = (d == doc || d == doc.body);
\r
5943 return { width : (isDoc ? extdom.getViewWidth() : d.clientWidth),
\r
5944 height : (isDoc ? extdom.getViewHeight() : d.clientHeight) };
\r
5948 * Returns the size of the element.
\r
5949 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
\r
5950 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
\r
5952 getSize : function(contentSize){
\r
5953 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
\r
5957 * Forces the browser to repaint this element
\r
5958 * @return {Ext.Element} this
\r
5960 repaint : function(){
\r
5961 var dom = this.dom;
\r
5962 this.addClass("x-repaint");
\r
5963 setTimeout(function(){
\r
5964 Ext.fly(dom).removeClass("x-repaint");
\r
5970 * Disables text selection for this element (normalized across browsers)
\r
5971 * @return {Ext.Element} this
\r
5973 unselectable : function(){
\r
5974 this.dom.unselectable = "on";
\r
5975 return this.swallowEvent("selectstart", true).
\r
5976 applyStyles("-moz-user-select:none;-khtml-user-select:none;").
\r
5977 addClass("x-unselectable");
\r
5981 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
\r
5982 * then it returns the calculated width of the sides (see getPadding)
\r
5983 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
\r
5984 * @return {Object/Number}
\r
5986 getMargins : function(side){
\r
5989 hash = {t:"top", l:"left", r:"right", b: "bottom"},
\r
5993 for (key in me.margins){
\r
5994 o[hash[key]] = parseInt(me.getStyle(me.margins[key]), 10) || 0;
\r
5998 return me.addStyles.call(me, side, me.margins);
\r
6003 * @class Ext.Element
\r
6006 var D = Ext.lib.Dom,
\r
6010 BOTTOM = "bottom",
\r
6011 POSITION = "position",
\r
6012 STATIC = "static",
\r
6013 RELATIVE = "relative",
\r
6015 ZINDEX = "z-index";
\r
6017 Ext.Element.addMethods({
\r
6019 * 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).
\r
6020 * @return {Number} The X position of the element
\r
6022 getX : function(){
\r
6023 return D.getX(this.dom);
\r
6027 * Gets the current Y 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).
\r
6028 * @return {Number} The Y position of the element
\r
6030 getY : function(){
\r
6031 return D.getY(this.dom);
\r
6035 * Gets the current 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).
\r
6036 * @return {Array} The XY position of the element
\r
6038 getXY : function(){
\r
6039 return D.getXY(this.dom);
\r
6043 * Returns the offsets of this element from the passed element. Both element must be part of the DOM tree and not have display:none to have page coordinates.
\r
6044 * @param {Mixed} element The element to get the offsets from.
\r
6045 * @return {Array} The XY page offsets (e.g. [100, -200])
\r
6047 getOffsetsTo : function(el){
\r
6048 var o = this.getXY(),
\r
6049 e = Ext.fly(el, '_internal').getXY();
\r
6050 return [o[0]-e[0],o[1]-e[1]];
\r
6054 * Sets the 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).
\r
6055 * @param {Number} The X position of the element
\r
6056 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
\r
6057 * @return {Ext.Element} this
\r
6059 setX : function(x, animate){
\r
6060 return this.setXY([x, this.getY()], this.animTest(arguments, animate, 1));
\r
6064 * Sets the Y 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).
\r
6065 * @param {Number} The Y position of the element
\r
6066 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
\r
6067 * @return {Ext.Element} this
\r
6069 setY : function(y, animate){
\r
6070 return this.setXY([this.getX(), y], this.animTest(arguments, animate, 1));
\r
6074 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
\r
6075 * @param {String} left The left CSS property value
\r
6076 * @return {Ext.Element} this
\r
6078 setLeft : function(left){
\r
6079 this.setStyle(LEFT, this.addUnits(left));
\r
6084 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
\r
6085 * @param {String} top The top CSS property value
\r
6086 * @return {Ext.Element} this
\r
6088 setTop : function(top){
\r
6089 this.setStyle(TOP, this.addUnits(top));
\r
6094 * Sets the element's CSS right style.
\r
6095 * @param {String} right The right CSS property value
\r
6096 * @return {Ext.Element} this
\r
6098 setRight : function(right){
\r
6099 this.setStyle(RIGHT, this.addUnits(right));
\r
6104 * Sets the element's CSS bottom style.
\r
6105 * @param {String} bottom The bottom CSS property value
\r
6106 * @return {Ext.Element} this
\r
6108 setBottom : function(bottom){
\r
6109 this.setStyle(BOTTOM, this.addUnits(bottom));
\r
6114 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
\r
6115 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
\r
6116 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
\r
6117 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
\r
6118 * @return {Ext.Element} this
\r
6120 setXY : function(pos, animate){
\r
6122 if(!animate || !me.anim){
\r
6123 D.setXY(me.dom, pos);
\r
6125 me.anim({points: {to: pos}}, me.preanim(arguments, 1), 'motion');
\r
6131 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
\r
6132 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
\r
6133 * @param {Number} x X value for new position (coordinates are page-based)
\r
6134 * @param {Number} y Y value for new position (coordinates are page-based)
\r
6135 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
\r
6136 * @return {Ext.Element} this
\r
6138 setLocation : function(x, y, animate){
\r
6139 return this.setXY([x, y], this.animTest(arguments, animate, 2));
\r
6143 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
\r
6144 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
\r
6145 * @param {Number} x X value for new position (coordinates are page-based)
\r
6146 * @param {Number} y Y value for new position (coordinates are page-based)
\r
6147 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
\r
6148 * @return {Ext.Element} this
\r
6150 moveTo : function(x, y, animate){
\r
6151 return this.setXY([x, y], this.animTest(arguments, animate, 2));
\r
6155 * Gets the left X coordinate
\r
6156 * @param {Boolean} local True to get the local css position instead of page coordinate
\r
6157 * @return {Number}
\r
6159 getLeft : function(local){
\r
6160 return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
\r
6164 * Gets the right X coordinate of the element (element X position + element width)
\r
6165 * @param {Boolean} local True to get the local css position instead of page coordinate
\r
6166 * @return {Number}
\r
6168 getRight : function(local){
\r
6170 return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
\r
6174 * Gets the top Y coordinate
\r
6175 * @param {Boolean} local True to get the local css position instead of page coordinate
\r
6176 * @return {Number}
\r
6178 getTop : function(local) {
\r
6179 return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
\r
6183 * Gets the bottom Y coordinate of the element (element Y position + element height)
\r
6184 * @param {Boolean} local True to get the local css position instead of page coordinate
\r
6185 * @return {Number}
\r
6187 getBottom : function(local){
\r
6189 return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
\r
6193 * Initializes positioning on this element. If a desired position is not passed, it will make the
\r
6194 * the element positioned relative IF it is not already positioned.
\r
6195 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
\r
6196 * @param {Number} zIndex (optional) The zIndex to apply
\r
6197 * @param {Number} x (optional) Set the page X position
\r
6198 * @param {Number} y (optional) Set the page Y position
\r
6200 position : function(pos, zIndex, x, y){
\r
6203 if(!pos && me.isStyle(POSITION, STATIC)){
\r
6204 me.setStyle(POSITION, RELATIVE);
\r
6206 me.setStyle(POSITION, pos);
\r
6209 me.setStyle(ZINDEX, zIndex);
\r
6211 if(x || y) me.setXY([x || false, y || false]);
\r
6215 * Clear positioning back to the default when the document was loaded
\r
6216 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
\r
6217 * @return {Ext.Element} this
\r
6219 clearPositioning : function(value){
\r
6220 value = value || '';
\r
6233 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
\r
6234 * snapshot before performing an update and then restoring the element.
\r
6235 * @return {Object}
\r
6237 getPositioning : function(){
\r
6238 var l = this.getStyle(LEFT);
\r
6239 var t = this.getStyle(TOP);
\r
6241 "position" : this.getStyle(POSITION),
\r
6243 "right" : l ? "" : this.getStyle(RIGHT),
\r
6245 "bottom" : t ? "" : this.getStyle(BOTTOM),
\r
6246 "z-index" : this.getStyle(ZINDEX)
\r
6251 * Set positioning with an object returned by getPositioning().
\r
6252 * @param {Object} posCfg
\r
6253 * @return {Ext.Element} this
\r
6255 setPositioning : function(pc){
\r
6257 style = me.dom.style;
\r
6261 if(pc.right == AUTO){
\r
6264 if(pc.bottom == AUTO){
\r
6265 style.bottom = "";
\r
6272 * Translates the passed page coordinates into left/top css values for this element
\r
6273 * @param {Number/Array} x The page x or an array containing [x, y]
\r
6274 * @param {Number} y (optional) The page y, required if x is not an array
\r
6275 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
\r
6277 translatePoints : function(x, y){
\r
6278 y = isNaN(x[1]) ? y : x[1];
\r
6279 x = isNaN(x[0]) ? x : x[0];
\r
6281 relative = me.isStyle(POSITION, RELATIVE),
\r
6283 l = parseInt(me.getStyle(LEFT), 10),
\r
6284 t = parseInt(me.getStyle(TOP), 10);
\r
6286 l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);
\r
6287 t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);
\r
6289 return {left: (x - o[0] + l), top: (y - o[1] + t)};
\r
6292 animTest : function(args, animate, i) {
\r
6293 return !!animate && this.preanim ? this.preanim(args, i) : false;
\r
6297 * @class Ext.Element
\r
6299 Ext.Element.addMethods({
\r
6301 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
\r
6302 * @param {Object} box The box to fill {x, y, width, height}
\r
6303 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
\r
6304 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
6305 * @return {Ext.Element} this
\r
6307 setBox : function(box, adjust, animate){
\r
6311 if((adjust && !me.autoBoxAdjust) && !me.isBorderBox()){
\r
6312 w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
\r
6313 h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
\r
6315 me.setBounds(box.x, box.y, w, h, me.animTest.call(me, arguments, animate, 2));
\r
6320 * Return a box {x, y, width, height} that can be used to set another elements
\r
6321 * size/location to match this element.
\r
6322 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
\r
6323 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
\r
6324 * @return {Object} box An object in the format {x, y, width, height}
\r
6326 getBox : function(contentBox, local) {
\r
6331 getBorderWidth = me.getBorderWidth,
\r
6332 getPadding = me.getPadding,
\r
6340 left = parseInt(me.getStyle("left"), 10) || 0;
\r
6341 top = parseInt(me.getStyle("top"), 10) || 0;
\r
6344 var el = me.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
\r
6346 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
\r
6348 l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");
\r
6349 r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");
\r
6350 t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");
\r
6351 b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");
\r
6352 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
\r
6354 bx.right = bx.x + bx.width;
\r
6355 bx.bottom = bx.y + bx.height;
\r
6360 * Move this element relative to its current position.
\r
6361 * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
\r
6362 * @param {Number} distance How far to move the element in pixels
\r
6363 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
6364 * @return {Ext.Element} this
\r
6366 move : function(direction, distance, animate){
\r
6371 left = [x - distance, y],
\r
6372 right = [x + distance, y],
\r
6373 top = [x, y - distance],
\r
6374 bottom = [x, y + distance],
\r
6388 direction = direction.toLowerCase();
\r
6389 me.moveTo(hash[direction][0], hash[direction][1], me.animTest.call(me, arguments, animate, 2));
\r
6393 * Quick set left and top adding default units
\r
6394 * @param {String} left The left CSS property value
\r
6395 * @param {String} top The top CSS property value
\r
6396 * @return {Ext.Element} this
\r
6398 setLeftTop : function(left, top){
\r
6400 style = me.dom.style;
\r
6401 style.left = me.addUnits(left);
\r
6402 style.top = me.addUnits(top);
\r
6407 * Returns the region of the given element.
\r
6408 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
\r
6409 * @return {Region} A Ext.lib.Region containing "top, left, bottom, right" member data.
\r
6411 getRegion : function(){
\r
6412 return Ext.lib.Dom.getRegion(this.dom);
\r
6416 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
\r
6417 * @param {Number} x X value for new position (coordinates are page-based)
\r
6418 * @param {Number} y Y value for new position (coordinates are page-based)
\r
6419 * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
\r
6420 * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>
\r
6421 * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
\r
6423 * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
\r
6424 * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>
\r
6425 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
\r
6427 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
6428 * @return {Ext.Element} this
\r
6430 setBounds : function(x, y, width, height, animate){
\r
6432 if (!animate || !me.anim) {
\r
6433 me.setSize(width, height);
\r
6434 me.setLocation(x, y);
\r
6436 me.anim({points: {to: [x, y]},
\r
6437 width: {to: me.adjustWidth(width)},
\r
6438 height: {to: me.adjustHeight(height)}},
\r
6439 me.preanim(arguments, 4),
\r
6446 * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.
\r
6447 * @param {Ext.lib.Region} region The region to fill
\r
6448 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
6449 * @return {Ext.Element} this
\r
6451 setRegion : function(region, animate) {
\r
6452 return this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.animTest.call(this, arguments, animate, 1));
\r
6455 * @class Ext.Element
\r
6457 Ext.Element.addMethods({
\r
6459 * Returns true if this element is scrollable.
\r
6460 * @return {Boolean}
\r
6462 isScrollable : function(){
\r
6463 var dom = this.dom;
\r
6464 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
\r
6468 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
\r
6469 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
\r
6470 * @param {Number} value The new scroll value.
\r
6471 * @return {Element} this
\r
6473 scrollTo : function(side, value){
\r
6474 this.dom["scroll" + (/top/i.test(side) ? "Top" : "Left")] = value;
\r
6479 * Returns the current scroll position of the element.
\r
6480 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
\r
6482 getScroll : function(){
\r
6483 var d = this.dom,
\r
6486 docElement = doc.documentElement,
\r
6491 if(d == doc || d == body){
\r
6492 if(Ext.isIE && Ext.isStrict){
\r
6493 l = docElement.scrollLeft;
\r
6494 t = docElement.scrollTop;
\r
6496 l = window.pageXOffset;
\r
6497 t = window.pageYOffset;
\r
6499 ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)};
\r
6501 ret = {left: d.scrollLeft, top: d.scrollTop};
\r
6506 * @class Ext.Element
\r
6508 Ext.Element.addMethods({
\r
6510 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
\r
6511 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
\r
6512 * @param {Number} value The new scroll value
\r
6513 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
6514 * @return {Element} this
\r
6516 scrollTo : function(side, value, animate){
\r
6517 var top = /top/i.test(side), //check if we're scrolling top or left
\r
6518 prop = 'scroll' + (top ? 'Left' : 'Top'), // if scrolling top, we need to grab scrollLeft, if left, scrollTop
\r
6521 if (!animate || !me.anim) {
\r
6522 dom[prop] = value;
\r
6524 me.anim({scroll: {to: top ? [dom[prop], value] : [value, dom[prop]]}},
\r
6525 me.preanim(arguments, 2), 'scroll');
\r
6531 * Scrolls this element into view within the passed container.
\r
6532 * @param {Mixed} container (optional) The container element to scroll (defaults to document.body). Should be a
\r
6533 * string (id), dom node, or Ext.Element.
\r
6534 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
\r
6535 * @return {Ext.Element} this
\r
6537 scrollIntoView : function(container, hscroll){
\r
6538 var c = Ext.getDom(container) || Ext.getBody().dom,
\r
6540 o = this.getOffsetsTo(c),
\r
6541 l = o[0] + c.scrollLeft,
\r
6542 t = o[1] + c.scrollTop,
\r
6543 b = t + el.offsetHeight,
\r
6544 r = l + el.offsetWidth,
\r
6545 ch = c.clientHeight,
\r
6546 ct = parseInt(c.scrollTop, 10),
\r
6547 cl = parseInt(c.scrollLeft, 10),
\r
6549 cr = cl + c.clientWidth;
\r
6551 if (el.offsetHeight > ch || t < ct) {
\r
6553 } else if (b > cb){
\r
6554 c.scrollTop = b-ch;
\r
6556 c.scrollTop = c.scrollTop; // corrects IE, other browsers will ignore
\r
6558 if(hscroll !== false){
\r
6559 if(el.offsetWidth > c.clientWidth || l < cl){
\r
6562 c.scrollLeft = r - c.clientWidth;
\r
6564 c.scrollLeft = c.scrollLeft;
\r
6570 scrollChildIntoView : function(child, hscroll){
\r
6571 Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
\r
6575 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
\r
6576 * within this element's scrollable range.
\r
6577 * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
\r
6578 * @param {Number} distance How far to scroll the element in pixels
\r
6579 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
6580 * @return {Boolean} Returns true if a scroll was triggered or false if the element
\r
6581 * was scrolled as far as it could go.
\r
6583 scroll : function(direction, distance, animate){
\r
6584 if(!this.isScrollable()){
\r
6587 var el = this.dom,
\r
6588 l = el.scrollLeft, t = el.scrollTop,
\r
6589 w = el.scrollWidth, h = el.scrollHeight,
\r
6590 cw = el.clientWidth, ch = el.clientHeight,
\r
6591 scrolled = false, v,
\r
6593 l: Math.min(l + distance, w-cw),
\r
6594 r: v = Math.max(l - distance, 0),
\r
6595 t: Math.max(t - distance, 0),
\r
6596 b: Math.min(t + distance, h-ch)
\r
6601 direction = direction.substr(0, 1);
\r
6602 if((v = hash[direction]) > -1){
\r
6604 this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.preanim(arguments, 2));
\r
6609 * @class Ext.Element
\r
6612 * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
\r
6616 Ext.Element.VISIBILITY = 1;
\r
6618 * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
\r
6622 Ext.Element.DISPLAY = 2;
\r
6624 Ext.Element.addMethods(function(){
\r
6625 var VISIBILITY = "visibility",
\r
6626 DISPLAY = "display",
\r
6627 HIDDEN = "hidden",
\r
6629 ORIGINALDISPLAY = 'originalDisplay',
\r
6630 VISMODE = 'visibilityMode',
\r
6631 ELDISPLAY = Ext.Element.DISPLAY,
\r
6632 data = Ext.Element.data,
\r
6633 getDisplay = function(dom){
\r
6634 var d = data(dom, ORIGINALDISPLAY);
\r
6635 if(d === undefined){
\r
6636 data(dom, ORIGINALDISPLAY, d = '');
\r
6640 getVisMode = function(dom){
\r
6641 var m = data(dom, VISMODE);
\r
6642 if(m === undefined){
\r
6643 data(dom, VISMODE, m = 1)
\r
6650 * The element's default display mode (defaults to "")
\r
6653 originalDisplay : "",
\r
6654 visibilityMode : 1,
\r
6657 * Sets the element's visibility mode. When setVisible() is called it
\r
6658 * will use this to determine whether to set the visibility or the display property.
\r
6659 * @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY
\r
6660 * @return {Ext.Element} this
\r
6662 setVisibilityMode : function(visMode){
\r
6663 data(this.dom, VISMODE, visMode);
\r
6668 * Perform custom animation on this element.
\r
6669 * <div><ul class="mdetail-params">
\r
6670 * <li><u>Animation Properties</u></li>
\r
6672 * <p>The Animation Control Object enables gradual transitions for any member of an
\r
6673 * element's style object that takes a numeric value including but not limited to
\r
6674 * these properties:</p><div><ul class="mdetail-params">
\r
6675 * <li><tt>bottom, top, left, right</tt></li>
\r
6676 * <li><tt>height, width</tt></li>
\r
6677 * <li><tt>margin, padding</tt></li>
\r
6678 * <li><tt>borderWidth</tt></li>
\r
6679 * <li><tt>opacity</tt></li>
\r
6680 * <li><tt>fontSize</tt></li>
\r
6681 * <li><tt>lineHeight</tt></li>
\r
6685 * <li><u>Animation Property Attributes</u></li>
\r
6687 * <p>Each Animation Property is a config object with optional properties:</p>
\r
6688 * <div><ul class="mdetail-params">
\r
6689 * <li><tt>by</tt>* : relative change - start at current value, change by this value</li>
\r
6690 * <li><tt>from</tt> : ignore current value, start from this value</li>
\r
6691 * <li><tt>to</tt>* : start at current value, go to this value</li>
\r
6692 * <li><tt>unit</tt> : any allowable unit specification</li>
\r
6693 * <p>* do not specify both <tt>to</tt> and <tt>by</tt> for an animation property</p>
\r
6696 * <li><u>Animation Types</u></li>
\r
6698 * <p>The supported animation types:</p><div><ul class="mdetail-params">
\r
6699 * <li><tt>'run'</tt> : Default
\r
6701 var el = Ext.get('complexEl');
\r
6703 // animation control object
\r
6705 borderWidth: {to: 3, from: 0},
\r
6706 opacity: {to: .3, from: 1},
\r
6707 height: {to: 50, from: el.getHeight()},
\r
6708 width: {to: 300, from: el.getWidth()},
\r
6709 top : {by: - 100, unit: 'px'},
\r
6711 0.35, // animation duration
\r
6713 'easeOut', // easing method
\r
6714 'run' // animation type ('run','color','motion','scroll')
\r
6718 * <li><tt>'color'</tt>
\r
6719 * <p>Animates transition of background, text, or border colors.</p>
\r
6722 // animation control object
\r
6724 color: { to: '#06e' },
\r
6725 backgroundColor: { to: '#e06' }
\r
6727 0.35, // animation duration
\r
6729 'easeOut', // easing method
\r
6730 'color' // animation type ('run','color','motion','scroll')
\r
6735 * <li><tt>'motion'</tt>
\r
6736 * <p>Animates the motion of an element to/from specific points using optional bezier
\r
6737 * way points during transit.</p>
\r
6740 // animation control object
\r
6742 borderWidth: {to: 3, from: 0},
\r
6743 opacity: {to: .3, from: 1},
\r
6744 height: {to: 50, from: el.getHeight()},
\r
6745 width: {to: 300, from: el.getWidth()},
\r
6746 top : {by: - 100, unit: 'px'},
\r
6748 to: [50, 100], // go to this point
\r
6749 control: [ // optional bezier way points
\r
6755 3000, // animation duration (milliseconds!)
\r
6757 'easeOut', // easing method
\r
6758 'motion' // animation type ('run','color','motion','scroll')
\r
6762 * <li><tt>'scroll'</tt>
\r
6763 * <p>Animate horizontal or vertical scrolling of an overflowing page element.</p>
\r
6766 // animation control object
\r
6768 scroll: {to: [400, 300]}
\r
6770 0.35, // animation duration
\r
6772 'easeOut', // easing method
\r
6773 'scroll' // animation type ('run','color','motion','scroll')
\r
6781 * @param {Object} args The animation control args
\r
6782 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to <tt>.35</tt>)
\r
6783 * @param {Function} onComplete (optional) Function to call when animation completes
\r
6784 * @param {String} easing (optional) {@link Ext.Fx#easing} method to use (defaults to <tt>'easeOut'</tt>)
\r
6785 * @param {String} animType (optional) <tt>'run'</tt> is the default. Can also be <tt>'color'</tt>,
\r
6786 * <tt>'motion'</tt>, or <tt>'scroll'</tt>
\r
6787 * @return {Ext.Element} this
\r
6789 animate : function(args, duration, onComplete, easing, animType){
\r
6790 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
\r
6795 * @private Internal animation call
\r
6797 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
\r
6798 animType = animType || 'run';
\r
6801 anim = Ext.lib.Anim[animType](
\r
6804 (opt.duration || defaultDur) || .35,
\r
6805 (opt.easing || defaultEase) || 'easeOut',
\r
6807 if(cb) cb.call(me);
\r
6808 if(opt.callback) opt.callback.call(opt.scope || me, me, opt);
\r
6816 // private legacy anim prep
\r
6817 preanim : function(a, i){
\r
6818 return !a[i] ? false : (Ext.isObject(a[i]) ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
\r
6822 * Checks whether the element is currently visible using both visibility and display properties.
\r
6823 * @return {Boolean} True if the element is currently visible, else false
\r
6825 isVisible : function() {
\r
6826 return !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE);
\r
6830 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
\r
6831 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
\r
6832 * @param {Boolean} visible Whether the element is visible
\r
6833 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
\r
6834 * @return {Ext.Element} this
\r
6836 setVisible : function(visible, animate){
\r
6839 isDisplay = getVisMode(this.dom) == ELDISPLAY;
\r
6841 if (!animate || !me.anim) {
\r
6843 me.setDisplayed(visible);
\r
6846 dom.style.visibility = visible ? "visible" : HIDDEN;
\r
6849 // closure for composites
\r
6851 me.setOpacity(.01);
\r
6852 me.setVisible(true);
\r
6854 me.anim({opacity: { to: (visible?1:0) }},
\r
6855 me.preanim(arguments, 1),
\r
6861 dom.style[isDisplay ? DISPLAY : VISIBILITY] = (isDisplay) ? NONE : HIDDEN;
\r
6862 Ext.fly(dom).setOpacity(1);
\r
6870 * Toggles the element's visibility or display, depending on visibility mode.
\r
6871 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
\r
6872 * @return {Ext.Element} this
\r
6874 toggle : function(animate){
\r
6876 me.setVisible(!me.isVisible(), me.preanim(arguments, 0));
\r
6881 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
\r
6882 * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
\r
6883 * @return {Ext.Element} this
\r
6885 setDisplayed : function(value) {
\r
6886 if(typeof value == "boolean"){
\r
6887 value = value ? getDisplay(this.dom) : NONE;
\r
6889 this.setStyle(DISPLAY, value);
\r
6894 fixDisplay : function(){
\r
6896 if(me.isStyle(DISPLAY, NONE)){
\r
6897 me.setStyle(VISIBILITY, HIDDEN);
\r
6898 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
\r
6899 if(me.isStyle(DISPLAY, NONE)){ // if that fails, default to block
\r
6900 me.setStyle(DISPLAY, "block");
\r
6906 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
\r
6907 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
6908 * @return {Ext.Element} this
\r
6910 hide : function(animate){
\r
6911 this.setVisible(false, this.preanim(arguments, 0));
\r
6916 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
\r
6917 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
\r
6918 * @return {Ext.Element} this
\r
6920 show : function(animate){
\r
6921 this.setVisible(true, this.preanim(arguments, 0));
\r
6926 * @class Ext.Element
\r
6928 Ext.Element.addMethods(
\r
6930 var VISIBILITY = "visibility",
\r
6931 DISPLAY = "display",
\r
6932 HIDDEN = "hidden",
\r
6934 XMASKED = "x-masked",
\r
6935 XMASKEDRELATIVE = "x-masked-relative",
\r
6936 data = Ext.Element.data;
\r
6940 * Checks whether the element is currently visible using both visibility and display properties.
\r
6941 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
\r
6942 * @return {Boolean} True if the element is currently visible, else false
\r
6944 isVisible : function(deep) {
\r
6945 var vis = !this.isStyle(VISIBILITY,HIDDEN) && !this.isStyle(DISPLAY,NONE),
\r
6946 p = this.dom.parentNode;
\r
6947 if(deep !== true || !vis){
\r
6950 while(p && !/body/i.test(p.tagName)){
\r
6951 if(!Ext.fly(p, '_isVisible').isVisible()){
\r
6960 * Returns true if display is not "none"
\r
6961 * @return {Boolean}
\r
6963 isDisplayed : function() {
\r
6964 return !this.isStyle(DISPLAY, NONE);
\r
6968 * Convenience method for setVisibilityMode(Element.DISPLAY)
\r
6969 * @param {String} display (optional) What to set display to when visible
\r
6970 * @return {Ext.Element} this
\r
6972 enableDisplayMode : function(display){
\r
6973 this.setVisibilityMode(Ext.Element.DISPLAY);
\r
6974 if(!Ext.isEmpty(display)){
\r
6975 data(this.dom, 'originalDisplay', display);
\r
6981 * Puts a mask over this element to disable user interaction. Requires core.css.
\r
6982 * This method can only be applied to elements which accept child nodes.
\r
6983 * @param {String} msg (optional) A message to display in the mask
\r
6984 * @param {String} msgCls (optional) A css class to apply to the msg element
\r
6985 * @return {Element} The mask element
\r
6987 mask : function(msg, msgCls){
\r
6990 dh = Ext.DomHelper,
\r
6991 EXTELMASKMSG = "ext-el-mask-msg",
\r
6995 if(me.getStyle("position") == "static"){
\r
6996 me.addClass(XMASKEDRELATIVE);
\r
6998 if((el = data(dom, 'maskMsg'))){
\r
7001 if((el = data(dom, 'mask'))){
\r
7005 mask = dh.append(dom, {cls : "ext-el-mask"}, true);
\r
7006 data(dom, 'mask', mask);
\r
7008 me.addClass(XMASKED);
\r
7009 mask.setDisplayed(true);
\r
7010 if(typeof msg == 'string'){
\r
7011 var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
\r
7012 data(dom, 'maskMsg', mm);
\r
7013 mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
\r
7014 mm.dom.firstChild.innerHTML = msg;
\r
7015 mm.setDisplayed(true);
\r
7018 if(Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto'){ // ie will not expand full height automatically
\r
7019 mask.setSize(undefined, me.getHeight());
\r
7025 * Removes a previously applied mask.
\r
7027 unmask : function(){
\r
7030 mask = data(dom, 'mask'),
\r
7031 maskMsg = data(dom, 'maskMsg');
\r
7035 data(dom, 'maskMsg', undefined);
\r
7038 data(dom, 'mask', undefined);
\r
7040 me.removeClass([XMASKED, XMASKEDRELATIVE]);
\r
7044 * Returns true if this element is masked
\r
7045 * @return {Boolean}
\r
7047 isMasked : function(){
\r
7048 var m = data(this.dom, 'mask');
\r
7049 return m && m.isVisible();
\r
7053 * Creates an iframe shim for this element to keep selects and other windowed objects from
\r
7054 * showing through.
\r
7055 * @return {Ext.Element} The new shim element
\r
7057 createShim : function(){
\r
7058 var el = document.createElement('iframe'),
\r
7060 el.frameBorder = '0';
\r
7061 el.className = 'ext-shim';
\r
7062 el.src = Ext.SSL_SECURE_URL;
\r
7063 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
\r
7064 shim.autoBoxAdjust = false;
\r
7069 * @class Ext.Element
\r
7071 Ext.Element.addMethods({
\r
7073 * Convenience method for constructing a KeyMap
\r
7074 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
\r
7075 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
\r
7076 * @param {Function} fn The function to call
\r
7077 * @param {Object} scope (optional) The scope of the function
\r
7078 * @return {Ext.KeyMap} The KeyMap created
\r
7080 addKeyListener : function(key, fn, scope){
\r
7082 if(!Ext.isObject(key) || Ext.isArray(key)){
\r
7091 shift : key.shift,
\r
7098 return new Ext.KeyMap(this, config);
\r
7102 * Creates a KeyMap for this element
\r
7103 * @param {Object} config The KeyMap config. See {@link Ext.KeyMap} for more details
\r
7104 * @return {Ext.KeyMap} The KeyMap created
\r
7106 addKeyMap : function(config){
\r
7107 return new Ext.KeyMap(this, config);
\r
7112 UNDEFINED = undefined,
\r
7119 BOTTOM = "bottom",
\r
7122 HEIGHT = "height",
\r
7124 POINTS = "points",
\r
7125 HIDDEN = "hidden",
\r
7126 ABSOLUTE = "absolute",
\r
7127 VISIBLE = "visible",
\r
7128 MOTION = "motion",
\r
7129 POSITION = "position",
\r
7130 EASEOUT = "easeOut",
\r
7132 * Use a light flyweight here since we are using so many callbacks and are always assured a DOM element
\r
7134 flyEl = new Ext.Element.Flyweight(),
\r
7136 getObject = function(o){
\r
7139 fly = function(dom){
\r
7141 flyEl.id = Ext.id(dom);
\r
7145 * Queueing now stored outside of the element due to closure issues
\r
7147 getQueue = function(id){
\r
7151 return queues[id];
\r
7153 setQueue = function(id, value){
\r
7154 queues[id] = value;
\r
7157 //Notifies Element that fx methods are available
\r
7158 Ext.enableFx = TRUE;
\r
7162 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
\r
7163 * to the {@link Ext.Element} interface when included, so all effects calls should be performed via {@link Ext.Element}.
\r
7164 * Conversely, since the effects are not actually defined in {@link Ext.Element}, Ext.Fx <b>must</b> be
\r
7165 * {@link Ext#enableFx included} in order for the Element effects to work.</p><br/>
\r
7167 * <p><b><u>Method Chaining</u></b></p>
\r
7168 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
\r
7169 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
\r
7170 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
\r
7171 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
\r
7172 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
\r
7173 * expected results and should be done with care. Also see <tt>{@link #callback}</tt>.</p><br/>
\r
7175 * <p><b><u>Anchor Options for Motion Effects</u></b></p>
\r
7176 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
\r
7177 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
\r
7180 ----- -----------------------------
\r
7181 tl The top left corner
\r
7182 t The center of the top edge
\r
7183 tr The top right corner
\r
7184 l The center of the left edge
\r
7185 r The center of the right edge
\r
7186 bl The bottom left corner
\r
7187 b The center of the bottom edge
\r
7188 br The bottom right corner
\r
7190 * <b>Note</b>: some Fx methods accept specific custom config parameters. The options shown in the Config Options
\r
7191 * section below are common options that can be passed to any Fx method unless otherwise noted.</b>
\r
7193 * @cfg {Function} callback A function called when the effect is finished. Note that effects are queued internally by the
\r
7194 * Fx class, so a callback is not required to specify another effect -- effects can simply be chained together
\r
7195 * and called in sequence (see note for <b><u>Method Chaining</u></b> above), for example:<pre><code>
\r
7196 * el.slideIn().highlight();
\r
7198 * The callback is intended for any additional code that should run once a particular effect has completed. The Element
\r
7199 * being operated upon is passed as the first parameter.
\r
7201 * @cfg {Object} scope The scope (<code>this</code> reference) in which the <tt>{@link #callback}</tt> function is executed. Defaults to the browser window.
\r
7203 * @cfg {String} easing A valid Ext.lib.Easing value for the effect:</p><div class="mdetail-params"><ul>
\r
7204 * <li><b><tt>backBoth</tt></b></li>
\r
7205 * <li><b><tt>backIn</tt></b></li>
\r
7206 * <li><b><tt>backOut</tt></b></li>
\r
7207 * <li><b><tt>bounceBoth</tt></b></li>
\r
7208 * <li><b><tt>bounceIn</tt></b></li>
\r
7209 * <li><b><tt>bounceOut</tt></b></li>
\r
7210 * <li><b><tt>easeBoth</tt></b></li>
\r
7211 * <li><b><tt>easeBothStrong</tt></b></li>
\r
7212 * <li><b><tt>easeIn</tt></b></li>
\r
7213 * <li><b><tt>easeInStrong</tt></b></li>
\r
7214 * <li><b><tt>easeNone</tt></b></li>
\r
7215 * <li><b><tt>easeOut</tt></b></li>
\r
7216 * <li><b><tt>easeOutStrong</tt></b></li>
\r
7217 * <li><b><tt>elasticBoth</tt></b></li>
\r
7218 * <li><b><tt>elasticIn</tt></b></li>
\r
7219 * <li><b><tt>elasticOut</tt></b></li>
\r
7222 * @cfg {String} afterCls A css class to apply after the effect
\r
7223 * @cfg {Number} duration The length of time (in seconds) that the effect should last
\r
7225 * @cfg {Number} endOpacity Only applicable for {@link #fadeIn} or {@link #fadeOut}, a number between
\r
7226 * <tt>0</tt> and <tt>1</tt> inclusive to configure the ending opacity value.
\r
7228 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
\r
7229 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
\r
7230 * effects that end with the element being visually hidden, ignored otherwise)
\r
7231 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. <tt>"width:100px"</tt>, or an object
\r
7232 * in the form <tt>{width:"100px"}</tt>, or a function which returns such a specification that will be applied to the
\r
7233 * Element after the effect finishes.
\r
7234 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
\r
7235 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
\r
7236 * @cfg {Boolean} stopFx Whether preceding effects should be stopped and removed before running current effect (only applies to non blocking effects)
\r
7240 // private - calls the function taking arguments from the argHash based on the key. Returns the return value of the function.
\r
7241 // this is useful for replacing switch statements (for example).
\r
7242 switchStatements : function(key, fn, argHash){
\r
7243 return fn.apply(this, argHash[key]);
\r
7247 * Slides the element into view. An anchor point can be optionally passed to set the point of
\r
7248 * origin for the slide effect. This function automatically handles wrapping the element with
\r
7249 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
\r
7252 // default: slide the element in from the top
\r
7255 // custom: slide the element in from the right with a 2-second duration
\r
7256 el.slideIn('r', { duration: 2 });
\r
7258 // common config options shown with default values
\r
7260 easing: 'easeOut',
\r
7264 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
\r
7265 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7266 * @return {Ext.Element} The Element
\r
7268 slideIn : function(anchor, o){
\r
7284 anchor = anchor || "t";
\r
7286 me.queueFx(o, function(){
\r
7287 xy = fly(dom).getXY();
\r
7288 // fix display to visibility
\r
7289 fly(dom).fixDisplay();
\r
7291 // restore values after effect
\r
7292 r = fly(dom).getFxRestore();
\r
7293 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
\r
7294 b.right = b.x + b.width;
\r
7295 b.bottom = b.y + b.height;
\r
7297 // fixed size for slide
\r
7298 fly(dom).setWidth(b.width).setHeight(b.height);
\r
7301 wrap = fly(dom).fxWrap(r.pos, o, HIDDEN);
\r
7303 st.visibility = VISIBLE;
\r
7304 st.position = ABSOLUTE;
\r
7306 // clear out temp styles after slide and unwrap
\r
7308 fly(dom).fxUnwrap(wrap, r.pos, o);
\r
7309 st.width = r.width;
\r
7310 st.height = r.height;
\r
7311 fly(dom).afterFx(o);
\r
7314 // time to calculate the positions
\r
7315 pt = {to: [b.x, b.y]};
\r
7316 bw = {to: b.width};
\r
7317 bh = {to: b.height};
\r
7319 function argCalc(wrap, style, ww, wh, sXY, sXYval, s1, s2, w, h, p){
\r
7321 fly(wrap).setWidth(ww).setHeight(wh);
\r
7322 if(fly(wrap)[sXY]){
\r
7323 fly(wrap)[sXY](sXYval);
\r
7325 style[s1] = style[s2] = "0";
\r
7338 args = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
\r
7339 t : [wrap, st, b.width, 0, NULL, NULL, LEFT, BOTTOM, NULL, bh, NULL],
\r
7340 l : [wrap, st, 0, b.height, NULL, NULL, RIGHT, TOP, bw, NULL, NULL],
\r
7341 r : [wrap, st, b.width, b.height, SETX, b.right, LEFT, TOP, NULL, NULL, pt],
\r
7342 b : [wrap, st, b.width, b.height, SETY, b.bottom, LEFT, TOP, NULL, bh, pt],
\r
7343 tl : [wrap, st, 0, 0, NULL, NULL, RIGHT, BOTTOM, bw, bh, pt],
\r
7344 bl : [wrap, st, 0, 0, SETY, b.y + b.height, RIGHT, TOP, bw, bh, pt],
\r
7345 br : [wrap, st, 0, 0, SETXY, [b.right, b.bottom], LEFT, TOP, bw, bh, pt],
\r
7346 tr : [wrap, st, 0, 0, SETX, b.x + b.width, LEFT, BOTTOM, bw, bh, pt]
\r
7349 st.visibility = VISIBLE;
\r
7352 arguments.callee.anim = fly(wrap).fxanim(args,
\r
7363 * Slides the element out of view. An anchor point can be optionally passed to set the end point
\r
7364 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
\r
7365 * 'hidden') but block elements will still take up space in the document. The element must be removed
\r
7366 * from the DOM using the 'remove' config option if desired. This function automatically handles
\r
7367 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
\r
7370 // default: slide the element out to the top
\r
7373 // custom: slide the element out to the right with a 2-second duration
\r
7374 el.slideOut('r', { duration: 2 });
\r
7376 // common config options shown with default values
\r
7377 el.slideOut('t', {
\r
7378 easing: 'easeOut',
\r
7384 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
\r
7385 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7386 * @return {Ext.Element} The Element
\r
7388 slideOut : function(anchor, o){
\r
7400 anchor = anchor || "t";
\r
7402 me.queueFx(o, function(){
\r
7404 // restore values after effect
\r
7405 r = fly(dom).getFxRestore();
\r
7406 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
\r
7407 b.right = b.x + b.width;
\r
7408 b.bottom = b.y + b.height;
\r
7410 // fixed size for slide
\r
7411 fly(dom).setWidth(b.width).setHeight(b.height);
\r
7414 wrap = fly(dom).fxWrap(r.pos, o, VISIBLE);
\r
7416 st.visibility = VISIBLE;
\r
7417 st.position = ABSOLUTE;
\r
7418 fly(wrap).setWidth(b.width).setHeight(b.height);
\r
7421 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();
\r
7422 fly(dom).fxUnwrap(wrap, r.pos, o);
\r
7423 st.width = r.width;
\r
7424 st.height = r.height;
\r
7425 fly(dom).afterFx(o);
\r
7428 function argCalc(style, s1, s2, p1, v1, p2, v2, p3, v3){
\r
7431 style[s1] = style[s2] = "0";
\r
7443 a = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
\r
7444 t : [st, LEFT, BOTTOM, HEIGHT, zero],
\r
7445 l : [st, RIGHT, TOP, WIDTH, zero],
\r
7446 r : [st, LEFT, TOP, WIDTH, zero, POINTS, {to : [b.right, b.y]}],
\r
7447 b : [st, LEFT, TOP, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
\r
7448 tl : [st, RIGHT, BOTTOM, WIDTH, zero, HEIGHT, zero],
\r
7449 bl : [st, RIGHT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
\r
7450 br : [st, LEFT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x + b.width, b.bottom]}],
\r
7451 tr : [st, LEFT, BOTTOM, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.right, b.y]}]
\r
7454 arguments.callee.anim = fly(wrap).fxanim(a,
\r
7465 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
\r
7466 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
\r
7467 * The element must be removed from the DOM using the 'remove' config option if desired.
\r
7473 // common config options shown with default values
\r
7475 easing: 'easeOut',
\r
7481 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7482 * @return {Ext.Element} The Element
\r
7484 puff : function(o){
\r
7493 me.queueFx(o, function(){
\r
7494 width = fly(dom).getWidth();
\r
7495 height = fly(dom).getHeight();
\r
7496 fly(dom).clearOpacity();
\r
7499 // restore values after effect
\r
7500 r = fly(dom).getFxRestore();
\r
7503 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();
\r
7504 fly(dom).clearOpacity();
\r
7505 fly(dom).setPositioning(r.pos);
\r
7506 st.width = r.width;
\r
7507 st.height = r.height;
\r
7509 fly(dom).afterFx(o);
\r
7512 arguments.callee.anim = fly(dom).fxanim({
\r
7513 width : {to : fly(dom).adjustWidth(width * 2)},
\r
7514 height : {to : fly(dom).adjustHeight(height * 2)},
\r
7515 points : {by : [-width * .5, -height * .5]},
\r
7516 opacity : {to : 0},
\r
7517 fontSize: {to : 200, unit: "%"}
\r
7529 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
\r
7530 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
\r
7531 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
\r
7537 // all config options shown with default values
\r
7545 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7546 * @return {Ext.Element} The Element
\r
7548 switchOff : function(o){
\r
7555 me.queueFx(o, function(){
\r
7556 fly(dom).clearOpacity();
\r
7559 // restore values after effect
\r
7560 r = fly(dom).getFxRestore();
\r
7563 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();
\r
7564 fly(dom).clearOpacity();
\r
7565 fly(dom).setPositioning(r.pos);
\r
7566 st.width = r.width;
\r
7567 st.height = r.height;
\r
7568 fly(dom).afterFx(o);
\r
7571 fly(dom).fxanim({opacity : {to : 0.3}},
\r
7577 fly(dom).clearOpacity();
\r
7580 height : {to : 1},
\r
7581 points : {by : [0, fly(dom).getHeight() * .5]}
\r
7595 * Highlights the Element by setting a color (applies to the background-color by default, but can be
\r
7596 * changed using the "attr" config option) and then fading back to the original color. If no original
\r
7597 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
\r
7600 // default: highlight background to yellow
\r
7603 // custom: highlight foreground text to blue for 2 seconds
\r
7604 el.highlight("0000ff", { attr: 'color', duration: 2 });
\r
7606 // common config options shown with default values
\r
7607 el.highlight("ffff9c", {
\r
7608 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
\r
7609 endColor: (current color) or "ffffff",
\r
7614 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
\r
7615 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7616 * @return {Ext.Element} The Element
\r
7618 highlight : function(color, o){
\r
7622 attr = o.attr || "backgroundColor",
\r
7626 me.queueFx(o, function(){
\r
7627 fly(dom).clearOpacity();
\r
7631 dom.style[attr] = restore;
\r
7632 fly(dom).afterFx(o);
\r
7634 restore = dom.style[attr];
\r
7635 a[attr] = {from: color || "ffff9c", to: o.endColor || fly(dom).getColor(attr) || "ffffff"};
\r
7636 arguments.callee.anim = fly(dom).fxanim(a,
\r
7647 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
\r
7650 // default: a single light blue ripple
\r
7653 // custom: 3 red ripples lasting 3 seconds total
\r
7654 el.frame("ff0000", 3, { duration: 3 });
\r
7656 // common config options shown with default values
\r
7657 el.frame("C3DAF9", 1, {
\r
7658 duration: 1 //duration of each individual ripple.
\r
7659 // Note: Easing is not configurable and will be ignored if included
\r
7662 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
\r
7663 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
\r
7664 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7665 * @return {Ext.Element} The Element
\r
7667 frame : function(color, count, o){
\r
7674 me.queueFx(o, function(){
\r
7675 color = color || '#C3DAF9'
\r
7676 if(color.length == 6){
\r
7677 color = '#' + color;
\r
7679 count = count || 1;
\r
7682 var xy = fly(dom).getXY(),
\r
7683 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight},
\r
7684 queue = function(){
\r
7685 proxy = fly(document.body || document.documentElement).createChild({
\r
7687 position : ABSOLUTE,
\r
7688 'z-index': 35000, // yee haw
\r
7689 border : '0px solid ' + color
\r
7692 return proxy.queueFx({}, animFn);
\r
7696 arguments.callee.anim = {
\r
7698 stop: function() {
\r
7704 function animFn(){
\r
7705 var scale = Ext.isBorderBox ? 2 : 1;
\r
7706 active = proxy.anim({
\r
7707 top : {from : b.y, to : b.y - 20},
\r
7708 left : {from : b.x, to : b.x - 20},
\r
7709 borderWidth : {from : 0, to : 10},
\r
7710 opacity : {from : 1, to : 0},
\r
7711 height : {from : b.height, to : b.height + 20 * scale},
\r
7712 width : {from : b.width, to : b.width + 20 * scale}
\r
7714 duration: o.duration || 1,
\r
7715 callback: function() {
\r
7717 --count > 0 ? queue() : fly(dom).afterFx(o);
\r
7720 arguments.callee.anim = {
\r
7733 * Creates a pause before any subsequent queued effects begin. If there are
\r
7734 * no effects queued after the pause it will have no effect.
\r
7739 * @param {Number} seconds The length of time to pause (in seconds)
\r
7740 * @return {Ext.Element} The Element
\r
7742 pause : function(seconds){
\r
7743 var dom = this.dom,
\r
7746 this.queueFx({}, function(){
\r
7747 t = setTimeout(function(){
\r
7748 fly(dom).afterFx({});
\r
7749 }, seconds * 1000);
\r
7750 arguments.callee.anim = {
\r
7754 fly(dom).afterFx({});
\r
7762 * Fade an element in (from transparent to opaque). The ending opacity can be specified
\r
7763 * using the <tt>{@link #endOpacity}</tt> config option.
\r
7766 // default: fade in from opacity 0 to 100%
\r
7769 // custom: fade in from opacity 0 to 75% over 2 seconds
\r
7770 el.fadeIn({ endOpacity: .75, duration: 2});
\r
7772 // common config options shown with default values
\r
7774 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
\r
7775 easing: 'easeOut',
\r
7779 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7780 * @return {Ext.Element} The Element
\r
7782 fadeIn : function(o){
\r
7786 to = o.endOpacity || 1;
\r
7788 me.queueFx(o, function(){
\r
7789 fly(dom).setOpacity(0);
\r
7790 fly(dom).fixDisplay();
\r
7791 dom.style.visibility = VISIBLE;
\r
7792 arguments.callee.anim = fly(dom).fxanim({opacity:{to:to}},
\r
7793 o, NULL, .5, EASEOUT, function(){
\r
7795 fly(dom).clearOpacity();
\r
7797 fly(dom).afterFx(o);
\r
7804 * Fade an element out (from opaque to transparent). The ending opacity can be specified
\r
7805 * using the <tt>{@link #endOpacity}</tt> config option. Note that IE may require
\r
7806 * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
\r
7809 // default: fade out from the element's current opacity to 0
\r
7812 // custom: fade out from the element's current opacity to 25% over 2 seconds
\r
7813 el.fadeOut({ endOpacity: .25, duration: 2});
\r
7815 // common config options shown with default values
\r
7817 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
\r
7818 easing: 'easeOut',
\r
7824 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7825 * @return {Ext.Element} The Element
\r
7827 fadeOut : function(o){
\r
7831 style = dom.style,
\r
7832 to = o.endOpacity || 0;
\r
7834 me.queueFx(o, function(){
\r
7835 arguments.callee.anim = fly(dom).fxanim({
\r
7836 opacity : {to : to}},
\r
7843 Ext.Element.data(dom, 'visibilityMode') == Ext.Element.DISPLAY || o.useDisplay ?
\r
7844 style.display = "none" :
\r
7845 style.visibility = HIDDEN;
\r
7847 fly(dom).clearOpacity();
\r
7849 fly(dom).afterFx(o);
\r
7856 * Animates the transition of an element's dimensions from a starting height/width
\r
7857 * to an ending height/width. This method is a convenience implementation of {@link shift}.
\r
7860 // change height and width to 100x100 pixels
\r
7861 el.scale(100, 100);
\r
7863 // common config options shown with default values. The height and width will default to
\r
7864 // the element's existing values if passed as null.
\r
7866 [element's width],
\r
7867 [element's height], {
\r
7868 easing: 'easeOut',
\r
7873 * @param {Number} width The new width (pass undefined to keep the original width)
\r
7874 * @param {Number} height The new height (pass undefined to keep the original height)
\r
7875 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7876 * @return {Ext.Element} The Element
\r
7878 scale : function(w, h, o){
\r
7879 this.shift(Ext.apply({}, o, {
\r
7887 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
\r
7888 * Any of these properties not specified in the config object will not be changed. This effect
\r
7889 * requires that at least one new dimension, position or opacity setting must be passed in on
\r
7890 * the config object in order for the function to have any effect.
\r
7893 // slide the element horizontally to x position 200 while changing the height and opacity
\r
7894 el.shift({ x: 200, height: 50, opacity: .8 });
\r
7896 // common config options shown with default values.
\r
7898 width: [element's width],
\r
7899 height: [element's height],
\r
7900 x: [element's x position],
\r
7901 y: [element's y position],
\r
7902 opacity: [element's opacity],
\r
7903 easing: 'easeOut',
\r
7907 * @param {Object} options Object literal with any of the Fx config options
\r
7908 * @return {Ext.Element} The Element
\r
7910 shift : function(o){
\r
7912 var dom = this.dom,
\r
7915 this.queueFx(o, function(){
\r
7916 for (var prop in o) {
\r
7917 if (o[prop] != UNDEFINED) {
\r
7918 a[prop] = {to : o[prop]};
\r
7922 a.width ? a.width.to = fly(dom).adjustWidth(o.width) : a;
\r
7923 a.height ? a.height.to = fly(dom).adjustWidth(o.height) : a;
\r
7925 if (a.x || a.y || a.xy) {
\r
7926 a.points = a.xy ||
\r
7927 {to : [ a.x ? a.x.to : fly(dom).getX(),
\r
7928 a.y ? a.y.to : fly(dom).getY()]};
\r
7931 arguments.callee.anim = fly(dom).fxanim(a,
\r
7937 fly(dom).afterFx(o);
\r
7944 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
\r
7945 * ending point of the effect.
\r
7948 // default: slide the element downward while fading out
\r
7951 // custom: slide the element out to the right with a 2-second duration
\r
7952 el.ghost('r', { duration: 2 });
\r
7954 // common config options shown with default values
\r
7956 easing: 'easeOut',
\r
7962 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
\r
7963 * @param {Object} options (optional) Object literal with any of the Fx config options
\r
7964 * @return {Ext.Element} The Element
\r
7966 ghost : function(anchor, o){
\r
7971 a = {opacity: {to: 0}, points: {}},
\r
7977 anchor = anchor || "b";
\r
7979 me.queueFx(o, function(){
\r
7980 // restore values after effect
\r
7981 r = fly(dom).getFxRestore();
\r
7982 w = fly(dom).getWidth();
\r
7983 h = fly(dom).getHeight();
\r
7986 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();
\r
7987 fly(dom).clearOpacity();
\r
7988 fly(dom).setPositioning(r.pos);
\r
7989 st.width = r.width;
\r
7990 st.height = r.height;
\r
7991 fly(dom).afterFx(o);
\r
7994 pt.by = fly(dom).switchStatements(anchor.toLowerCase(), function(v1,v2){ return [v1, v2];}, {
\r
8005 arguments.callee.anim = fly(dom).fxanim(a,
\r
8015 * Ensures that all effects queued after syncFx is called on the element are
\r
8016 * run concurrently. This is the opposite of {@link #sequenceFx}.
\r
8017 * @return {Ext.Element} The Element
\r
8019 syncFx : function(){
\r
8021 me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
\r
8023 concurrent : TRUE,
\r
8030 * Ensures that all effects queued after sequenceFx is called on the element are
\r
8031 * run in sequence. This is the opposite of {@link #syncFx}.
\r
8032 * @return {Ext.Element} The Element
\r
8034 sequenceFx : function(){
\r
8036 me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
\r
8038 concurrent : FALSE,
\r
8045 nextFx : function(){
\r
8046 var ef = getQueue(this.dom.id)[0];
\r
8053 * Returns true if the element has any effects actively running or queued, else returns false.
\r
8054 * @return {Boolean} True if element has active effects, else false
\r
8056 hasActiveFx : function(){
\r
8057 return getQueue(this.dom.id)[0];
\r
8061 * Stops any running effects and clears the element's internal effects queue if it contains
\r
8062 * any additional effects that haven't started yet.
\r
8063 * @return {Ext.Element} The Element
\r
8065 stopFx : function(finish){
\r
8068 if(me.hasActiveFx()){
\r
8069 var cur = getQueue(id)[0];
\r
8070 if(cur && cur.anim){
\r
8071 if(cur.anim.isAnimated){
\r
8072 setQueue(id, [cur]); //clear
\r
8073 cur.anim.stop(finish !== undefined ? finish : TRUE);
\r
8083 beforeFx : function(o){
\r
8084 if(this.hasActiveFx() && !o.concurrent){
\r
8095 * Returns true if the element is currently blocking so that no other effect can be queued
\r
8096 * until this effect is finished, else returns false if blocking is not set. This is commonly
\r
8097 * used to ensure that an effect initiated by a user action runs to completion prior to the
\r
8098 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
\r
8099 * @return {Boolean} True if blocking, else false
\r
8101 hasFxBlock : function(){
\r
8102 var q = getQueue(this.dom.id);
\r
8103 return q && q[0] && q[0].block;
\r
8107 queueFx : function(o, fn){
\r
8108 var me = fly(this.dom);
\r
8109 if(!me.hasFxBlock()){
\r
8110 Ext.applyIf(o, me.fxDefaults);
\r
8111 if(!o.concurrent){
\r
8112 var run = me.beforeFx(o);
\r
8113 fn.block = o.block;
\r
8114 getQueue(me.dom.id).push(fn);
\r
8126 fxWrap : function(pos, o, vis){
\r
8127 var dom = this.dom,
\r
8130 if(!o.wrap || !(wrap = Ext.getDom(o.wrap))){
\r
8131 if(o.fixPosition){
\r
8132 wrapXY = fly(dom).getXY();
\r
8134 var div = document.createElement("div");
\r
8135 div.style.visibility = vis;
\r
8136 wrap = dom.parentNode.insertBefore(div, dom);
\r
8137 fly(wrap).setPositioning(pos);
\r
8138 if(fly(wrap).isStyle(POSITION, "static")){
\r
8139 fly(wrap).position("relative");
\r
8141 fly(dom).clearPositioning('auto');
\r
8143 wrap.appendChild(dom);
\r
8145 fly(wrap).setXY(wrapXY);
\r
8152 fxUnwrap : function(wrap, pos, o){
\r
8153 var dom = this.dom;
\r
8154 fly(dom).clearPositioning();
\r
8155 fly(dom).setPositioning(pos);
\r
8157 var pn = fly(wrap).dom.parentNode;
8158 pn.insertBefore(dom, wrap);
\r
8159 fly(wrap).remove();
\r
8164 getFxRestore : function(){
\r
8165 var st = this.dom.style;
\r
8166 return {pos: this.getPositioning(), width: st.width, height : st.height};
\r
8170 afterFx : function(o){
\r
8171 var dom = this.dom,
\r
8174 fly(dom).setStyle(o.afterStyle);
\r
8177 fly(dom).addClass(o.afterCls);
\r
8179 if(o.remove == TRUE){
\r
8180 fly(dom).remove();
\r
8183 o.callback.call(o.scope, fly(dom));
\r
8185 if(!o.concurrent){
\r
8186 getQueue(id).shift();
\r
8187 fly(dom).nextFx();
\r
8192 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
\r
8193 animType = animType || 'run';
\r
8195 var anim = Ext.lib.Anim[animType](
\r
8198 (opt.duration || defaultDur) || .35,
\r
8199 (opt.easing || defaultEase) || EASEOUT,
\r
8208 // backwards compat
\r
8209 Ext.Fx.resize = Ext.Fx.scale;
\r
8211 //When included, Ext.Fx is automatically applied to Element so that all basic
\r
8212 //effects are available directly via the Element API
\r
8213 Ext.Element.addMethods(Ext.Fx);
\r
8216 * @class Ext.CompositeElementLite
\r
8217 * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
\r
8218 * members, or to perform collective actions upon the whole set.</p>
\r
8219 * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
\r
8220 * {@link Ext.Fx}. The methods from these classes will be performed on all the elements in this collection.</p>
\r
8221 * Example:<pre><code>
\r
8222 var els = Ext.select("#some-el div.some-class");
\r
8223 // or select directly from an existing element
\r
8224 var el = Ext.get('some-el');
\r
8225 el.select('div.some-class');
\r
8227 els.setWidth(100); // all elements become 100 width
\r
8228 els.hide(true); // all elements fade out and hide
\r
8230 els.setWidth(100).hide(true);
\r
8233 Ext.CompositeElementLite = function(els, root){
\r
8235 * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
\r
8236 * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
\r
8237 * to augment the capabilities of the CompositeElementLite class may use it when adding
\r
8238 * methods to the class.</p>
\r
8239 * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
\r
8240 * following siblings of selected elements, the code would be</p><code><pre>
\r
8241 Ext.override(Ext.CompositeElementLite, {
\r
8242 nextAll: function() {
\r
8243 var els = this.elements, i, l = els.length, n, r = [], ri = -1;
\r
8245 // Loop through all elements in this Composite, accumulating
\r
8246 // an Array of all siblings.
\r
8247 for (i = 0; i < l; i++) {
\r
8248 for (n = els[i].nextSibling; n; n = n.nextSibling) {
\r
8253 // Add all found siblings to this Composite
\r
8254 return this.add(r);
\r
8258 * @property elements
\r
8260 this.elements = [];
\r
8261 this.add(els, root);
\r
8262 this.el = new Ext.Element.Flyweight();
\r
8265 Ext.CompositeElementLite.prototype = {
\r
8266 isComposite: true,
\r
8268 * Returns the number of elements in this Composite.
\r
8271 getCount : function(){
\r
8272 return this.elements.length;
\r
8275 * Adds elements to this Composite object.
\r
8276 * @param {Mixed} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
\r
8277 * @return {CompositeElement} This Composite object.
\r
8279 add : function(els){
\r
8281 if (Ext.isArray(els)) {
\r
8282 this.elements = this.elements.concat(els);
\r
8284 var yels = this.elements;
\r
8285 Ext.each(els, function(e) {
\r
8292 invoke : function(fn, args){
\r
8293 var els = this.elements,
\r
8295 Ext.each(els, function(e) {
\r
8297 Ext.Element.prototype[fn].apply(el, args);
\r
8302 * Returns a flyweight Element of the dom element object at the specified index
\r
8303 * @param {Number} index
\r
8304 * @return {Ext.Element}
\r
8306 item : function(index){
\r
8308 if(!me.elements[index]){
\r
8311 me.el.dom = me.elements[index];
\r
8315 // fixes scope with flyweight
\r
8316 addListener : function(eventName, handler, scope, opt){
\r
8317 Ext.each(this.elements, function(e) {
\r
8318 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
\r
8323 * <p>Calls the passed function for each element in this composite.</p>
\r
8324 * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
\r
8325 * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
\r
8326 * <b>This is the flyweight (shared) Ext.Element instance, so if you require a
\r
8327 * a reference to the dom node, use el.dom.</b></div></li>
\r
8328 * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
\r
8329 * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
\r
8331 * @param {Object} scope (optional) The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
\r
8332 * @return {CompositeElement} this
\r
8334 each : function(fn, scope){
\r
8338 Ext.each(me.elements, function(e,i) {
\r
8340 return fn.call(scope || el, el, me, i);
\r
8346 * Clears this Composite and adds the elements passed.
\r
8347 * @param {Mixed} els Either an array of DOM elements, or another Composite from which to fill this Composite.
\r
8348 * @return {CompositeElement} this
\r
8350 fill : function(els){
\r
8358 * Filters this composite to only elements that match the passed selector.
\r
8359 * @param {String/Function} selector A string CSS selector or a comparison function.
\r
8360 * The comparison function will be called with the following arguments:<ul>
\r
8361 * <li><code>el</code> : Ext.Element<div class="sub-desc">The current DOM element.</div></li>
\r
8362 * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
\r
8364 * @return {CompositeElement} this
\r
8366 filter : function(selector){
\r
8369 fn = Ext.isFunction(selector) ? selector
\r
8371 return el.is(selector);
\r
8373 me.each(function(el, self, i){
\r
8374 if(fn(el, i) !== false){
\r
8375 els[els.length] = el.dom;
\r
8383 * Find the index of the passed element within the composite collection.
\r
8384 * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
\r
8385 * @return Number The index of the passed Ext.Element in the composite collection, or -1 if not found.
\r
8387 indexOf : function(el){
\r
8388 return this.elements.indexOf(Ext.getDom(el));
\r
8392 * Replaces the specified element with the passed element.
\r
8393 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
\r
8395 * @param {Mixed} replacement The id of an element or the Element itself.
\r
8396 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
\r
8397 * @return {CompositeElement} this
\r
8399 replaceElement : function(el, replacement, domReplace){
\r
8400 var index = !isNaN(el) ? el : this.indexOf(el),
\r
8403 replacement = Ext.getDom(replacement);
\r
8405 d = this.elements[index];
\r
8406 d.parentNode.insertBefore(replacement, d);
\r
8407 Ext.removeNode(d);
\r
8409 this.elements.splice(index, 1, replacement);
\r
8415 * Removes all elements.
\r
8417 clear : function(){
\r
8418 this.elements = [];
\r
8422 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
\r
8426 ElProto = Ext.Element.prototype,
\r
8427 CelProto = Ext.CompositeElementLite.prototype;
\r
8429 for(fnName in ElProto){
\r
8430 if(Ext.isFunction(ElProto[fnName])){
\r
8431 (function(fnName){
\r
8432 CelProto[fnName] = CelProto[fnName] || function(){
\r
8433 return this.invoke(fnName, arguments);
\r
8435 }).call(CelProto, fnName);
\r
8442 Ext.Element.selectorFunction = Ext.DomQuery.select;
\r
8446 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
\r
8447 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
\r
8448 * {@link Ext.CompositeElementLite CompositeElementLite} object.
\r
8449 * @param {String/Array} selector The CSS selector or an array of elements
\r
8450 * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object) <b>Not supported in core</b>
\r
8451 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
\r
8452 * @return {CompositeElementLite/CompositeElement}
\r
8453 * @member Ext.Element
\r
8456 Ext.Element.select = function(selector, unique, root){
\r
8458 if(typeof selector == "string"){
\r
8459 els = Ext.Element.selectorFunction(selector, root);
\r
8460 }else if(selector.length !== undefined){
\r
8463 throw "Invalid selector";
\r
8465 return new Ext.CompositeElementLite(els);
\r
8468 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
\r
8469 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
\r
8470 * {@link Ext.CompositeElementLite CompositeElementLite} object.
\r
8471 * @param {String/Array} selector The CSS selector or an array of elements
\r
8472 * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
\r
8473 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
\r
8474 * @return {CompositeElementLite/CompositeElement}
\r
8478 Ext.select = Ext.Element.select;/**
\r
8479 * @class Ext.CompositeElementLite
\r
8481 Ext.apply(Ext.CompositeElementLite.prototype, {
\r
8482 addElements : function(els, root){
\r
8486 if(typeof els == "string"){
\r
8487 els = Ext.Element.selectorFunction(els, root);
\r
8489 var yels = this.elements;
\r
8490 Ext.each(els, function(e) {
\r
8491 yels.push(Ext.get(e));
\r
8497 * Returns the first Element
\r
8498 * @return {Ext.Element}
\r
8500 first : function(){
\r
8501 return this.item(0);
\r
8505 * Returns the last Element
\r
8506 * @return {Ext.Element}
\r
8508 last : function(){
\r
8509 return this.item(this.getCount()-1);
\r
8513 * Returns true if this composite contains the passed element
\r
8514 * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
\r
8517 contains : function(el){
\r
8518 return this.indexOf(el) != -1;
\r
8522 * Removes the specified element(s).
\r
8523 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
\r
8524 * or an array of any of those.
\r
8525 * @param {Boolean} removeDom (optional) True to also remove the element from the document
\r
8526 * @return {CompositeElement} this
\r
8528 removeElement : function(keys, removeDom){
\r
8530 els = this.elements,
\r
8532 Ext.each(keys, function(val){
\r
8533 if ((el = (els[val] || els[val = me.indexOf(val)]))) {
\r
8538 Ext.removeNode(el);
\r
8541 els.splice(val, 1);
\r
8548 * @class Ext.CompositeElement
\r
8549 * @extends Ext.CompositeElementLite
\r
8550 * Standard composite class. Creates a Ext.Element for every element in the collection.
\r
8552 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Ext.Element. All Ext.Element
\r
8553 * actions will be performed on all the elements in this collection.</b>
\r
8555 * All methods return <i>this</i> and can be chained.
\r
8557 var els = Ext.select("#some-el div.some-class", true);
\r
8558 // or select directly from an existing element
\r
8559 var el = Ext.get('some-el');
\r
8560 el.select('div.some-class', true);
\r
8562 els.setWidth(100); // all elements become 100 width
\r
8563 els.hide(true); // all elements fade out and hide
\r
8565 els.setWidth(100).hide(true);
\r
8568 Ext.CompositeElement = function(els, root){
\r
8569 this.elements = [];
\r
8570 this.add(els, root);
\r
8573 Ext.extend(Ext.CompositeElement, Ext.CompositeElementLite, {
\r
8574 invoke : function(fn, args){
\r
8575 Ext.each(this.elements, function(e) {
\r
8576 Ext.Element.prototype[fn].apply(e, args);
\r
8582 * Adds elements to this composite.
\r
8583 * @param {String/Array} els A string CSS selector, an array of elements or an element
\r
8584 * @return {CompositeElement} this
\r
8586 add : function(els, root){
\r
8590 if(typeof els == "string"){
\r
8591 els = Ext.Element.selectorFunction(els, root);
\r
8593 var yels = this.elements;
\r
8594 Ext.each(els, function(e) {
\r
8595 yels.push(Ext.get(e));
\r
8601 * Returns the Element object at the specified index
\r
8602 * @param {Number} index
\r
8603 * @return {Ext.Element}
\r
8605 item : function(index){
\r
8606 return this.elements[index] || null;
\r
8610 indexOf : function(el){
\r
8611 return this.elements.indexOf(Ext.get(el));
\r
8614 filter : function(selector){
\r
8618 Ext.each(me.elements, function(el) {
\r
8619 if(el.is(selector)){
\r
8620 out.push(Ext.get(el));
\r
8623 me.elements = out;
\r
8628 * Iterates each <code>element</code> in this <code>composite</code>
\r
8629 * calling the supplied function using {@link Ext#each}.
\r
8630 * @param {Function} fn The function to be called with each
\r
8631 * <code>element</code>. If the supplied function returns <tt>false</tt>,
\r
8632 * iteration stops. This function is called with the following arguments:
\r
8633 * <div class="mdetail-params"><ul>
\r
8634 * <li><code>element</code> : <i>Object</i>
\r
8635 * <div class="sub-desc">The element at the current <code>index</code>
\r
8636 * in the <code>composite</code></div></li>
\r
8637 * <li><code>composite</code> : <i>Object</i>
\r
8638 * <div class="sub-desc">This composite.</div></li>
\r
8639 * <li><code>index</code> : <i>Number</i>
\r
8640 * <div class="sub-desc">The current index within the <code>composite</code>
\r
8643 * @param {Object} scope (optional) The scope to call the specified function.
\r
8644 * Defaults to the <code>element</code> at the current <code>index</code>
\r
8645 * within the composite.
\r
8646 * @return {CompositeElement} this
\r
8648 each : function(fn, scope){
\r
8649 Ext.each(this.elements, function(e, i){
\r
8650 return fn.call(scope || e, e, this, i);
\r
8657 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
\r
8658 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
\r
8659 * {@link Ext.CompositeElementLite CompositeElementLite} object.
\r
8660 * @param {String/Array} selector The CSS selector or an array of elements
\r
8661 * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
\r
8662 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
\r
8663 * @return {CompositeElementLite/CompositeElement}
\r
8664 * @member Ext.Element
\r
8667 Ext.Element.select = function(selector, unique, root){
\r
8669 if(typeof selector == "string"){
\r
8670 els = Ext.Element.selectorFunction(selector, root);
\r
8671 }else if(selector.length !== undefined){
\r
8674 throw "Invalid selector";
\r
8677 return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
\r
8681 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
\r
8682 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
\r
8683 * {@link Ext.CompositeElementLite CompositeElementLite} object.
\r
8684 * @param {String/Array} selector The CSS selector or an array of elements
\r
8685 * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
\r
8686 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
\r
8687 * @return {CompositeElementLite/CompositeElement}
\r
8688 * @member Ext.Element
\r
8691 Ext.select = Ext.Element.select;(function(){
\r
8692 var BEFOREREQUEST = "beforerequest",
\r
8693 REQUESTCOMPLETE = "requestcomplete",
\r
8694 REQUESTEXCEPTION = "requestexception",
\r
8695 UNDEFINED = undefined,
\r
8702 * @class Ext.data.Connection
\r
8703 * @extends Ext.util.Observable
\r
8704 * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made
\r
8705 * either to a configured URL, or to a URL specified at request time.</p>
\r
8706 * <p>Requests made by this class are asynchronous, and will return immediately. No data from
\r
8707 * the server will be available to the statement immediately following the {@link #request} call.
\r
8708 * To process returned data, use a
\r
8709 * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>
\r
8710 * in the request options object,
\r
8711 * or an {@link #requestcomplete event listener}.</p>
\r
8712 * <p><h3>File Uploads</h3><a href="#request-option-isUpload" ext:member="request-option-isUpload" ext:cls="Ext.data.Connection">File uploads</a> are not performed using normal "Ajax" techniques, that
\r
8713 * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
\r
8714 * manner with the DOM <tt><form></tt> element temporarily modified to have its
\r
8715 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
\r
8716 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
\r
8717 * but removed after the return data has been gathered.</p>
\r
8718 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
\r
8719 * server is using JSON to send the return object, then the
\r
8720 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
\r
8721 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
\r
8722 * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
\r
8723 * "<" as "&lt;", "&" as "&amp;" etc.</p>
\r
8724 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
\r
8725 * is created containing a <tt>responseText</tt> property in order to conform to the
\r
8726 * requirements of event handlers and callbacks.</p>
\r
8727 * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
\r
8728 * and some server technologies (notably JEE) may require some custom processing in order to
\r
8729 * retrieve parameter names and parameter values from the packet content.</p>
\r
8731 * @param {Object} config a configuration object.
\r
8733 Ext.data.Connection = function(config){
\r
8734 Ext.apply(this, config);
\r
8737 * @event beforerequest
\r
8738 * Fires before a network request is made to retrieve a data object.
\r
8739 * @param {Connection} conn This Connection object.
\r
8740 * @param {Object} options The options config object passed to the {@link #request} method.
\r
8744 * @event requestcomplete
\r
8745 * Fires if the request was successfully completed.
\r
8746 * @param {Connection} conn This Connection object.
\r
8747 * @param {Object} response The XHR object containing the response data.
\r
8748 * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
\r
8750 * @param {Object} options The options config object passed to the {@link #request} method.
\r
8754 * @event requestexception
\r
8755 * Fires if an error HTTP status was returned from the server.
\r
8756 * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
\r
8757 * for details of HTTP status codes.
\r
8758 * @param {Connection} conn This Connection object.
\r
8759 * @param {Object} response The XHR object containing the response data.
\r
8760 * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
\r
8762 * @param {Object} options The options config object passed to the {@link #request} method.
\r
8766 Ext.data.Connection.superclass.constructor.call(this);
\r
8769 Ext.extend(Ext.data.Connection, Ext.util.Observable, {
\r
8771 * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>
\r
8772 * <p>The <code>url</code> config may be a function which <i>returns</i> the URL to use for the Ajax request. The scope
\r
8773 * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>
\r
8776 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
\r
8777 * extra parameters to each request made by this object. (defaults to undefined)
\r
8780 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
\r
8781 * to each request made by this object. (defaults to undefined)
\r
8784 * @cfg {String} method (Optional) The default HTTP method to be used for requests.
\r
8785 * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;
\r
8786 * otherwise, GET will be used.)
\r
8789 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
\r
8793 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
\r
8799 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
\r
8802 disableCaching: true,
\r
8805 * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
\r
8806 * through a cache buster. Defaults to '_dc'
\r
8809 disableCachingParam: '_dc',
\r
8812 * <p>Sends an HTTP request to a remote server.</p>
\r
8813 * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
\r
8814 * return before the response has been received. Process any returned data
\r
8815 * in a callback function.</p>
\r
8817 Ext.Ajax.request({
\r
8818 url: 'ajax_demo/sample.json',
\r
8819 success: function(response, opts) {
\r
8820 var obj = Ext.decode(response.responseText);
\r
8823 failure: function(response, opts) {
\r
8824 console.log('server-side failure with status code ' + response.status);
\r
8828 * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
\r
8829 * @param {Object} options An object which may contain the following properties:<ul>
\r
8830 * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
\r
8831 * which to send the request, or a function to call which returns a URL string. The scope of the
\r
8832 * function is specified by the <tt>scope</tt> option. Defaults to the configured
\r
8833 * <tt>{@link #url}</tt>.</div></li>
\r
8834 * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
\r
8835 * An object containing properties which are used as parameters to the
\r
8836 * request, a url encoded string or a function to call to get either. The scope of the function
\r
8837 * is specified by the <tt>scope</tt> option.</div></li>
\r
8838 * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
\r
8839 * for the request. Defaults to the configured method, or if no method was configured,
\r
8840 * "GET" if no parameters are being sent, and "POST" if parameters are being sent. Note that
\r
8841 * the method name is case-sensitive and should be all caps.</div></li>
\r
8842 * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
\r
8843 * function to be called upon receipt of the HTTP response. The callback is
\r
8844 * called regardless of success or failure and is passed the following
\r
8846 * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
\r
8847 * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
\r
8848 * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.
\r
8849 * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about
\r
8850 * accessing elements of the response.</div></li>
\r
8851 * </ul></div></li>
\r
8852 * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
\r
8853 * to be called upon success of the request. The callback is passed the following
\r
8855 * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
\r
8856 * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
\r
8857 * </ul></div></li>
\r
8858 * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
\r
8859 * to be called upon failure of the request. The callback is passed the
\r
8860 * following parameters:<ul>
\r
8861 * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
\r
8862 * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
\r
8863 * </ul></div></li>
\r
8864 * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
\r
8865 * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
\r
8866 * specified as functions from which to draw values, then this also serves as the scope for those function calls.
\r
8867 * Defaults to the browser window.</div></li>
\r
8868 * <li><b>timeout</b> : Number (Optional)<div class="sub-desc">The timeout in milliseconds to be used for this request. Defaults to 30 seconds.</div></li>
\r
8869 * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt><form></tt>
\r
8870 * Element or the id of the <tt><form></tt> to pull parameters from.</div></li>
\r
8871 * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used
\r
8872 * with the <tt>form</tt> option</b>.
\r
8873 * <p>True if the form object is a file upload (will be set automatically if the form was
\r
8874 * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
\r
8875 * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
\r
8876 * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
\r
8877 * DOM <tt><form></tt> element temporarily modified to have its
\r
8878 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
\r
8879 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
\r
8880 * but removed after the return data has been gathered.</p>
\r
8881 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
\r
8882 * server is using JSON to send the return object, then the
\r
8883 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
\r
8884 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
\r
8885 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
\r
8886 * is created containing a <tt>responseText</tt> property in order to conform to the
\r
8887 * requirements of event handlers and callbacks.</p>
\r
8888 * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
\r
8889 * and some server technologies (notably JEE) may require some custom processing in order to
\r
8890 * retrieve parameter names and parameter values from the packet content.</p>
\r
8892 * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
\r
8893 * headers to set for the request.</div></li>
\r
8894 * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
\r
8895 * to use for the post. Note: This will be used instead of params for the post
\r
8896 * data. Any params will be appended to the URL.</div></li>
\r
8897 * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
\r
8898 * data to use as the post. Note: This will be used instead of params for the post
\r
8899 * data. Any params will be appended to the URL.</div></li>
\r
8900 * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
\r
8901 * to add a unique cache-buster param to GET requests.</div></li>
\r
8903 * <p>The options object may also contain any other property which might be needed to perform
\r
8904 * postprocessing in a callback because it is passed to callback functions.</p>
\r
8905 * @return {Number} transactionId The id of the server transaction. This may be used
\r
8906 * to cancel the request.
\r
8908 request : function(o){
\r
8910 if(me.fireEvent(BEFOREREQUEST, me, o)){
\r
8912 if(!Ext.isEmpty(o.indicatorText)){
\r
8913 me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";
\r
8915 if(me.indicatorText) {
\r
8916 Ext.getDom(o.el).innerHTML = me.indicatorText;
\r
8918 o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {
\r
8919 Ext.getDom(o.el).innerHTML = response.responseText;
\r
8924 url = o.url || me.url,
\r
8926 cb = {success: me.handleResponse,
\r
8927 failure: me.handleFailure,
\r
8929 argument: {options: o},
\r
8930 timeout : o.timeout || me.timeout
\r
8936 if (Ext.isFunction(p)) {
\r
8937 p = p.call(o.scope||WINDOW, o);
\r
8940 p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);
\r
8942 if (Ext.isFunction(url)) {
\r
8943 url = url.call(o.scope || WINDOW, o);
\r
8946 if((form = Ext.getDom(o.form))){
\r
8947 url = url || form.action;
\r
8948 if(o.isUpload || /multipart\/form-data/i.test(form.getAttribute("enctype"))) {
\r
8949 return me.doFormUpload.call(me, o, p, url);
\r
8951 serForm = Ext.lib.Ajax.serializeForm(form);
\r
8952 p = p ? (p + '&' + serForm) : serForm;
\r
8955 method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);
\r
8957 if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
\r
8958 var dcp = o.disableCachingParam || me.disableCachingParam;
\r
8959 url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));
\r
8962 o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});
\r
8964 if(o.autoAbort === true || me.autoAbort) {
\r
8968 if((method == GET || o.xmlData || o.jsonData) && p){
\r
8969 url = Ext.urlAppend(url, p);
\r
8972 return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
\r
8974 return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;
\r
8979 * Determine whether this object has a request outstanding.
\r
8980 * @param {Number} transactionId (Optional) defaults to the last transaction
\r
8981 * @return {Boolean} True if there is an outstanding request.
\r
8983 isLoading : function(transId){
\r
8984 return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;
\r
8988 * Aborts any outstanding request.
\r
8989 * @param {Number} transactionId (Optional) defaults to the last transaction
\r
8991 abort : function(transId){
\r
8992 if(transId || this.isLoading()){
\r
8993 Ext.lib.Ajax.abort(transId || this.transId);
\r
8998 handleResponse : function(response){
\r
8999 this.transId = false;
\r
9000 var options = response.argument.options;
\r
9001 response.argument = options ? options.argument : null;
\r
9002 this.fireEvent(REQUESTCOMPLETE, this, response, options);
\r
9003 if(options.success){
\r
9004 options.success.call(options.scope, response, options);
\r
9006 if(options.callback){
\r
9007 options.callback.call(options.scope, options, true, response);
\r
9012 handleFailure : function(response, e){
\r
9013 this.transId = false;
\r
9014 var options = response.argument.options;
\r
9015 response.argument = options ? options.argument : null;
\r
9016 this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
\r
9017 if(options.failure){
\r
9018 options.failure.call(options.scope, response, options);
\r
9020 if(options.callback){
\r
9021 options.callback.call(options.scope, options, false, response);
\r
9026 doFormUpload : function(o, ps, url){
\r
9027 var id = Ext.id(),
\r
9029 frame = doc.createElement('iframe'),
\r
9030 form = Ext.getDom(o.form),
\r
9033 encoding = 'multipart/form-data',
\r
9035 target: form.target,
\r
9036 method: form.method,
\r
9037 encoding: form.encoding,
\r
9038 enctype: form.enctype,
\r
9039 action: form.action
\r
9042 Ext.fly(frame).set({
\r
9046 src: Ext.SSL_SECURE_URL // for IE
\r
9048 doc.body.appendChild(frame);
\r
9050 // This is required so that IE doesn't pop the response up in a new window.
\r
9052 document.frames[id].name = id;
\r
9055 Ext.fly(form).set({
\r
9058 enctype: encoding,
\r
9059 encoding: encoding,
\r
9060 action: url || buf.action
\r
9063 // add dynamic params
\r
9064 Ext.iterate(Ext.urlDecode(ps, false), function(k, v){
\r
9065 hd = doc.createElement('input');
\r
9071 form.appendChild(hd);
\r
9077 // bogus response object
\r
9078 r = {responseText : '',
\r
9079 responseXML : null,
\r
9080 argument : o.argument},
\r
9085 doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
\r
9088 if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea
\r
9089 r.responseText = firstChild.value;
\r
9091 r.responseText = doc.body.innerHTML;
\r
9094 //in IE the document may still have a body even if returns XML.
\r
9095 r.responseXML = doc.XMLDocument || doc;
\r
9100 Ext.EventManager.removeListener(frame, LOAD, cb, me);
\r
9102 me.fireEvent(REQUESTCOMPLETE, me, r, o);
\r
9104 function runCallback(fn, scope, args){
\r
9105 if(Ext.isFunction(fn)){
\r
9106 fn.apply(scope, args);
\r
9110 runCallback(o.success, o.scope, [r, o]);
\r
9111 runCallback(o.callback, o.scope, [o, true, r]);
\r
9113 if(!me.debugUploads){
\r
9114 setTimeout(function(){Ext.removeNode(frame);}, 100);
\r
9118 Ext.EventManager.on(frame, LOAD, cb, this);
\r
9121 Ext.fly(form).set(buf);
\r
9122 Ext.each(hiddens, function(h) {
\r
9123 Ext.removeNode(h);
\r
9131 * @extends Ext.data.Connection
\r
9132 * <p>The global Ajax request class that provides a simple way to make Ajax requests
\r
9133 * with maximum flexibility.</p>
\r
9134 * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once
\r
9135 * and override them at the request function level only if necessary.</p>
\r
9136 * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>
\r
9137 * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>
\r
9138 * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>
\r
9139 * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>
\r
9142 // Default headers to pass in every request
\r
9143 Ext.Ajax.defaultHeaders = {
\r
9144 'Powered-By': 'Ext'
\r
9148 * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>
\r
9149 * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>
\r
9150 * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>
\r
9151 * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>
\r
9154 // Example: show a spinner during all Ajax requests
\r
9155 Ext.Ajax.on('beforerequest', this.showSpinner, this);
\r
9156 Ext.Ajax.on('requestcomplete', this.hideSpinner, this);
\r
9157 Ext.Ajax.on('requestexception', this.hideSpinner, this);
\r
9160 * <p>An example request:</p>
\r
9163 Ext.Ajax.{@link Ext.data.Connection#request request}({
\r
9168 'my-header': 'foo'
\r
9170 params: { foo: 'bar' }
\r
9173 // Simple ajax form submission
\r
9174 Ext.Ajax.{@link Ext.data.Connection#request request}({
\r
9175 form: 'some-form',
\r
9182 Ext.Ajax = new Ext.data.Connection({
\r
9184 * @cfg {String} url @hide
\r
9187 * @cfg {Object} extraParams @hide
\r
9190 * @cfg {Object} defaultHeaders @hide
\r
9193 * @cfg {String} method (Optional) @hide
\r
9196 * @cfg {Number} timeout (Optional) @hide
\r
9199 * @cfg {Boolean} autoAbort (Optional) @hide
\r
9203 * @cfg {Boolean} disableCaching (Optional) @hide
\r
9207 * @property disableCaching
\r
9208 * True to add a unique cache-buster param to GET requests. (defaults to true)
\r
9213 * The default URL to be used for requests to the server. (defaults to undefined)
\r
9214 * If the server receives all requests through one URL, setting this once is easier than
\r
9215 * entering it on every request.
\r
9219 * @property extraParams
\r
9220 * An object containing properties which are used as extra parameters to each request made
\r
9221 * by this object (defaults to undefined). Session information and other data that you need
\r
9222 * to pass with each request are commonly put here.
\r
9226 * @property defaultHeaders
\r
9227 * An object containing request headers which are added to each request made by this object
\r
9228 * (defaults to undefined).
\r
9232 * @property method
\r
9233 * The default HTTP method to be used for requests. Note that this is case-sensitive and
\r
9234 * should be all caps (defaults to undefined; if not set but params are present will use
\r
9235 * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
\r
9239 * @property timeout
\r
9240 * The timeout in milliseconds to be used for requests. (defaults to 30000)
\r
9245 * @property autoAbort
\r
9246 * Whether a new request should abort any pending requests. (defaults to false)
\r
9249 autoAbort : false,
\r
9252 * Serialize the passed form into a url encoded string
\r
9253 * @param {String/HTMLElement} form
\r
9254 * @return {String}
\r
9256 serializeForm : function(form){
\r
9257 return Ext.lib.Ajax.serializeForm(form);
\r
9261 * @class Ext.Updater
9262 * @extends Ext.util.Observable
9263 * Provides AJAX-style update capabilities for Element objects. Updater can be used to {@link #update}
9264 * an {@link Ext.Element} once, or you can use {@link #startAutoRefresh} to set up an auto-updating
9265 * {@link Ext.Element Element} on a specific interval.<br><br>
9268 * var el = Ext.get("foo"); // Get Ext.Element object
9269 * var mgr = el.getUpdater();
9271 url: "http://myserver.com/index.php",
9278 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
9280 * // or directly (returns the same Updater instance)
9281 * var mgr = new Ext.Updater("myElementId");
9282 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
9283 * mgr.on("update", myFcnNeedsToKnow);
9285 * // short handed call directly from the element object
9286 * Ext.get("foo").load({
9289 params: "param1=foo&param2=bar",
9290 text: "Loading Foo..."
9294 * Create new Updater directly.
9295 * @param {Mixed} el The element to update
9296 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already
9297 * has an Updater and if it does it returns the same instance. This will skip that check (useful for extending this class).
9299 Ext.UpdateManager = Ext.Updater = Ext.extend(Ext.util.Observable,
9301 var BEFOREUPDATE = "beforeupdate",
9303 FAILURE = "failure";
9306 function processSuccess(response){
9308 me.transaction = null;
9309 if (response.argument.form && response.argument.reset) {
9310 try { // put in try/catch since some older FF releases had problems with this
9311 response.argument.form.reset();
9314 if (me.loadScripts) {
9315 me.renderer.render(me.el, response, me,
9316 updateComplete.createDelegate(me, [response]));
9318 me.renderer.render(me.el, response, me);
9319 updateComplete.call(me, response);
9324 function updateComplete(response, type, success){
9325 this.fireEvent(type || UPDATE, this.el, response);
9326 if(Ext.isFunction(response.argument.callback)){
9327 response.argument.callback.call(response.argument.scope, this.el, Ext.isEmpty(success) ? true : false, response, response.argument.options);
9332 function processFailure(response){
9333 updateComplete.call(this, response, FAILURE, !!(this.transaction = null));
9337 constructor: function(el, forceNew){
9340 if(!forceNew && el.updateManager){
9341 return el.updateManager;
9344 * The Element object
9349 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
9352 me.defaultUrl = null;
9356 * @event beforeupdate
9357 * Fired before an update is made, return false from your handler and the update is cancelled.
9358 * @param {Ext.Element} el
9359 * @param {String/Object/Function} url
9360 * @param {String/Object} params
9365 * Fired after successful update is made.
9366 * @param {Ext.Element} el
9367 * @param {Object} oResponseObject The response Object
9372 * Fired on update failure.
9373 * @param {Ext.Element} el
9374 * @param {Object} oResponseObject The response Object
9379 Ext.apply(me, Ext.Updater.defaults);
9381 * Blank page URL to use with SSL file uploads (defaults to {@link Ext.Updater.defaults#sslBlankUrl}).
9382 * @property sslBlankUrl
9386 * Whether to append unique parameter on get request to disable caching (defaults to {@link Ext.Updater.defaults#disableCaching}).
9387 * @property disableCaching
9391 * Text for loading indicator (defaults to {@link Ext.Updater.defaults#indicatorText}).
9392 * @property indicatorText
9396 * Whether to show indicatorText when loading (defaults to {@link Ext.Updater.defaults#showLoadIndicator}).
9397 * @property showLoadIndicator
9401 * Timeout for requests or form posts in seconds (defaults to {@link Ext.Updater.defaults#timeout}).
9406 * True to process scripts in the output (defaults to {@link Ext.Updater.defaults#loadScripts}).
9407 * @property loadScripts
9412 * Transaction object of the current executing transaction, or null if there is no active transaction.
9414 me.transaction = null;
9416 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
9419 me.refreshDelegate = me.refresh.createDelegate(me);
9421 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
9424 me.updateDelegate = me.update.createDelegate(me);
9426 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
9429 me.formUpdateDelegate = (me.formUpdate || function(){}).createDelegate(me);
9432 * The renderer for this Updater (defaults to {@link Ext.Updater.BasicRenderer}).
9434 me.renderer = me.renderer || me.getDefaultRenderer();
9436 Ext.Updater.superclass.constructor.call(me);
9440 * Sets the content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.
9441 * @param {Object} renderer The object implementing the render() method
9443 setRenderer : function(renderer){
9444 this.renderer = renderer;
9448 * Returns the current content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.
9451 getRenderer : function(){
9452 return this.renderer;
9456 * This is an overrideable method which returns a reference to a default
9457 * renderer class if none is specified when creating the Ext.Updater.
9458 * Defaults to {@link Ext.Updater.BasicRenderer}
9460 getDefaultRenderer: function() {
9461 return new Ext.Updater.BasicRenderer();
9465 * Sets the default URL used for updates.
9466 * @param {String/Function} defaultUrl The url or a function to call to get the url
9468 setDefaultUrl : function(defaultUrl){
9469 this.defaultUrl = defaultUrl;
9473 * Get the Element this Updater is bound to
9474 * @return {Ext.Element} The element
9481 * Performs an <b>asynchronous</b> request, updating this element with the response.
9482 * If params are specified it uses POST, otherwise it uses GET.<br><br>
9483 * <b>Note:</b> Due to the asynchronous nature of remote server requests, the Element
9484 * will not have been fully updated when the function returns. To post-process the returned
9485 * data, use the callback option, or an <b><tt>update</tt></b> event handler.
9486 * @param {Object} options A config object containing any of the following options:<ul>
9487 * <li>url : <b>String/Function</b><p class="sub-desc">The URL to request or a function which
9488 * <i>returns</i> the URL (defaults to the value of {@link Ext.Ajax#url} if not specified).</p></li>
9489 * <li>method : <b>String</b><p class="sub-desc">The HTTP method to
9490 * use. Defaults to POST if the <tt>params</tt> argument is present, otherwise GET.</p></li>
9491 * <li>params : <b>String/Object/Function</b><p class="sub-desc">The
9492 * parameters to pass to the server (defaults to none). These may be specified as a url-encoded
9493 * string, or as an object containing properties which represent parameters,
9494 * or as a function, which returns such an object.</p></li>
9495 * <li>scripts : <b>Boolean</b><p class="sub-desc">If <tt>true</tt>
9496 * any <script> tags embedded in the response text will be extracted
9497 * and executed (defaults to {@link Ext.Updater.defaults#loadScripts}). If this option is specified,
9498 * the callback will be called <i>after</i> the execution of the scripts.</p></li>
9499 * <li>callback : <b>Function</b><p class="sub-desc">A function to
9500 * be called when the response from the server arrives. The following
9501 * parameters are passed:<ul>
9502 * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>
9503 * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>
9504 * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li>
9505 * <li><b>options</b> : Object<p class="sub-desc">The config object passed to the update call.</p></li></ul>
9507 * <li>scope : <b>Object</b><p class="sub-desc">The scope in which
9508 * to execute the callback (The callback's <tt>this</tt> reference.) If the
9509 * <tt>params</tt> argument is a function, this scope is used for that function also.</p></li>
9510 * <li>discardUrl : <b>Boolean</b><p class="sub-desc">By default, the URL of this request becomes
9511 * the default URL for this Updater object, and will be subsequently used in {@link #refresh}
9512 * calls. To bypass this behavior, pass <tt>discardUrl:true</tt> (defaults to false).</p></li>
9513 * <li>timeout : <b>Number</b><p class="sub-desc">The number of seconds to wait for a response before
9514 * timing out (defaults to {@link Ext.Updater.defaults#timeout}).</p></li>
9515 * <li>text : <b>String</b><p class="sub-desc">The text to use as the innerHTML of the
9516 * {@link Ext.Updater.defaults#indicatorText} div (defaults to 'Loading...'). To replace the entire div, not
9517 * just the text, override {@link Ext.Updater.defaults#indicatorText} directly.</p></li>
9518 * <li>nocache : <b>Boolean</b><p class="sub-desc">Only needed for GET
9519 * requests, this option causes an extra, auto-generated parameter to be appended to the request
9520 * to defeat caching (defaults to {@link Ext.Updater.defaults#disableCaching}).</p></li></ul>
9525 url: "your-url.php",
9526 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9527 callback: yourFunction,
9528 scope: yourObject, //(optional scope)
9533 scripts: false // Save time by avoiding RegExp execution.
9537 update : function(url, params, callback, discardUrl){
9542 if(me.fireEvent(BEFOREUPDATE, me.el, url, params) !== false){
9543 if(Ext.isObject(url)){ // must be config object
9546 params = params || cfg.params;
9547 callback = callback || cfg.callback;
9548 discardUrl = discardUrl || cfg.discardUrl;
9549 callerScope = cfg.scope;
9550 if(!Ext.isEmpty(cfg.nocache)){me.disableCaching = cfg.nocache;};
9551 if(!Ext.isEmpty(cfg.text)){me.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
9552 if(!Ext.isEmpty(cfg.scripts)){me.loadScripts = cfg.scripts;};
9553 if(!Ext.isEmpty(cfg.timeout)){me.timeout = cfg.timeout;};
9558 me.defaultUrl = url;
9560 if(Ext.isFunction(url)){
9564 var o = Ext.apply({}, {
9566 params: (Ext.isFunction(params) && callerScope) ? params.createDelegate(callerScope) : params,
9567 success: processSuccess,
9568 failure: processFailure,
9570 callback: undefined,
9571 timeout: (me.timeout*1000),
9572 disableCaching: me.disableCaching,
9577 "callback": callback,
9578 "scope": callerScope || window,
9583 me.transaction = Ext.Ajax.request(o);
9588 * <p>Performs an async form post, updating this element with the response. If the form has the attribute
9589 * enctype="<a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form-data</a>", it assumes it's a file upload.
9590 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.</p>
9591 * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
9592 * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
9593 * DOM <tt><form></tt> element temporarily modified to have its
9594 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
9595 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
9596 * but removed after the return data has been gathered.</p>
9597 * <p>Be aware that file upload packets, sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form-data</a>
9598 * and some server technologies (notably JEE) may require some custom processing in order to
9599 * retrieve parameter names and parameter values from the packet content.</p>
9600 * @param {String/HTMLElement} form The form Id or form element
9601 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
9602 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
9603 * @param {Function} callback (optional) Callback when transaction is complete. The following
9604 * parameters are passed:<ul>
9605 * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>
9606 * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>
9607 * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li></ul>
9609 formUpdate : function(form, url, reset, callback){
9611 if(me.fireEvent(BEFOREUPDATE, me.el, form, url) !== false){
9612 if(Ext.isFunction(url)){
9615 form = Ext.getDom(form)
9616 me.transaction = Ext.Ajax.request({
9619 success: processSuccess,
9620 failure: processFailure,
9622 timeout: (me.timeout*1000),
9626 "callback": callback,
9630 me.showLoading.defer(1, me);
9635 * Set this element to auto refresh. Can be canceled by calling {@link #stopAutoRefresh}.
9636 * @param {Number} interval How often to update (in seconds).
9637 * @param {String/Object/Function} url (optional) The url for this request, a config object in the same format
9638 * supported by {@link #load}, or a function to call to get the url (defaults to the last used url). Note that while
9639 * the url used in a load call can be reused by this method, other load config options will not be reused and must be
9640 * sepcified as part of a config object passed as this paramter if needed.
9641 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string
9642 * "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
9643 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9644 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
9646 startAutoRefresh : function(interval, url, params, callback, refreshNow){
9649 me.update(url || me.defaultUrl, params, callback, true);
9651 if(me.autoRefreshProcId){
9652 clearInterval(me.autoRefreshProcId);
9654 me.autoRefreshProcId = setInterval(me.update.createDelegate(me, [url || me.defaultUrl, params, callback, true]), interval * 1000);
9658 * Stop auto refresh on this element.
9660 stopAutoRefresh : function(){
9661 if(this.autoRefreshProcId){
9662 clearInterval(this.autoRefreshProcId);
9663 delete this.autoRefreshProcId;
9668 * Returns true if the Updater is currently set to auto refresh its content (see {@link #startAutoRefresh}), otherwise false.
9670 isAutoRefreshing : function(){
9671 return !!this.autoRefreshProcId;
9675 * Display the element's "loading" state. By default, the element is updated with {@link #indicatorText}. This
9676 * method may be overridden to perform a custom action while this Updater is actively updating its contents.
9678 showLoading : function(){
9679 if(this.showLoadIndicator){
9680 this.el.dom.innerHTML = this.indicatorText;
9685 * Aborts the currently executing transaction, if any.
9688 if(this.transaction){
9689 Ext.Ajax.abort(this.transaction);
9694 * Returns true if an update is in progress, otherwise false.
9697 isUpdating : function(){
9698 return this.transaction ? Ext.Ajax.isLoading(this.transaction) : false;
9702 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
9703 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9705 refresh : function(callback){
9706 if(this.defaultUrl){
9707 this.update(this.defaultUrl, null, callback, true);
9714 * @class Ext.Updater.defaults
9715 * The defaults collection enables customizing the default properties of Updater
9717 Ext.Updater.defaults = {
9719 * Timeout for requests or form posts in seconds (defaults to 30 seconds).
9724 * True to append a unique parameter to GET requests to disable caching (defaults to false).
9727 disableCaching : false,
9729 * Whether or not to show {@link #indicatorText} during loading (defaults to true).
9732 showLoadIndicator : true,
9734 * Text for loading indicator (defaults to '<div class="loading-indicator">Loading...</div>').
9737 indicatorText : '<div class="loading-indicator">Loading...</div>',
9739 * True to process scripts by default (defaults to false).
9742 loadScripts : false,
9744 * Blank page URL to use with SSL file uploads (defaults to {@link Ext#SSL_SECURE_URL} if set, or "javascript:false").
9747 sslBlankUrl : Ext.SSL_SECURE_URL
9752 * Static convenience method. <b>This method is deprecated in favor of el.load({url:'foo.php', ...})</b>.
9754 * <pre><code>Ext.Updater.updateElement("my-div", "stuff.php");</code></pre>
9755 * @param {Mixed} el The element to update
9756 * @param {String} url The url
9757 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
9758 * @param {Object} options (optional) A config object with any of the Updater properties you want to set - for
9759 * example: {disableCaching:true, indicatorText: "Loading data..."}
9762 * @member Ext.Updater
9764 Ext.Updater.updateElement = function(el, url, params, options){
9765 var um = Ext.get(el).getUpdater();
9766 Ext.apply(um, options);
9767 um.update(url, params, options ? options.callback : null);
9771 * @class Ext.Updater.BasicRenderer
9772 * Default Content renderer. Updates the elements innerHTML with the responseText.
9774 Ext.Updater.BasicRenderer = function(){};
9776 Ext.Updater.BasicRenderer.prototype = {
9778 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
9779 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
9780 * create an object with a "render(el, response)" method and pass it to setRenderer on the Updater.
9781 * @param {Ext.Element} el The element being rendered
9782 * @param {Object} response The XMLHttpRequest object
9783 * @param {Updater} updateManager The calling update manager
9784 * @param {Function} callback A callback that will need to be called if loadScripts is true on the Updater
9786 render : function(el, response, updateManager, callback){
9787 el.update(response.responseText, updateManager.loadScripts, callback);
9792 * The date parsing and formatting syntax contains a subset of
9793 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
9794 * supported will provide results equivalent to their PHP versions.
9796 * The following is a list of all currently supported formats:
9798 Format Description Example returned values
9799 ------ ----------------------------------------------------------------------- -----------------------
9800 d Day of the month, 2 digits with leading zeros 01 to 31
9801 D A short textual representation of the day of the week Mon to Sun
9802 j Day of the month without leading zeros 1 to 31
9803 l A full textual representation of the day of the week Sunday to Saturday
9804 N ISO-8601 numeric representation of the day of the week 1 (for Monday) through 7 (for Sunday)
9805 S English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
9806 w Numeric representation of the day of the week 0 (for Sunday) to 6 (for Saturday)
9807 z The day of the year (starting from 0) 0 to 364 (365 in leap years)
9808 W ISO-8601 week number of year, weeks starting on Monday 01 to 53
9809 F A full textual representation of a month, such as January or March January to December
9810 m Numeric representation of a month, with leading zeros 01 to 12
9811 M A short textual representation of a month Jan to Dec
9812 n Numeric representation of a month, without leading zeros 1 to 12
9813 t Number of days in the given month 28 to 31
9814 L Whether it's a leap year 1 if it is a leap year, 0 otherwise.
9815 o ISO-8601 year number (identical to (Y), but if the ISO week number (W) Examples: 1998 or 2004
9816 belongs to the previous or next year, that year is used instead)
9817 Y A full numeric representation of a year, 4 digits Examples: 1999 or 2003
9818 y A two digit representation of a year Examples: 99 or 03
9819 a Lowercase Ante meridiem and Post meridiem am or pm
9820 A Uppercase Ante meridiem and Post meridiem AM or PM
9821 g 12-hour format of an hour without leading zeros 1 to 12
9822 G 24-hour format of an hour without leading zeros 0 to 23
9823 h 12-hour format of an hour with leading zeros 01 to 12
9824 H 24-hour format of an hour with leading zeros 00 to 23
9825 i Minutes, with leading zeros 00 to 59
9826 s Seconds, with leading zeros 00 to 59
9827 u Decimal fraction of a second Examples:
9828 (minimum 1 digit, arbitrary number of digits allowed) 001 (i.e. 0.001s) or
9829 100 (i.e. 0.100s) or
9830 999 (i.e. 0.999s) or
9831 999876543210 (i.e. 0.999876543210s)
9832 O Difference to Greenwich time (GMT) in hours and minutes Example: +1030
9833 P Difference to Greenwich time (GMT) with colon between hours and minutes Example: -08:00
9834 T Timezone abbreviation of the machine running the code Examples: EST, MDT, PDT ...
9835 Z Timezone offset in seconds (negative if west of UTC, positive if east) -43200 to 50400
9838 1) If unspecified, the month / day defaults to the current month / day, 1991 or
9839 the time defaults to midnight, while the timezone defaults to the 1992-10 or
9840 browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
9841 and minutes. The "T" delimiter, seconds, milliseconds and timezone 1994-08-19T16:20+01:00 or
9842 are optional. 1995-07-18T17:21:28-02:00 or
9843 2) The decimal fraction of a second, if specified, must contain at 1996-06-17T18:22:29.98765+03:00 or
9844 least 1 digit (there is no limit to the maximum number 1997-05-16T19:23:30,12345-0400 or
9845 of digits allowed), and may be delimited by either a '.' or a ',' 1998-04-15T20:24:31.2468Z or
9846 Refer to the examples on the right for the various levels of 1999-03-14T20:24:32Z or
9847 date-time granularity which are supported, or see 2000-02-13T21:25:33
9848 http://www.w3.org/TR/NOTE-datetime for more info. 2001-01-12 22:26:34
9849 U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) 1193432466 or -2138434463
9850 M$ Microsoft AJAX serialized dates \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
9851 \/Date(1238606590509+0800)\/
9854 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
9857 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
9859 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
9860 document.write(dt.format('Y-m-d')); // 2007-01-10
9861 document.write(dt.format('F j, Y, g:i a')); // January 10, 2007, 3:05 pm
9862 document.write(dt.format('l, \\t\\he jS \\of F Y h:i:s A')); // Wednesday, the 10th of January 2007 03:05:01 PM
9865 * Here are some standard date/time patterns that you might find helpful. They
9866 * are not part of the source of Date.js, but to use them you can simply copy this
9867 * block of code into any script that is included after Date.js and they will also become
9868 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
9871 ISO8601Long:"Y-m-d H:i:s",
9872 ISO8601Short:"Y-m-d",
9874 LongDate: "l, F d, Y",
9875 FullDateTime: "l, F d, Y g:i:s A",
9878 LongTime: "g:i:s A",
9879 SortableDateTime: "Y-m-d\\TH:i:s",
9880 UniversalSortableDateTime: "Y-m-d H:i:sO",
9887 var dt = new Date();
9888 document.write(dt.format(Date.patterns.ShortDate));
9890 * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
9891 * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
9895 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
9896 * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
9897 * They generate precompiled functions from format patterns instead of parsing and
9898 * processing each pattern every time a date is formatted. These functions are available
9899 * on every Date object.
9905 * Global flag which determines if strict date parsing should be used.
9906 * Strict date parsing will not roll-over invalid dates, which is the
9907 * default behaviour of javascript Date objects.
9908 * (see {@link #parseDate} for more information)
9909 * Defaults to <tt>false</tt>.
9913 Date.useStrict = false;
9916 // create private copy of Ext's String.format() method
9917 // - to remove unnecessary dependency
9918 // - to resolve namespace conflict with M$-Ajax's implementation
9919 function xf(format) {
9920 var args = Array.prototype.slice.call(arguments, 1);
9921 return format.replace(/\{(\d+)\}/g, function(m, i) {
9928 Date.formatCodeToRegex = function(character, currentGroup) {
9929 // Note: currentGroup - position in regex result array (see notes for Date.parseCodes below)
9930 var p = Date.parseCodes[character];
9933 p = typeof p == 'function'? p() : p;
9934 Date.parseCodes[character] = p; // reassign function result to prevent repeated execution
9937 return p? Ext.applyIf({
9938 c: p.c? xf(p.c, currentGroup || "{0}") : p.c
9942 s:Ext.escapeRe(character) // treat unrecognised characters as literals
9946 // private shorthand for Date.formatCodeToRegex since we'll be using it fairly often
9947 var $f = Date.formatCodeToRegex;
9951 * <p>An object hash in which each property is a date parsing function. The property name is the
9952 * format string which that function parses.</p>
9953 * <p>This object is automatically populated with date parsing functions as
9954 * date formats are requested for Ext standard formatting strings.</p>
9955 * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
9956 * may be used as a format string to {@link #parseDate}.<p>
9957 * <p>Example:</p><pre><code>
9958 Date.parseFunctions['x-date-format'] = myDateParser;
9960 * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
9961 * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
9962 * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
9963 * (i.e. prevent javascript Date "rollover") (The default must be false).
9964 * Invalid date strings should return null when parsed.</div></li>
9966 * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
9967 * formatting function must be placed into the {@link #formatFunctions} property.
9968 * @property parseFunctions
9973 "M$": function(input, strict) {
9974 // note: the timezone offset is ignored since the M$ Ajax server sends
9975 // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
9976 var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
9977 var r = (input || '').match(re);
9978 return r? new Date(((r[1] || '') + r[2]) * 1) : null;
9984 * <p>An object hash in which each property is a date formatting function. The property name is the
9985 * format string which corresponds to the produced formatted date string.</p>
9986 * <p>This object is automatically populated with date formatting functions as
9987 * date formats are requested for Ext standard formatting strings.</p>
9988 * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
9989 * may be used as a format string to {@link #format}. Example:</p><pre><code>
9990 Date.formatFunctions['x-date-format'] = myDateFormatter;
9992 * <p>A formatting function should return a string repesentation of the passed Date object:<div class="mdetail-params"><ul>
9993 * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
9995 * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
9996 * parsing function must be placed into the {@link #parseFunctions} property.
9997 * @property formatFunctions
10003 // UTC milliseconds since Unix epoch (M$-AJAX serialized date format (MRSF))
10004 return '\\/Date(' + this.getTime() + ')\\/';
10011 * Date interval constant
10018 * Date interval constant
10025 * Date interval constant
10031 /** Date interval constant
10038 * Date interval constant
10045 * Date interval constant
10052 * Date interval constant
10059 * <p>An object hash containing default date values used during date parsing.</p>
10060 * <p>The following properties are available:<div class="mdetail-params"><ul>
10061 * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
10062 * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
10063 * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
10064 * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
10065 * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
10066 * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
10067 * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
10069 * <p>Override these properties to customize the default date values used by the {@link #parseDate} method.</p>
10070 * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
10071 * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
10072 * It is the responsiblity of the developer to account for this.</b></p>
10075 // set default day value to the first day of the month
10076 Date.defaults.d = 1;
10078 // parse a February date string containing only year and month values.
10079 // setting the default day value to 1 prevents weird date rollover issues
10080 // when attempting to parse the following date string on, for example, March 31st 2009.
10081 Date.parseDate('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
10083 * @property defaults
10090 * An array of textual day names.
10091 * Override these values for international dates.
10095 'SundayInYourLang',
10096 'MondayInYourLang',
10114 * An array of textual month names.
10115 * Override these values for international dates.
10118 Date.monthNames = [
10143 * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
10144 * Override these values for international dates.
10147 Date.monthNumbers = {
10148 'ShortJanNameInYourLang':0,
10149 'ShortFebNameInYourLang':1,
10172 * Get the short month name for the given month number.
10173 * Override this function for international dates.
10174 * @param {Number} month A zero-based javascript month number.
10175 * @return {String} The short month name.
10178 getShortMonthName : function(month) {
10179 return Date.monthNames[month].substring(0, 3);
10183 * Get the short day name for the given day number.
10184 * Override this function for international dates.
10185 * @param {Number} day A zero-based javascript day number.
10186 * @return {String} The short day name.
10189 getShortDayName : function(day) {
10190 return Date.dayNames[day].substring(0, 3);
10194 * Get the zero-based javascript month number for the given short/full month name.
10195 * Override this function for international dates.
10196 * @param {String} name The short/full month name.
10197 * @return {Number} The zero-based javascript month number.
10200 getMonthNumber : function(name) {
10201 // handle camel casing for english month names (since the keys for the Date.monthNumbers hash are case sensitive)
10202 return Date.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
10206 * The base format-code to formatting-function hashmap used by the {@link #format} method.
10207 * Formatting functions are strings (or functions which return strings) which
10208 * will return the appropriate value when evaluated in the context of the Date object
10209 * from which the {@link #format} method is called.
10210 * Add to / override these mappings for custom date formatting.
10211 * Note: Date.format() treats characters as literals if an appropriate mapping cannot be found.
10214 Date.formatCodes.x = "String.leftPad(this.getDate(), 2, '0')";
10215 (new Date()).format("X"); // returns the current day of the month
10221 d: "String.leftPad(this.getDate(), 2, '0')",
10222 D: "Date.getShortDayName(this.getDay())", // get localised short day name
10223 j: "this.getDate()",
10224 l: "Date.dayNames[this.getDay()]",
10225 N: "(this.getDay() ? this.getDay() : 7)",
10226 S: "this.getSuffix()",
10227 w: "this.getDay()",
10228 z: "this.getDayOfYear()",
10229 W: "String.leftPad(this.getWeekOfYear(), 2, '0')",
10230 F: "Date.monthNames[this.getMonth()]",
10231 m: "String.leftPad(this.getMonth() + 1, 2, '0')",
10232 M: "Date.getShortMonthName(this.getMonth())", // get localised short month name
10233 n: "(this.getMonth() + 1)",
10234 t: "this.getDaysInMonth()",
10235 L: "(this.isLeapYear() ? 1 : 0)",
10236 o: "(this.getFullYear() + (this.getWeekOfYear() == 1 && this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 && this.getMonth() < 11 ? -1 : 0)))",
10237 Y: "this.getFullYear()",
10238 y: "('' + this.getFullYear()).substring(2, 4)",
10239 a: "(this.getHours() < 12 ? 'am' : 'pm')",
10240 A: "(this.getHours() < 12 ? 'AM' : 'PM')",
10241 g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
10242 G: "this.getHours()",
10243 h: "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
10244 H: "String.leftPad(this.getHours(), 2, '0')",
10245 i: "String.leftPad(this.getMinutes(), 2, '0')",
10246 s: "String.leftPad(this.getSeconds(), 2, '0')",
10247 u: "String.leftPad(this.getMilliseconds(), 3, '0')",
10248 O: "this.getGMTOffset()",
10249 P: "this.getGMTOffset(true)",
10250 T: "this.getTimezone()",
10251 Z: "(this.getTimezoneOffset() * -60)",
10253 c: function() { // ISO-8601 -- GMT format
10254 for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
10255 var e = c.charAt(i);
10256 code.push(e == "T" ? "'T'" : Date.getFormatCode(e)); // treat T as a character literal
10258 return code.join(" + ");
10261 c: function() { // ISO-8601 -- UTC format
10263 "this.getUTCFullYear()", "'-'",
10264 "String.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
10265 "String.leftPad(this.getUTCDate(), 2, '0')",
10267 "String.leftPad(this.getUTCHours(), 2, '0')", "':'",
10268 "String.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
10269 "String.leftPad(this.getUTCSeconds(), 2, '0')",
10275 U: "Math.round(this.getTime() / 1000)"
10279 * Checks if the passed Date parameters will cause a javascript Date "rollover".
10280 * @param {Number} year 4-digit year
10281 * @param {Number} month 1-based month-of-year
10282 * @param {Number} day Day of month
10283 * @param {Number} hour (optional) Hour
10284 * @param {Number} minute (optional) Minute
10285 * @param {Number} second (optional) Second
10286 * @param {Number} millisecond (optional) Millisecond
10287 * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
10290 isValid : function(y, m, d, h, i, s, ms) {
10297 var dt = new Date(y, m - 1, d, h, i, s, ms);
10299 return y == dt.getFullYear() &&
10300 m == dt.getMonth() + 1 &&
10301 d == dt.getDate() &&
10302 h == dt.getHours() &&
10303 i == dt.getMinutes() &&
10304 s == dt.getSeconds() &&
10305 ms == dt.getMilliseconds();
10309 * Parses the passed string using the specified date format.
10310 * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
10311 * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
10312 * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
10313 * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
10314 * Keep in mind that the input date string must precisely match the specified format string
10315 * in order for the parse operation to be successful (failed parse operations return a null value).
10316 * <p>Example:</p><pre><code>
10317 //dt = Fri May 25 2007 (current date)
10318 var dt = new Date();
10320 //dt = Thu May 25 2006 (today's month/day in 2006)
10321 dt = Date.parseDate("2006", "Y");
10323 //dt = Sun Jan 15 2006 (all date parts specified)
10324 dt = Date.parseDate("2006-01-15", "Y-m-d");
10326 //dt = Sun Jan 15 2006 15:20:01
10327 dt = Date.parseDate("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
10329 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
10330 dt = Date.parseDate("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
10332 * @param {String} input The raw date string.
10333 * @param {String} format The expected date string format.
10334 * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
10335 (defaults to false). Invalid date strings will return null when parsed.
10336 * @return {Date} The parsed Date.
10339 parseDate : function(input, format, strict) {
10340 var p = Date.parseFunctions;
10341 if (p[format] == null) {
10342 Date.createParser(format);
10344 return p[format](input, Ext.isDefined(strict) ? strict : Date.useStrict);
10348 getFormatCode : function(character) {
10349 var f = Date.formatCodes[character];
10352 f = typeof f == 'function'? f() : f;
10353 Date.formatCodes[character] = f; // reassign function result to prevent repeated execution
10356 // note: unknown characters are treated as literals
10357 return f || ("'" + String.escape(character) + "'");
10361 createFormat : function(format) {
10366 for (var i = 0; i < format.length; ++i) {
10367 ch = format.charAt(i);
10368 if (!special && ch == "\\") {
10370 } else if (special) {
10372 code.push("'" + String.escape(ch) + "'");
10374 code.push(Date.getFormatCode(ch))
10377 Date.formatFunctions[format] = new Function("return " + code.join('+'));
10381 createParser : function() {
10383 "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
10384 "def = Date.defaults,",
10385 "results = String(input).match(Date.parseRegexes[{0}]);", // either null, or an array of matched strings
10390 "if(u != null){", // i.e. unix time is defined
10391 "v = new Date(u * 1000);", // give top priority to UNIX time
10393 // create Date object representing midnight of the current day;
10394 // this will provide us with our date defaults
10395 // (note: clearTime() handles Daylight Saving Time automatically)
10396 "dt = (new Date()).clearTime();",
10398 // date calculations (note: these calculations create a dependency on Ext.num())
10399 "y = y >= 0? y : Ext.num(def.y, dt.getFullYear());",
10400 "m = m >= 0? m : Ext.num(def.m - 1, dt.getMonth());",
10401 "d = d >= 0? d : Ext.num(def.d, dt.getDate());",
10403 // time calculations (note: these calculations create a dependency on Ext.num())
10404 "h = h || Ext.num(def.h, dt.getHours());",
10405 "i = i || Ext.num(def.i, dt.getMinutes());",
10406 "s = s || Ext.num(def.s, dt.getSeconds());",
10407 "ms = ms || Ext.num(def.ms, dt.getMilliseconds());",
10409 "if(z >= 0 && y >= 0){",
10410 // both the year and zero-based day of year are defined and >= 0.
10411 // these 2 values alone provide sufficient info to create a full date object
10413 // create Date object representing January 1st for the given year
10414 "v = new Date(y, 0, 1, h, i, s, ms);",
10416 // then add day of year, checking for Date "rollover" if necessary
10417 "v = !strict? v : (strict === true && (z <= 364 || (v.isLeapYear() && z <= 365))? v.add(Date.DAY, z) : null);",
10418 "}else if(strict === true && !Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
10419 "v = null;", // invalid date, so return null
10421 // plain old Date object
10422 "v = new Date(y, m, d, h, i, s, ms);",
10428 // favour UTC offset over GMT offset
10430 // reset to UTC, then add offset
10431 "v = v.add(Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
10433 // reset to GMT, then add offset
10434 "v = v.add(Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
10441 return function(format) {
10442 var regexNum = Date.parseRegexes.length,
10449 for (var i = 0; i < format.length; ++i) {
10450 ch = format.charAt(i);
10451 if (!special && ch == "\\") {
10453 } else if (special) {
10455 regex.push(String.escape(ch));
10457 var obj = $f(ch, currentGroup);
10458 currentGroup += obj.g;
10460 if (obj.g && obj.c) {
10466 Date.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", "i");
10467 Date.parseFunctions[format] = new Function("input", "strict", xf(code, regexNum, calc.join('')));
10475 * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
10476 * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
10477 * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
10481 c:"d = parseInt(results[{0}], 10);\n",
10482 s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
10486 c:"d = parseInt(results[{0}], 10);\n",
10487 s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
10490 for (var a = [], i = 0; i < 7; a.push(Date.getShortDayName(i)), ++i); // get localised short day names
10494 s:"(?:" + a.join("|") +")"
10501 s:"(?:" + Date.dayNames.join("|") + ")"
10507 s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
10512 s:"(?:st|nd|rd|th)"
10517 s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
10521 c:"z = parseInt(results[{0}], 10);\n",
10522 s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
10527 s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
10532 c:"m = parseInt(Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
10533 s:"(" + Date.monthNames.join("|") + ")"
10537 for (var a = [], i = 0; i < 12; a.push(Date.getShortMonthName(i)), ++i); // get localised short month names
10538 return Ext.applyIf({
10539 s:"(" + a.join("|") + ")"
10544 c:"m = parseInt(results[{0}], 10) - 1;\n",
10545 s:"(\\d{2})" // month number with leading zeros (01 - 12)
10549 c:"m = parseInt(results[{0}], 10) - 1;\n",
10550 s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
10555 s:"(?:\\d{2})" // no. of days in the month (28 - 31)
10567 c:"y = parseInt(results[{0}], 10);\n",
10568 s:"(\\d{4})" // 4-digit year
10572 c:"var ty = parseInt(results[{0}], 10);\n"
10573 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
10578 c:"if (results[{0}] == 'am') {\n"
10579 + "if (!h || h == 12) { h = 0; }\n"
10580 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
10585 c:"if (results[{0}] == 'AM') {\n"
10586 + "if (!h || h == 12) { h = 0; }\n"
10587 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
10595 c:"h = parseInt(results[{0}], 10);\n",
10596 s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
10603 c:"h = parseInt(results[{0}], 10);\n",
10604 s:"(\\d{2})" // 24-hr format of an hour with leading zeroes (00 - 23)
10608 c:"i = parseInt(results[{0}], 10);\n",
10609 s:"(\\d{2})" // minutes with leading zeros (00 - 59)
10613 c:"s = parseInt(results[{0}], 10);\n",
10614 s:"(\\d{2})" // seconds with leading zeros (00 - 59)
10618 c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
10619 s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
10624 "o = results[{0}];",
10625 "var sn = o.substring(0,1),", // get + / - sign
10626 "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
10627 "mn = o.substring(3,5) % 60;", // get minutes
10628 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
10630 s: "([+\-]\\d{4})" // GMT offset in hrs and mins
10635 "o = results[{0}];",
10636 "var sn = o.substring(0,1),", // get + / - sign
10637 "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
10638 "mn = o.substring(4,6) % 60;", // get minutes
10639 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
10641 s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
10646 s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
10650 c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
10651 + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
10652 s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
10657 $f("Y", 1), // year
10658 $f("m", 2), // month
10660 $f("h", 4), // hour
10661 $f("i", 5), // minute
10662 $f("s", 6), // second
10663 {c:"ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n"}, // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
10664 {c:[ // allow either "Z" (i.e. UTC) or "-0530" or "+08:00" (i.e. UTC offset) timezone delimiters. assumes local timezone if no timezone is specified
10665 "if(results[8]) {", // timezone specified
10666 "if(results[8] == 'Z'){",
10668 "}else if (results[8].indexOf(':') > -1){",
10669 $f("P", 8).c, // timezone offset with colon separator
10671 $f("O", 8).c, // timezone offset without colon separator
10677 for (var i = 0, l = arr.length; i < l; ++i) {
10678 calc.push(arr[i].c);
10685 arr[0].s, // year (required)
10686 "(?:", "-", arr[1].s, // month (optional)
10687 "(?:", "-", arr[2].s, // day (optional)
10689 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
10690 arr[3].s, ":", arr[4].s, // hour AND minute, delimited by a single colon (optional). MUST be preceded by either a "T" or a single blank space
10691 "(?::", arr[5].s, ")?", // seconds (optional)
10692 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
10693 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
10702 c:"u = parseInt(results[{0}], 10);\n",
10703 s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
10710 Ext.apply(Date.prototype, {
10712 dateFormat : function(format) {
10713 if (Date.formatFunctions[format] == null) {
10714 Date.createFormat(format);
10716 return Date.formatFunctions[format].call(this);
10720 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
10722 * Note: The date string returned by the javascript Date object's toString() method varies
10723 * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
10724 * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
10725 * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
10726 * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
10727 * from the GMT offset portion of the date string.
10728 * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
10730 getTimezone : function() {
10731 // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
10733 // Opera : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
10734 // Safari : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone (same as FF)
10735 // FF : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
10736 // IE : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
10737 // IE : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
10739 // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
10740 // step 1: (?:\((.*)\) -- find timezone in parentheses
10741 // step 2: ([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?) -- if nothing was found in step 1, find timezone from timezone offset portion of date string
10742 // step 3: remove all non uppercase characters found in step 1 and 2
10743 return this.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
10747 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
10748 * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
10749 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
10751 getGMTOffset : function(colon) {
10752 return (this.getTimezoneOffset() > 0 ? "-" : "+")
10753 + String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset()) / 60), 2, "0")
10754 + (colon ? ":" : "")
10755 + String.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, "0");
10759 * Get the numeric day number of the year, adjusted for leap year.
10760 * @return {Number} 0 to 364 (365 in leap years).
10762 getDayOfYear: function() {
10765 m = this.getMonth(),
10768 for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
10769 num += d.getDaysInMonth();
10771 return num + this.getDate() - 1;
10775 * Get the numeric ISO-8601 week number of the year.
10776 * (equivalent to the format specifier 'W', but without a leading zero).
10777 * @return {Number} 1 to 53
10779 getWeekOfYear : function() {
10780 // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
10781 var ms1d = 864e5, // milliseconds in a day
10782 ms7d = 7 * ms1d; // milliseconds in a week
10784 return function() { // return a closure so constants get calculated only once
10785 var DC3 = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / ms1d, // an Absolute Day Number
10786 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
10787 Wyr = new Date(AWN * ms7d).getUTCFullYear();
10789 return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
10794 * Checks if the current date falls within a leap year.
10795 * @return {Boolean} True if the current date falls within a leap year, false otherwise.
10797 isLeapYear : function() {
10798 var year = this.getFullYear();
10799 return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
10803 * Get the first day of the current month, adjusted for leap year. The returned value
10804 * is the numeric day index within the week (0-6) which can be used in conjunction with
10805 * the {@link #monthNames} array to retrieve the textual day name.
10808 var dt = new Date('1/10/2007');
10809 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
10811 * @return {Number} The day number (0-6).
10813 getFirstDayOfMonth : function() {
10814 var day = (this.getDay() - (this.getDate() - 1)) % 7;
10815 return (day < 0) ? (day + 7) : day;
10819 * Get the last day of the current month, adjusted for leap year. The returned value
10820 * is the numeric day index within the week (0-6) which can be used in conjunction with
10821 * the {@link #monthNames} array to retrieve the textual day name.
10824 var dt = new Date('1/10/2007');
10825 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
10827 * @return {Number} The day number (0-6).
10829 getLastDayOfMonth : function() {
10830 return this.getLastDateOfMonth().getDay();
10835 * Get the date of the first day of the month in which this date resides.
10838 getFirstDateOfMonth : function() {
10839 return new Date(this.getFullYear(), this.getMonth(), 1);
10843 * Get the date of the last day of the month in which this date resides.
10846 getLastDateOfMonth : function() {
10847 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
10851 * Get the number of days in the current month, adjusted for leap year.
10852 * @return {Number} The number of days in the month.
10854 getDaysInMonth: function() {
10855 var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
10857 return function() { // return a closure for efficiency
10858 var m = this.getMonth();
10860 return m == 1 && this.isLeapYear() ? 29 : daysInMonth[m];
10865 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
10866 * @return {String} 'st, 'nd', 'rd' or 'th'.
10868 getSuffix : function() {
10869 switch (this.getDate()) {
10886 * Creates and returns a new Date instance with the exact same date value as the called instance.
10887 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
10888 * variable will also be changed. When the intention is to create a new variable that will not
10889 * modify the original instance, you should create a clone.
10891 * Example of correctly cloning a date:
10894 var orig = new Date('10/1/2006');
10897 document.write(orig); //returns 'Thu Oct 05 2006'!
10900 var orig = new Date('10/1/2006');
10901 var copy = orig.clone();
10903 document.write(orig); //returns 'Thu Oct 01 2006'
10905 * @return {Date} The new Date instance.
10907 clone : function() {
10908 return new Date(this.getTime());
10912 * Checks if the current date is affected by Daylight Saving Time (DST).
10913 * @return {Boolean} True if the current date is affected by DST.
10915 isDST : function() {
10916 // adapted from http://extjs.com/forum/showthread.php?p=247172#post247172
10917 // courtesy of @geoffrey.mcgill
10918 return new Date(this.getFullYear(), 0, 1).getTimezoneOffset() != this.getTimezoneOffset();
10922 * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
10923 * automatically adjusting for Daylight Saving Time (DST) where applicable.
10924 * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
10925 * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
10926 * @return {Date} this or the clone.
10928 clearTime : function(clone) {
10930 return this.clone().clearTime();
10933 // get current date before clearing time
10934 var d = this.getDate();
10938 this.setMinutes(0);
10939 this.setSeconds(0);
10940 this.setMilliseconds(0);
10942 if (this.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
10943 // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
10944 // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
10946 // increment hour until cloned date == current date
10947 for (var hr = 1, c = this.add(Date.HOUR, hr); c.getDate() != d; hr++, c = this.add(Date.HOUR, hr));
10950 this.setHours(c.getHours());
10957 * Provides a convenient method for performing basic date arithmetic. This method
10958 * does not modify the Date instance being called - it creates and returns
10959 * a new Date instance containing the resulting date value.
10964 var dt = new Date('10/29/2006').add(Date.DAY, 5);
10965 document.write(dt); //returns 'Fri Nov 03 2006 00:00:00'
10967 // Negative values will be subtracted:
10968 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
10969 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
10971 // You can even chain several calls together in one line:
10972 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
10973 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
10976 * @param {String} interval A valid date interval enum value.
10977 * @param {Number} value The amount to add to the current date.
10978 * @return {Date} The new Date instance.
10980 add : function(interval, value) {
10981 var d = this.clone();
10982 if (!interval || value === 0) return d;
10984 switch(interval.toLowerCase()) {
10986 d.setMilliseconds(this.getMilliseconds() + value);
10989 d.setSeconds(this.getSeconds() + value);
10992 d.setMinutes(this.getMinutes() + value);
10995 d.setHours(this.getHours() + value);
10998 d.setDate(this.getDate() + value);
11001 var day = this.getDate();
11003 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
11006 d.setMonth(this.getMonth() + value);
11009 d.setFullYear(this.getFullYear() + value);
11016 * Checks if this date falls on or between the given start and end dates.
11017 * @param {Date} start Start date
11018 * @param {Date} end End date
11019 * @return {Boolean} true if this date falls on or between the given start and end dates.
11021 between : function(start, end) {
11022 var t = this.getTime();
11023 return start.getTime() <= t && t <= end.getTime();
11029 * Formats a date given the supplied format string.
11030 * @param {String} format The format string.
11031 * @return {String} The formatted date.
11034 Date.prototype.format = Date.prototype.dateFormat;
11038 if (Ext.isSafari && (navigator.userAgent.match(/WebKit\/(\d+)/)[1] || NaN) < 420) {
11039 Ext.apply(Date.prototype, {
11040 _xMonth : Date.prototype.setMonth,
11041 _xDate : Date.prototype.setDate,
11043 // Bug in Safari 1.3, 2.0 (WebKit build < 420)
11044 // Date.setMonth does not work consistently if iMonth is not 0-11
11045 setMonth : function(num) {
11047 var n = Math.ceil(-num),
11048 back_year = Math.ceil(n / 12),
11049 month = (n % 12) ? 12 - n % 12 : 0;
11051 this.setFullYear(this.getFullYear() - back_year);
11053 return this._xMonth(month);
11055 return this._xMonth(num);
11059 // Bug in setDate() method (resolved in WebKit build 419.3, so to be safe we target Webkit builds < 420)
11060 // The parameter for Date.setDate() is converted to a signed byte integer in Safari
11061 // http://brianary.blogspot.com/2006/03/safari-date-bug.html
11062 setDate : function(d) {
11063 // use setTime() to workaround setDate() bug
11064 // subtract current day of month in milliseconds, then add desired day of month in milliseconds
11065 return this.setTime(this.getTime() - (this.getDate() - d) * 864e5);
11072 /* Some basic Date tests... (requires Firebug)
11074 Date.parseDate('', 'c'); // call Date.parseDate() once to force computation of regex string so we can console.log() it
11075 console.log('Insane Regex for "c" format: %o', Date.parseCodes.c.s); // view the insane regex for the "c" format specifier
11078 console.group('Standard Date.parseDate() Tests');
11079 console.log('Date.parseDate("2009-01-05T11:38:56", "c") = %o', Date.parseDate("2009-01-05T11:38:56", "c")); // assumes browser's timezone setting
11080 console.log('Date.parseDate("2009-02-04T12:37:55.001000", "c") = %o', Date.parseDate("2009-02-04T12:37:55.001000", "c")); // assumes browser's timezone setting
11081 console.log('Date.parseDate("2009-03-03T13:36:54,101000Z", "c") = %o', Date.parseDate("2009-03-03T13:36:54,101000Z", "c")); // UTC
11082 console.log('Date.parseDate("2009-04-02T14:35:53.901000-0530", "c") = %o', Date.parseDate("2009-04-02T14:35:53.901000-0530", "c")); // GMT-0530
11083 console.log('Date.parseDate("2009-05-01T15:34:52,9876000+08:00", "c") = %o', Date.parseDate("2009-05-01T15:34:52,987600+08:00", "c")); // GMT+08:00
11084 console.groupEnd();
11086 // ISO-8601 format as specified in http://www.w3.org/TR/NOTE-datetime
11087 // -- accepts ALL 6 levels of date-time granularity
11088 console.group('ISO-8601 Granularity Test (see http://www.w3.org/TR/NOTE-datetime)');
11089 console.log('Date.parseDate("1997", "c") = %o', Date.parseDate("1997", "c")); // YYYY (e.g. 1997)
11090 console.log('Date.parseDate("1997-07", "c") = %o', Date.parseDate("1997-07", "c")); // YYYY-MM (e.g. 1997-07)
11091 console.log('Date.parseDate("1997-07-16", "c") = %o', Date.parseDate("1997-07-16", "c")); // YYYY-MM-DD (e.g. 1997-07-16)
11092 console.log('Date.parseDate("1997-07-16T19:20+01:00", "c") = %o', Date.parseDate("1997-07-16T19:20+01:00", "c")); // YYYY-MM-DDThh:mmTZD (e.g. 1997-07-16T19:20+01:00)
11093 console.log('Date.parseDate("1997-07-16T19:20:30+01:00", "c") = %o', Date.parseDate("1997-07-16T19:20:30+01:00", "c")); // YYYY-MM-DDThh:mm:ssTZD (e.g. 1997-07-16T19:20:30+01:00)
11094 console.log('Date.parseDate("1997-07-16T19:20:30.45+01:00", "c") = %o', Date.parseDate("1997-07-16T19:20:30.45+01:00", "c")); // YYYY-MM-DDThh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45+01:00)
11095 console.log('Date.parseDate("1997-07-16 19:20:30.45+01:00", "c") = %o', Date.parseDate("1997-07-16 19:20:30.45+01:00", "c")); // YYYY-MM-DD hh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45+01:00)
11096 console.log('Date.parseDate("1997-13-16T19:20:30.45+01:00", "c", true)= %o', Date.parseDate("1997-13-16T19:20:30.45+01:00", "c", true)); // strict date parsing with invalid month value
11097 console.groupEnd();
11100 * @class Ext.util.DelayedTask
11101 * <p> The DelayedTask class provides a convenient way to "buffer" the execution of a method,
11102 * performing setTimeout where a new timeout cancels the old timeout. When called, the
11103 * task will wait the specified time period before executing. If durng that time period,
11104 * the task is called again, the original call will be cancelled. This continues so that
11105 * the function is only called a single time for each iteration.</p>
11106 * <p>This method is especially useful for things like detecting whether a user has finished
11107 * typing in a text field. An example would be performing validation on a keypress. You can
11108 * use this class to buffer the keypress events for a certain number of milliseconds, and
11109 * perform only if they stop for that amount of time. Usage:</p><pre><code>
11110 var task = new Ext.util.DelayedTask(function(){
11111 alert(Ext.getDom('myInputField').value.length);
11113 // Wait 500ms before calling our function. If the user presses another key
11114 // during that 500ms, it will be cancelled and we'll wait another 500ms.
11115 Ext.get('myInputField').on('keypress', function(){
11116 task.{@link #delay}(500);
11119 * <p>Note that we are using a DelayedTask here to illustrate a point. The configuration
11120 * option <tt>buffer</tt> for {@link Ext.util.Observable#addListener addListener/on} will
11121 * also setup a delayed task for you to buffer events.</p>
11122 * @constructor The parameters to this constructor serve as defaults and are not required.
11123 * @param {Function} fn (optional) The default function to call.
11124 * @param {Object} scope The default scope (The <code><b>this</b></code> reference) in which the
11125 * function is called. If not specified, <code>this</code> will refer to the browser window.
11126 * @param {Array} args (optional) The default Array of arguments.
11128 Ext.util.DelayedTask = function(fn, scope, args){
11134 fn.apply(scope, args || []);
11138 * Cancels any pending timeout and queues a new one
11139 * @param {Number} delay The milliseconds to delay
11140 * @param {Function} newFn (optional) Overrides function passed to constructor
11141 * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
11142 * is specified, <code>this</code> will refer to the browser window.
11143 * @param {Array} newArgs (optional) Overrides args passed to constructor
11145 me.delay = function(delay, newFn, newScope, newArgs){
11148 scope = newScope || scope;
11149 args = newArgs || args;
11150 id = setInterval(call, delay);
11154 * Cancel the last queued timeout
11156 me.cancel = function(){
11163 * @class Ext.util.MixedCollection
\r
11164 * @extends Ext.util.Observable
\r
11165 * A Collection class that maintains both numeric indexes and keys and exposes events.
\r
11167 * @param {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
\r
11168 * function should add function references to the collection. Defaults to
\r
11169 * <tt>false</tt>.
\r
11170 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
\r
11171 * and return the key value for that item. This is used when available to look up the key on items that
\r
11172 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
\r
11173 * equivalent to providing an implementation for the {@link #getKey} method.
\r
11175 Ext.util.MixedCollection = function(allowFunctions, keyFn){
\r
11183 * Fires when the collection is cleared.
\r
11188 * Fires when an item is added to the collection.
\r
11189 * @param {Number} index The index at which the item was added.
\r
11190 * @param {Object} o The item added.
\r
11191 * @param {String} key The key associated with the added item.
\r
11196 * Fires when an item is replaced in the collection.
\r
11197 * @param {String} key he key associated with the new added.
\r
11198 * @param {Object} old The item being replaced.
\r
11199 * @param {Object} new The new item.
\r
11204 * Fires when an item is removed from the collection.
\r
11205 * @param {Object} o The item being removed.
\r
11206 * @param {String} key (optional) The key associated with the removed item.
\r
11211 this.allowFunctions = allowFunctions === true;
\r
11213 this.getKey = keyFn;
\r
11215 Ext.util.MixedCollection.superclass.constructor.call(this);
\r
11218 Ext.extend(Ext.util.MixedCollection, Ext.util.Observable, {
\r
11221 * @cfg {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
\r
11222 * function should add function references to the collection. Defaults to
\r
11223 * <tt>false</tt>.
\r
11225 allowFunctions : false,
\r
11228 * Adds an item to the collection. Fires the {@link #add} event when complete.
\r
11229 * @param {String} key <p>The key to associate with the item, or the new item.</p>
\r
11230 * <p>If a {@link #getKey} implementation was specified for this MixedCollection,
\r
11231 * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
\r
11232 * the MixedCollection will be able to <i>derive</i> the key for the new item.
\r
11233 * In this case just pass the new item in this parameter.</p>
\r
11234 * @param {Object} o The item to add.
\r
11235 * @return {Object} The item added.
\r
11237 add : function(key, o){
\r
11238 if(arguments.length == 1){
\r
11239 o = arguments[0];
\r
11240 key = this.getKey(o);
\r
11242 if(typeof key != 'undefined' && key !== null){
\r
11243 var old = this.map[key];
\r
11244 if(typeof old != 'undefined'){
\r
11245 return this.replace(key, o);
\r
11247 this.map[key] = o;
\r
11250 this.items.push(o);
\r
11251 this.keys.push(key);
\r
11252 this.fireEvent('add', this.length-1, o, key);
\r
11257 * MixedCollection has a generic way to fetch keys if you implement getKey. The default implementation
\r
11258 * simply returns <b><code>item.id</code></b> but you can provide your own implementation
\r
11259 * to return a different value as in the following examples:<pre><code>
\r
11261 var mc = new Ext.util.MixedCollection();
\r
11262 mc.add(someEl.dom.id, someEl);
\r
11263 mc.add(otherEl.dom.id, otherEl);
\r
11267 var mc = new Ext.util.MixedCollection();
\r
11268 mc.getKey = function(el){
\r
11269 return el.dom.id;
\r
11274 // or via the constructor
\r
11275 var mc = new Ext.util.MixedCollection(false, function(el){
\r
11276 return el.dom.id;
\r
11281 * @param {Object} item The item for which to find the key.
\r
11282 * @return {Object} The key for the passed item.
\r
11284 getKey : function(o){
\r
11289 * Replaces an item in the collection. Fires the {@link #replace} event when complete.
\r
11290 * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>
\r
11291 * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key
\r
11292 * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection
\r
11293 * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item
\r
11294 * with one having the same key value, then just pass the replacement item in this parameter.</p>
\r
11295 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate
\r
11297 * @return {Object} The new item.
\r
11299 replace : function(key, o){
\r
11300 if(arguments.length == 1){
\r
11301 o = arguments[0];
\r
11302 key = this.getKey(o);
\r
11304 var old = this.map[key];
\r
11305 if(typeof key == 'undefined' || key === null || typeof old == 'undefined'){
\r
11306 return this.add(key, o);
\r
11308 var index = this.indexOfKey(key);
\r
11309 this.items[index] = o;
\r
11310 this.map[key] = o;
\r
11311 this.fireEvent('replace', key, old, o);
\r
11316 * Adds all elements of an Array or an Object to the collection.
\r
11317 * @param {Object/Array} objs An Object containing properties which will be added
\r
11318 * to the collection, or an Array of values, each of which are added to the collection.
\r
11319 * Functions references will be added to the collection if <code>{@link #allowFunctions}</code>
\r
11320 * has been set to <tt>true</tt>.
\r
11322 addAll : function(objs){
\r
11323 if(arguments.length > 1 || Ext.isArray(objs)){
\r
11324 var args = arguments.length > 1 ? arguments : objs;
\r
11325 for(var i = 0, len = args.length; i < len; i++){
\r
11326 this.add(args[i]);
\r
11329 for(var key in objs){
\r
11330 if(this.allowFunctions || typeof objs[key] != 'function'){
\r
11331 this.add(key, objs[key]);
\r
11338 * Executes the specified function once for every item in the collection, passing the following arguments:
\r
11339 * <div class="mdetail-params"><ul>
\r
11340 * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>
\r
11341 * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>
\r
11342 * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>
\r
11344 * The function should return a boolean value. Returning false from the function will stop the iteration.
\r
11345 * @param {Function} fn The function to execute for each item.
\r
11346 * @param {Object} scope (optional) The scope in which to execute the function.
\r
11348 each : function(fn, scope){
\r
11349 var items = [].concat(this.items); // each safe for removal
\r
11350 for(var i = 0, len = items.length; i < len; i++){
\r
11351 if(fn.call(scope || items[i], items[i], i, len) === false){
\r
11358 * Executes the specified function once for every key in the collection, passing each
\r
11359 * key, and its associated item as the first two parameters.
\r
11360 * @param {Function} fn The function to execute for each item.
\r
11361 * @param {Object} scope (optional) The scope in which to execute the function.
\r
11363 eachKey : function(fn, scope){
\r
11364 for(var i = 0, len = this.keys.length; i < len; i++){
\r
11365 fn.call(scope || window, this.keys[i], this.items[i], i, len);
\r
11370 * Returns the first item in the collection which elicits a true return value from the
\r
11371 * passed selection function.
\r
11372 * @param {Function} fn The selection function to execute for each item.
\r
11373 * @param {Object} scope (optional) The scope in which to execute the function.
\r
11374 * @return {Object} The first item in the collection which returned true from the selection function.
\r
11376 find : function(fn, scope){
\r
11377 for(var i = 0, len = this.items.length; i < len; i++){
\r
11378 if(fn.call(scope || window, this.items[i], this.keys[i])){
\r
11379 return this.items[i];
\r
11386 * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.
\r
11387 * @param {Number} index The index to insert the item at.
\r
11388 * @param {String} key The key to associate with the new item, or the item itself.
\r
11389 * @param {Object} o (optional) If the second parameter was a key, the new item.
\r
11390 * @return {Object} The item inserted.
\r
11392 insert : function(index, key, o){
\r
11393 if(arguments.length == 2){
\r
11394 o = arguments[1];
\r
11395 key = this.getKey(o);
\r
11397 if(this.containsKey(key)){
\r
11398 this.suspendEvents();
\r
11399 this.removeKey(key);
\r
11400 this.resumeEvents();
\r
11402 if(index >= this.length){
\r
11403 return this.add(key, o);
\r
11406 this.items.splice(index, 0, o);
\r
11407 if(typeof key != 'undefined' && key !== null){
\r
11408 this.map[key] = o;
\r
11410 this.keys.splice(index, 0, key);
\r
11411 this.fireEvent('add', index, o, key);
\r
11416 * Remove an item from the collection.
\r
11417 * @param {Object} o The item to remove.
\r
11418 * @return {Object} The item removed or false if no item was removed.
\r
11420 remove : function(o){
\r
11421 return this.removeAt(this.indexOf(o));
\r
11425 * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.
\r
11426 * @param {Number} index The index within the collection of the item to remove.
\r
11427 * @return {Object} The item removed or false if no item was removed.
\r
11429 removeAt : function(index){
\r
11430 if(index < this.length && index >= 0){
\r
11432 var o = this.items[index];
\r
11433 this.items.splice(index, 1);
\r
11434 var key = this.keys[index];
\r
11435 if(typeof key != 'undefined'){
\r
11436 delete this.map[key];
\r
11438 this.keys.splice(index, 1);
\r
11439 this.fireEvent('remove', o, key);
\r
11446 * Removed an item associated with the passed key fom the collection.
\r
11447 * @param {String} key The key of the item to remove.
\r
11448 * @return {Object} The item removed or false if no item was removed.
\r
11450 removeKey : function(key){
\r
11451 return this.removeAt(this.indexOfKey(key));
\r
11455 * Returns the number of items in the collection.
\r
11456 * @return {Number} the number of items in the collection.
\r
11458 getCount : function(){
\r
11459 return this.length;
\r
11463 * Returns index within the collection of the passed Object.
\r
11464 * @param {Object} o The item to find the index of.
\r
11465 * @return {Number} index of the item. Returns -1 if not found.
\r
11467 indexOf : function(o){
\r
11468 return this.items.indexOf(o);
\r
11472 * Returns index within the collection of the passed key.
\r
11473 * @param {String} key The key to find the index of.
\r
11474 * @return {Number} index of the key.
\r
11476 indexOfKey : function(key){
\r
11477 return this.keys.indexOf(key);
\r
11481 * Returns the item associated with the passed key OR index.
\r
11482 * Key has priority over index. This is the equivalent
\r
11483 * of calling {@link #key} first, then if nothing matched calling {@link #itemAt}.
\r
11484 * @param {String/Number} key The key or index of the item.
\r
11485 * @return {Object} If the item is found, returns the item. If the item was not found, returns <tt>undefined</tt>.
\r
11486 * If an item was found, but is a Class, returns <tt>null</tt>.
\r
11488 item : function(key){
\r
11489 var mk = this.map[key],
\r
11490 item = mk !== undefined ? mk : (typeof key == 'number') ? this.items[key] : undefined;
\r
11491 return !Ext.isFunction(item) || this.allowFunctions ? item : null; // for prototype!
\r
11495 * Returns the item at the specified index.
\r
11496 * @param {Number} index The index of the item.
\r
11497 * @return {Object} The item at the specified index.
\r
11499 itemAt : function(index){
\r
11500 return this.items[index];
\r
11504 * Returns the item associated with the passed key.
\r
11505 * @param {String/Number} key The key of the item.
\r
11506 * @return {Object} The item associated with the passed key.
\r
11508 key : function(key){
\r
11509 return this.map[key];
\r
11513 * Returns true if the collection contains the passed Object as an item.
\r
11514 * @param {Object} o The Object to look for in the collection.
\r
11515 * @return {Boolean} True if the collection contains the Object as an item.
\r
11517 contains : function(o){
\r
11518 return this.indexOf(o) != -1;
\r
11522 * Returns true if the collection contains the passed Object as a key.
\r
11523 * @param {String} key The key to look for in the collection.
\r
11524 * @return {Boolean} True if the collection contains the Object as a key.
\r
11526 containsKey : function(key){
\r
11527 return typeof this.map[key] != 'undefined';
\r
11531 * Removes all items from the collection. Fires the {@link #clear} event when complete.
\r
11533 clear : function(){
\r
11538 this.fireEvent('clear');
\r
11542 * Returns the first item in the collection.
\r
11543 * @return {Object} the first item in the collection..
\r
11545 first : function(){
\r
11546 return this.items[0];
\r
11550 * Returns the last item in the collection.
\r
11551 * @return {Object} the last item in the collection..
\r
11553 last : function(){
\r
11554 return this.items[this.length-1];
\r
11559 * @param {String} property Property to sort by ('key', 'value', or 'index')
\r
11560 * @param {String} dir (optional) Direction to sort 'ASC' or 'DESC'. Defaults to 'ASC'.
\r
11561 * @param {Function} fn (optional) Comparison function that defines the sort order.
\r
11562 * Defaults to sorting by numeric value.
\r
11564 _sort : function(property, dir, fn){
\r
11567 dsc = String(dir).toUpperCase() == 'DESC' ? -1 : 1,
\r
11568 c = [], k = this.keys, items = this.items;
\r
11570 fn = fn || function(a, b){
\r
11573 for(i = 0, len = items.length; i < len; i++){
\r
11574 c[c.length] = {key: k[i], value: items[i], index: i};
\r
11576 c.sort(function(a, b){
\r
11577 var v = fn(a[property], b[property]) * dsc;
\r
11579 v = (a.index < b.index ? -1 : 1);
\r
11583 for(i = 0, len = c.length; i < len; i++){
\r
11584 items[i] = c[i].value;
\r
11587 this.fireEvent('sort', this);
\r
11591 * Sorts this collection by <b>item</b> value with the passed comparison function.
\r
11592 * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.
\r
11593 * @param {Function} fn (optional) Comparison function that defines the sort order.
\r
11594 * Defaults to sorting by numeric value.
\r
11596 sort : function(dir, fn){
\r
11597 this._sort('value', dir, fn);
\r
11601 * Sorts this collection by <b>key</b>s.
\r
11602 * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.
\r
11603 * @param {Function} fn (optional) Comparison function that defines the sort order.
\r
11604 * Defaults to sorting by case insensitive string.
\r
11606 keySort : function(dir, fn){
\r
11607 this._sort('key', dir, fn || function(a, b){
\r
11608 var v1 = String(a).toUpperCase(), v2 = String(b).toUpperCase();
\r
11609 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
\r
11614 * Returns a range of items in this collection
\r
11615 * @param {Number} startIndex (optional) The starting index. Defaults to 0.
\r
11616 * @param {Number} endIndex (optional) The ending index. Defaults to the last item.
\r
11617 * @return {Array} An array of items
\r
11619 getRange : function(start, end){
\r
11620 var items = this.items;
\r
11621 if(items.length < 1){
\r
11624 start = start || 0;
\r
11625 end = Math.min(typeof end == 'undefined' ? this.length-1 : end, this.length-1);
\r
11627 if(start <= end){
\r
11628 for(i = start; i <= end; i++) {
\r
11629 r[r.length] = items[i];
\r
11632 for(i = start; i >= end; i--) {
\r
11633 r[r.length] = items[i];
\r
11640 * Filter the <i>objects</i> in this collection by a specific property.
\r
11641 * Returns a new collection that has been filtered.
\r
11642 * @param {String} property A property on your objects
\r
11643 * @param {String/RegExp} value Either string that the property values
\r
11644 * should start with or a RegExp to test against the property
\r
11645 * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
\r
11646 * @param {Boolean} caseSensitive (optional) True for case sensitive comparison (defaults to False).
\r
11647 * @return {MixedCollection} The new filtered collection
\r
11649 filter : function(property, value, anyMatch, caseSensitive){
\r
11650 if(Ext.isEmpty(value, false)){
\r
11651 return this.clone();
\r
11653 value = this.createValueMatcher(value, anyMatch, caseSensitive);
\r
11654 return this.filterBy(function(o){
\r
11655 return o && value.test(o[property]);
\r
11660 * Filter by a function. Returns a <i>new</i> collection that has been filtered.
\r
11661 * The passed function will be called with each object in the collection.
\r
11662 * If the function returns true, the value is included otherwise it is filtered.
\r
11663 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
\r
11664 * @param {Object} scope (optional) The scope of the function (defaults to this)
\r
11665 * @return {MixedCollection} The new filtered collection
\r
11667 filterBy : function(fn, scope){
\r
11668 var r = new Ext.util.MixedCollection();
\r
11669 r.getKey = this.getKey;
\r
11670 var k = this.keys, it = this.items;
\r
11671 for(var i = 0, len = it.length; i < len; i++){
\r
11672 if(fn.call(scope||this, it[i], k[i])){
\r
11673 r.add(k[i], it[i]);
\r
11680 * Finds the index of the first matching object in this collection by a specific property/value.
\r
11681 * @param {String} property The name of a property on your objects.
\r
11682 * @param {String/RegExp} value A string that the property values
\r
11683 * should start with or a RegExp to test against the property.
\r
11684 * @param {Number} start (optional) The index to start searching at (defaults to 0).
\r
11685 * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning.
\r
11686 * @param {Boolean} caseSensitive (optional) True for case sensitive comparison.
\r
11687 * @return {Number} The matched index or -1
\r
11689 findIndex : function(property, value, start, anyMatch, caseSensitive){
\r
11690 if(Ext.isEmpty(value, false)){
\r
11693 value = this.createValueMatcher(value, anyMatch, caseSensitive);
\r
11694 return this.findIndexBy(function(o){
\r
11695 return o && value.test(o[property]);
\r
11700 * Find the index of the first matching object in this collection by a function.
\r
11701 * If the function returns <i>true</i> it is considered a match.
\r
11702 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).
\r
11703 * @param {Object} scope (optional) The scope of the function (defaults to this).
\r
11704 * @param {Number} start (optional) The index to start searching at (defaults to 0).
\r
11705 * @return {Number} The matched index or -1
\r
11707 findIndexBy : function(fn, scope, start){
\r
11708 var k = this.keys, it = this.items;
\r
11709 for(var i = (start||0), len = it.length; i < len; i++){
\r
11710 if(fn.call(scope||this, it[i], k[i])){
\r
11718 createValueMatcher : function(value, anyMatch, caseSensitive){
\r
11719 if(!value.exec){ // not a regex
\r
11720 value = String(value);
\r
11721 value = new RegExp((anyMatch === true ? '' : '^') + Ext.escapeRe(value), caseSensitive ? '' : 'i');
\r
11727 * Creates a shallow copy of this collection
\r
11728 * @return {MixedCollection}
\r
11730 clone : function(){
\r
11731 var r = new Ext.util.MixedCollection();
\r
11732 var k = this.keys, it = this.items;
\r
11733 for(var i = 0, len = it.length; i < len; i++){
\r
11734 r.add(k[i], it[i]);
\r
11736 r.getKey = this.getKey;
\r
11741 * This method calls {@link #item item()}.
\r
11742 * Returns the item associated with the passed key OR index. Key has priority
\r
11743 * over index. This is the equivalent of calling {@link #key} first, then if
\r
11744 * nothing matched calling {@link #itemAt}.
\r
11745 * @param {String/Number} key The key or index of the item.
\r
11746 * @return {Object} If the item is found, returns the item. If the item was
\r
11747 * not found, returns <tt>undefined</tt>. If an item was found, but is a Class,
\r
11748 * returns <tt>null</tt>.
\r
11750 Ext.util.MixedCollection.prototype.get = Ext.util.MixedCollection.prototype.item;/**
11751 * @class Ext.util.JSON
11752 * Modified version of Douglas Crockford"s json.js that doesn"t
11753 * mess with the Object prototype
11754 * http://www.json.org/js.html
11757 Ext.util.JSON = new (function(){
11758 var useHasOwn = !!{}.hasOwnProperty,
11759 isNative = function() {
11760 var useNative = null;
11762 return function() {
11763 if (useNative === null) {
11764 useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
11770 pad = function(n) {
11771 return n < 10 ? "0" + n : n;
11773 doDecode = function(json){
11774 return eval("(" + json + ')');
11776 doEncode = function(o){
11777 if(!Ext.isDefined(o) || o === null){
11779 }else if(Ext.isArray(o)){
11780 return encodeArray(o);
11781 }else if(Ext.isDate(o)){
11782 return Ext.util.JSON.encodeDate(o);
11783 }else if(Ext.isString(o)){
11784 return encodeString(o);
11785 }else if(typeof o == "number"){
11786 //don't use isNumber here, since finite checks happen inside isNumber
11787 return isFinite(o) ? String(o) : "null";
11788 }else if(Ext.isBoolean(o)){
11791 var a = ["{"], b, i, v;
11793 // don't encode DOM objects
11794 if(!o.getElementsByTagName){
11795 if(!useHasOwn || o.hasOwnProperty(i)) {
11797 switch (typeof v) {
11806 a.push(doEncode(i), ":",
11807 v === null ? "null" : doEncode(v));
11826 encodeString = function(s){
11827 if (/["\\\x00-\x1f]/.test(s)) {
11828 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
11833 c = b.charCodeAt();
11835 Math.floor(c / 16).toString(16) +
11836 (c % 16).toString(16);
11839 return '"' + s + '"';
11841 encodeArray = function(o){
11842 var a = ["["], b, i, l = o.length, v;
11843 for (i = 0; i < l; i += 1) {
11845 switch (typeof v) {
11854 a.push(v === null ? "null" : Ext.util.JSON.encode(v));
11862 this.encodeDate = function(o){
11863 return '"' + o.getFullYear() + "-" +
11864 pad(o.getMonth() + 1) + "-" +
11865 pad(o.getDate()) + "T" +
11866 pad(o.getHours()) + ":" +
11867 pad(o.getMinutes()) + ":" +
11868 pad(o.getSeconds()) + '"';
11872 * Encodes an Object, Array or other value
11873 * @param {Mixed} o The variable to encode
11874 * @return {String} The JSON string
11876 this.encode = function() {
11878 return function(o) {
11880 // setup encoding function on first access
11881 ec = isNative() ? JSON.stringify : doEncode;
11889 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
11890 * @param {String} json The JSON string
11891 * @return {Object} The resulting object
11893 this.decode = function() {
11895 return function(json) {
11897 // setup decoding function on first access
11898 dc = isNative() ? JSON.parse : doDecode;
11906 * Shorthand for {@link Ext.util.JSON#encode}
11907 * @param {Mixed} o The variable to encode
11908 * @return {String} The JSON string
11912 Ext.encode = Ext.util.JSON.encode;
11914 * Shorthand for {@link Ext.util.JSON#decode}
11915 * @param {String} json The JSON string
11916 * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
11917 * @return {Object} The resulting object
11921 Ext.decode = Ext.util.JSON.decode;
11923 * @class Ext.util.Format
\r
11924 * Reusable data formatting functions
\r
11927 Ext.util.Format = function(){
\r
11928 var trimRe = /^\s+|\s+$/g;
\r
11931 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
\r
11932 * @param {String} value The string to truncate
\r
11933 * @param {Number} length The maximum length to allow before truncating
\r
11934 * @param {Boolean} word True to try to find a common work break
\r
11935 * @return {String} The converted text
\r
11937 ellipsis : function(value, len, word){
\r
11938 if(value && value.length > len){
\r
11940 var vs = value.substr(0, len - 2);
\r
11941 var index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
\r
11942 if(index == -1 || index < (len - 15)){
\r
11943 return value.substr(0, len - 3) + "...";
\r
11945 return vs.substr(0, index) + "...";
\r
11948 return value.substr(0, len - 3) + "...";
\r
11955 * Checks a reference and converts it to empty string if it is undefined
\r
11956 * @param {Mixed} value Reference to check
\r
11957 * @return {Mixed} Empty string if converted, otherwise the original value
\r
11959 undef : function(value){
\r
11960 return value !== undefined ? value : "";
\r
11964 * Checks a reference and converts it to the default value if it's empty
\r
11965 * @param {Mixed} value Reference to check
\r
11966 * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
\r
11967 * @return {String}
\r
11969 defaultValue : function(value, defaultValue){
\r
11970 return value !== undefined && value !== '' ? value : defaultValue;
\r
11974 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
\r
11975 * @param {String} value The string to encode
\r
11976 * @return {String} The encoded text
\r
11978 htmlEncode : function(value){
\r
11979 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
\r
11983 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
\r
11984 * @param {String} value The string to decode
\r
11985 * @return {String} The decoded text
\r
11987 htmlDecode : function(value){
\r
11988 return !value ? value : String(value).replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"').replace(/&/g, "&");
\r
11992 * Trims any whitespace from either side of a string
\r
11993 * @param {String} value The text to trim
\r
11994 * @return {String} The trimmed text
\r
11996 trim : function(value){
\r
11997 return String(value).replace(trimRe, "");
\r
12001 * Returns a substring from within an original string
\r
12002 * @param {String} value The original text
\r
12003 * @param {Number} start The start index of the substring
\r
12004 * @param {Number} length The length of the substring
\r
12005 * @return {String} The substring
\r
12007 substr : function(value, start, length){
\r
12008 return String(value).substr(start, length);
\r
12012 * Converts a string to all lower case letters
\r
12013 * @param {String} value The text to convert
\r
12014 * @return {String} The converted text
\r
12016 lowercase : function(value){
\r
12017 return String(value).toLowerCase();
\r
12021 * Converts a string to all upper case letters
\r
12022 * @param {String} value The text to convert
\r
12023 * @return {String} The converted text
\r
12025 uppercase : function(value){
\r
12026 return String(value).toUpperCase();
\r
12030 * Converts the first character only of a string to upper case
\r
12031 * @param {String} value The text to convert
\r
12032 * @return {String} The converted text
\r
12034 capitalize : function(value){
\r
12035 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
\r
12039 call : function(value, fn){
\r
12040 if(arguments.length > 2){
\r
12041 var args = Array.prototype.slice.call(arguments, 2);
\r
12042 args.unshift(value);
\r
12043 return eval(fn).apply(window, args);
\r
12045 return eval(fn).call(window, value);
\r
12050 * Format a number as US currency
\r
12051 * @param {Number/String} value The numeric value to format
\r
12052 * @return {String} The formatted currency string
\r
12054 usMoney : function(v){
\r
12055 v = (Math.round((v-0)*100))/100;
\r
12056 v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
\r
12058 var ps = v.split('.');
\r
12059 var whole = ps[0];
\r
12060 var sub = ps[1] ? '.'+ ps[1] : '.00';
\r
12061 var r = /(\d+)(\d{3})/;
\r
12062 while (r.test(whole)) {
\r
12063 whole = whole.replace(r, '$1' + ',' + '$2');
\r
12066 if(v.charAt(0) == '-'){
\r
12067 return '-$' + v.substr(1);
\r
12073 * Parse a value into a formatted date using the specified format pattern.
\r
12074 * @param {String/Date} value The value to format (Strings must conform to the format expected by the javascript Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method)
\r
12075 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
\r
12076 * @return {String} The formatted date string
\r
12078 date : function(v, format){
\r
12082 if(!Ext.isDate(v)){
\r
12083 v = new Date(Date.parse(v));
\r
12085 return v.dateFormat(format || "m/d/Y");
\r
12089 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
\r
12090 * @param {String} format Any valid date format string
\r
12091 * @return {Function} The date formatting function
\r
12093 dateRenderer : function(format){
\r
12094 return function(v){
\r
12095 return Ext.util.Format.date(v, format);
\r
12100 stripTagsRE : /<\/?[^>]+>/gi,
\r
12103 * Strips all HTML tags
\r
12104 * @param {Mixed} value The text from which to strip tags
\r
12105 * @return {String} The stripped text
\r
12107 stripTags : function(v){
\r
12108 return !v ? v : String(v).replace(this.stripTagsRE, "");
\r
12111 stripScriptsRe : /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
\r
12114 * Strips all script tags
\r
12115 * @param {Mixed} value The text from which to strip script tags
\r
12116 * @return {String} The stripped text
\r
12118 stripScripts : function(v){
\r
12119 return !v ? v : String(v).replace(this.stripScriptsRe, "");
\r
12123 * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
\r
12124 * @param {Number/String} size The numeric value to format
\r
12125 * @return {String} The formatted file size
\r
12127 fileSize : function(size){
\r
12128 if(size < 1024) {
\r
12129 return size + " bytes";
\r
12130 } else if(size < 1048576) {
\r
12131 return (Math.round(((size*10) / 1024))/10) + " KB";
\r
12133 return (Math.round(((size*10) / 1048576))/10) + " MB";
\r
12138 * It does simple math for use in a template, for example:<pre><code>
\r
12139 * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
\r
12141 * @return {Function} A function that operates on the passed value.
\r
12143 math : function(){
\r
12145 return function(v, a){
\r
12147 fns[a] = new Function('v', 'return v ' + a + ';');
\r
12149 return fns[a](v);
\r
12154 * Rounds the passed number to the required decimal precision.
\r
12155 * @param {Number/String} value The numeric value to round.
\r
12156 * @param {Number} precision The number of decimal places to which to round the first parameter's value.
\r
12157 * @return {Number} The rounded value.
\r
12159 round : function(value, precision) {
\r
12160 var result = Number(value);
\r
12161 if (typeof precision == 'number') {
\r
12162 precision = Math.pow(10, precision);
\r
12163 result = Math.round(value * precision) / precision;
\r
12169 * Formats the number according to the format string.
\r
12170 * <div style="margin-left:40px">examples (123456.789):
\r
12171 * <div style="margin-left:10px">
\r
12172 * 0 - (123456) show only digits, no precision<br>
\r
12173 * 0.00 - (123456.78) show only digits, 2 precision<br>
\r
12174 * 0.0000 - (123456.7890) show only digits, 4 precision<br>
\r
12175 * 0,000 - (123,456) show comma and digits, no precision<br>
\r
12176 * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
\r
12177 * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
\r
12178 * To reverse the grouping (,) and decimal (.) for international numbers, add /i to the end.
\r
12179 * For example: 0.000,00/i
\r
12181 * @param {Number} v The number to format.
\r
12182 * @param {String} format The way you would like to format this text.
\r
12183 * @return {String} The formatted number.
\r
12185 number: function(v, format) {
\r
12189 v = Ext.num(v, NaN);
\r
12199 if(format.substr(format.length - 2) == '/i'){
\r
12200 format = format.substr(0, format.length - 2);
\r
12206 var hasComma = format.indexOf(comma) != -1,
\r
12207 psplit = (i18n ? format.replace(/[^\d\,]/g, '') : format.replace(/[^\d\.]/g, '')).split(dec);
\r
12209 if(1 < psplit.length){
\r
12210 v = v.toFixed(psplit[1].length);
\r
12211 }else if(2 < psplit.length){
\r
12212 throw ('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);
\r
12214 v = v.toFixed(0);
\r
12217 var fnum = v.toString();
\r
12219 psplit = fnum.split('.');
\r
12221 var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3;
\r
12223 for(var i = 0; i < j; i += n){
\r
12227 parr[parr.length] = cnum.substr(i, n);
\r
12230 fnum = parr.join(comma);
\r
12232 fnum += dec + psplit[1];
\r
12236 return (neg ? '-' : '') + format.replace(/[\d,?\.?]+/, fnum);
\r
12240 * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
\r
12241 * @param {String} format Any valid number format string for {@link #number}
\r
12242 * @return {Function} The number formatting function
\r
12244 numberRenderer : function(format){
\r
12245 return function(v){
\r
12246 return Ext.util.Format.number(v, format);
\r
12251 * Selectively do a plural form of a word based on a numeric value. For example, in a template,
\r
12252 * {commentCount:plural("Comment")} would result in "1 Comment" if commentCount was 1 or would be "x Comments"
\r
12253 * if the value is 0 or greater than 1.
\r
12254 * @param {Number} value The value to compare against
\r
12255 * @param {String} singular The singular form of the word
\r
12256 * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
\r
12258 plural : function(v, s, p){
\r
12259 return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
\r
12263 * Converts newline characters to the HTML tag <br/>
\r
12264 * @param {String} The string value to format.
\r
12265 * @return {String} The string with embedded <br/> tags in place of newlines.
\r
12267 nl2br : function(v){
\r
12268 return v === undefined || v === null ? '' : v.replace(/\n/g, '<br/>');
\r
12272 * @class Ext.XTemplate
12273 * @extends Ext.Template
12274 * <p>A template class that supports advanced functionality like:<div class="mdetail-params"><ul>
12275 * <li>Autofilling arrays using templates and sub-templates</li>
12276 * <li>Conditional processing with basic comparison operators</li>
12277 * <li>Basic math function support</li>
12278 * <li>Execute arbitrary inline code with special built-in template variables</li>
12279 * <li>Custom member functions</li>
12280 * <li>Many special tags and built-in operators that aren't defined as part of
12281 * the API, but are supported in the templates that can be created</li>
12283 * <p>XTemplate provides the templating mechanism built into:<div class="mdetail-params"><ul>
12284 * <li>{@link Ext.DataView}</li>
12285 * <li>{@link Ext.ListView}</li>
12286 * <li>{@link Ext.form.ComboBox}</li>
12287 * <li>{@link Ext.grid.TemplateColumn}</li>
12288 * <li>{@link Ext.grid.GroupingView}</li>
12289 * <li>{@link Ext.menu.Item}</li>
12290 * <li>{@link Ext.layout.MenuLayout}</li>
12291 * <li>{@link Ext.ColorPalette}</li>
12294 * <p>For example usage {@link #XTemplate see the constructor}.</p>
12297 * The {@link Ext.Template#Template Ext.Template constructor} describes
12298 * the acceptable parameters to pass to the constructor. The following
12299 * examples demonstrate all of the supported features.</p>
12301 * <div class="mdetail-params"><ul>
12303 * <li><b><u>Sample Data</u></b>
12304 * <div class="sub-desc">
12305 * <p>This is the data object used for reference in each code example:</p>
12308 name: 'Jack Slocum',
12309 title: 'Lead Developer',
12310 company: 'Ext JS, LLC',
12311 email: 'jack@extjs.com',
12312 address: '4 Red Bulls Drive',
12316 drinks: ['Red Bull', 'Coffee', 'Water'],
12318 name: 'Sara Grace',
12324 name: 'John James',
12333 * <li><b><u>Auto filling of arrays</u></b>
12334 * <div class="sub-desc">
12335 * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>for</tt></b> operator are used
12336 * to process the provided data object:
12338 * <li>If the value specified in <tt>for</tt> is an array, it will auto-fill,
12339 * repeating the template block inside the <tt>tpl</tt> tag for each item in the
12341 * <li>If <tt>for="."</tt> is specified, the data object provided is examined.</li>
12342 * <li>While processing an array, the special variable <tt>{#}</tt>
12343 * will provide the current array index + 1 (starts at 1, not 0).</li>
12347 <tpl <b>for</b>=".">...</tpl> // loop through array at root node
12348 <tpl <b>for</b>="foo">...</tpl> // loop through array at foo node
12349 <tpl <b>for</b>="foo.bar">...</tpl> // loop through array at foo.bar node
12351 * Using the sample data above:
12353 var tpl = new Ext.XTemplate(
12355 '<tpl <b>for</b>=".">', // process the data.kids node
12356 '<p>{#}. {name}</p>', // use current array index to autonumber
12359 tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object
12361 * <p>An example illustrating how the <b><tt>for</tt></b> property can be leveraged
12362 * to access specified members of the provided data object to populate the template:</p>
12364 var tpl = new Ext.XTemplate(
12365 '<p>Name: {name}</p>',
12366 '<p>Title: {title}</p>',
12367 '<p>Company: {company}</p>',
12369 '<tpl <b>for="kids"</b>>', // interrogate the kids property within the data
12370 '<p>{name}</p>',
12373 tpl.overwrite(panel.body, data); // pass the root node of the data object
12375 * <p>Flat arrays that contain values (and not objects) can be auto-rendered
12376 * using the special <b><tt>{.}</tt></b> variable inside a loop. This variable
12377 * will represent the value of the array at the current index:</p>
12379 var tpl = new Ext.XTemplate(
12380 '<p>{name}\'s favorite beverages:</p>',
12381 '<tpl for="drinks">',
12382 '<div> - {.}</div>',
12385 tpl.overwrite(panel.body, data);
12387 * <p>When processing a sub-template, for example while looping through a child array,
12388 * you can access the parent object's members via the <b><tt>parent</tt></b> object:</p>
12390 var tpl = new Ext.XTemplate(
12391 '<p>Name: {name}</p>',
12393 '<tpl for="kids">',
12394 '<tpl if="age > 1">',
12395 '<p>{name}</p>',
12396 '<p>Dad: {<b>parent</b>.name}</p>',
12400 tpl.overwrite(panel.body, data);
12406 * <li><b><u>Conditional processing with basic comparison operators</u></b>
12407 * <div class="sub-desc">
12408 * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>if</tt></b> operator are used
12409 * to provide conditional checks for deciding whether or not to render specific
12410 * parts of the template. Notes:<div class="sub-desc"><ul>
12411 * <li>Double quotes must be encoded if used within the conditional</li>
12412 * <li>There is no <tt>else</tt> operator — if needed, two opposite
12413 * <tt>if</tt> statements should be used.</li>
12416 <tpl if="age > 1 && age < 10">Child</tpl>
12417 <tpl if="age >= 10 && age < 18">Teenager</tpl>
12418 <tpl <b>if</b>="this.isGirl(name)">...</tpl>
12419 <tpl <b>if</b>="id==\'download\'">...</tpl>
12420 <tpl <b>if</b>="needsIcon"><img src="{icon}" class="{iconCls}"/></tpl>
12422 <tpl if="name == "Jack"">Hello</tpl>
12423 // encode " if it is part of the condition, e.g.
12424 <tpl if="name == &quot;Jack&quot;">Hello</tpl>
12426 * Using the sample data above:
12428 var tpl = new Ext.XTemplate(
12429 '<p>Name: {name}</p>',
12431 '<tpl for="kids">',
12432 '<tpl if="age > 1">',
12433 '<p>{name}</p>',
12437 tpl.overwrite(panel.body, data);
12443 * <li><b><u>Basic math support</u></b>
12444 * <div class="sub-desc">
12445 * <p>The following basic math operators may be applied directly on numeric
12446 * data values:</p><pre>
12451 var tpl = new Ext.XTemplate(
12452 '<p>Name: {name}</p>',
12454 '<tpl for="kids">',
12455 '<tpl if="age &gt; 1">', // <-- Note that the > is encoded
12456 '<p>{#}: {name}</p>', // <-- Auto-number each item
12457 '<p>In 5 Years: {age+5}</p>', // <-- Basic math
12458 '<p>Dad: {parent.name}</p>',
12462 tpl.overwrite(panel.body, data);
12468 * <li><b><u>Execute arbitrary inline code with special built-in template variables</u></b>
12469 * <div class="sub-desc">
12470 * <p>Anything between <code>{[ ... ]}</code> is considered code to be executed
12471 * in the scope of the template. There are some special variables available in that code:
12473 * <li><b><tt>values</tt></b>: The values in the current scope. If you are using
12474 * scope changing sub-templates, you can change what <tt>values</tt> is.</li>
12475 * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li>
12476 * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of the
12477 * loop you are in (1-based).</li>
12478 * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total length
12479 * of the array you are looping.</li>
12480 * <li><b><tt>fm</tt></b>: An alias for <tt>Ext.util.Format</tt>.</li>
12482 * This example demonstrates basic row striping using an inline code block and the
12483 * <tt>xindex</tt> variable:</p>
12485 var tpl = new Ext.XTemplate(
12486 '<p>Name: {name}</p>',
12487 '<p>Company: {[values.company.toUpperCase() + ", " + values.title]}</p>',
12489 '<tpl for="kids">',
12490 '<div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
12495 tpl.overwrite(panel.body, data);
12500 * <li><b><u>Template member functions</u></b>
12501 * <div class="sub-desc">
12502 * <p>One or more member functions can be specified in a configuration
12503 * object passed into the XTemplate constructor for more complex processing:</p>
12505 var tpl = new Ext.XTemplate(
12506 '<p>Name: {name}</p>',
12508 '<tpl for="kids">',
12509 '<tpl if="this.isGirl(name)">',
12510 '<p>Girl: {name} - {age}</p>',
12512 // use opposite if statement to simulate 'else' processing:
12513 '<tpl if="this.isGirl(name) == false">',
12514 '<p>Boy: {name} - {age}</p>',
12516 '<tpl if="this.isBaby(age)">',
12517 '<p>{name} is a baby!</p>',
12519 '</tpl></p>',
12521 // XTemplate configuration:
12523 disableFormats: true,
12524 // member functions:
12525 isGirl: function(name){
12526 return name == 'Sara Grace';
12528 isBaby: function(age){
12533 tpl.overwrite(panel.body, data);
12540 * @param {Mixed} config
12542 Ext.XTemplate = function(){
12543 Ext.XTemplate.superclass.constructor.apply(this, arguments);
12547 re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
12548 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
12549 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
12550 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
12558 RETURN = 'return ',
12559 WITHVALUES = 'with(values){ ';
12561 s = ['<tpl>', s, '</tpl>'].join('');
12563 while((m = s.match(re))){
12564 var m2 = m[0].match(nameRe),
12565 m3 = m[0].match(ifRe),
12566 m4 = m[0].match(execRe),
12570 name = m2 && m2[1] ? m2[1] : '';
12573 exp = m3 && m3[1] ? m3[1] : null;
12575 fn = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + RETURN +(Ext.util.Format.htmlDecode(exp))+'; }');
12579 exp = m4 && m4[1] ? m4[1] : null;
12581 exec = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES +(Ext.util.Format.htmlDecode(exp))+'; }');
12586 case '.': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + VALUES + '; }'); break;
12587 case '..': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + PARENT + '; }'); break;
12588 default: name = new Function(VALUES, PARENT, WITHVALUES + RETURN + name + '; }');
12598 s = s.replace(m[0], '{xtpl'+ id + '}');
12601 Ext.each(tpls, function(t) {
12604 me.master = tpls[tpls.length-1];
12607 Ext.extend(Ext.XTemplate, Ext.Template, {
12609 re : /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\\]\s?[\d\.\+\-\*\\\(\)]+)?\}/g,
12611 codeRe : /\{\[((?:\\\]|.|\n)*?)\]\}/g,
12614 applySubTemplate : function(id, values, parent, xindex, xcount){
12620 if ((t.test && !t.test.call(me, values, parent, xindex, xcount)) ||
12621 (t.exec && t.exec.call(me, values, parent, xindex, xcount))) {
12624 vs = t.target ? t.target.call(me, values, parent) : values;
12626 parent = t.target ? values : parent;
12627 if(t.target && Ext.isArray(vs)){
12628 Ext.each(vs, function(v, i) {
12629 buf[buf.length] = t.compiled.call(me, v, parent, i+1, len);
12631 return buf.join('');
12633 return t.compiled.call(me, vs, parent, xindex, xcount);
12637 compileTpl : function(tpl){
12638 var fm = Ext.util.Format,
12639 useF = this.disableFormats !== true,
12640 sep = Ext.isGecko ? "+" : ",",
12643 function fn(m, name, format, args, math){
12644 if(name.substr(0, 4) == 'xtpl'){
12645 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent, xindex, xcount)'+sep+"'";
12650 }else if(name === '#'){
12652 }else if(name.indexOf('.') != -1){
12655 v = "values['" + name + "']";
12658 v = '(' + v + math + ')';
12660 if (format && useF) {
12661 args = args ? ',' + args : "";
12662 if(format.substr(0, 5) != "this."){
12663 format = "fm." + format + '(';
12665 format = 'this.call("'+ format.substr(5) + '", ';
12669 args= ''; format = "("+v+" === undefined ? '' : ";
12671 return "'"+ sep + format + v + args + ")"+sep+"'";
12674 function codeFn(m, code){
12675 // Single quotes get escaped when the template is compiled, however we want to undo this when running code.
12676 return "'" + sep + '(' + code.replace(/\\'/g, "'") + ')' + sep + "'";
12679 // branched to use + in gecko and [].join() in others
12681 body = "tpl.compiled = function(values, parent, xindex, xcount){ return '" +
12682 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn) +
12685 body = ["tpl.compiled = function(values, parent, xindex, xcount){ return ['"];
12686 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn));
12687 body.push("'].join('');};");
12688 body = body.join('');
12695 * Returns an HTML fragment of this template with the specified values applied.
12696 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
12697 * @return {String} The HTML fragment
12699 applyTemplate : function(values){
12700 return this.master.compiled.call(this, values, {}, 1, 1);
12704 * Compile the template to a function for optimized performance. Recommended if the template will be used frequently.
12705 * @return {Function} The compiled function
12707 compile : function(){return this;}
12714 * @property disableFormats
12724 * Alias for {@link #applyTemplate}
12725 * Returns an HTML fragment of this template with the specified values applied.
12726 * @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'})
12727 * @return {String} The HTML fragment
12728 * @member Ext.XTemplate
12731 Ext.XTemplate.prototype.apply = Ext.XTemplate.prototype.applyTemplate;
12734 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
12735 * @param {String/HTMLElement} el A DOM element or its id
12736 * @return {Ext.Template} The created template
12739 Ext.XTemplate.from = function(el){
12740 el = Ext.getDom(el);
12741 return new Ext.XTemplate(el.value || el.innerHTML);
12743 * @class Ext.util.CSS
\r
12744 * Utility class for manipulating CSS rules
\r
12747 Ext.util.CSS = function(){
\r
12748 var rules = null;
\r
12749 var doc = document;
\r
12751 var camelRe = /(-[a-z])/gi;
\r
12752 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
\r
12756 * Creates a stylesheet from a text blob of rules.
\r
12757 * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
\r
12758 * @param {String} cssText The text containing the css rules
\r
12759 * @param {String} id An id to add to the stylesheet for later removal
\r
12760 * @return {StyleSheet}
\r
12762 createStyleSheet : function(cssText, id){
\r
12764 var head = doc.getElementsByTagName("head")[0];
\r
12765 var rules = doc.createElement("style");
\r
12766 rules.setAttribute("type", "text/css");
\r
12768 rules.setAttribute("id", id);
\r
12771 head.appendChild(rules);
\r
12772 ss = rules.styleSheet;
\r
12773 ss.cssText = cssText;
\r
12776 rules.appendChild(doc.createTextNode(cssText));
\r
12778 rules.cssText = cssText;
\r
12780 head.appendChild(rules);
\r
12781 ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
\r
12783 this.cacheStyleSheet(ss);
\r
12788 * Removes a style or link tag by id
\r
12789 * @param {String} id The id of the tag
\r
12791 removeStyleSheet : function(id){
\r
12792 var existing = doc.getElementById(id);
\r
12794 existing.parentNode.removeChild(existing);
\r
12799 * Dynamically swaps an existing stylesheet reference for a new one
\r
12800 * @param {String} id The id of an existing link tag to remove
\r
12801 * @param {String} url The href of the new stylesheet to include
\r
12803 swapStyleSheet : function(id, url){
\r
12804 this.removeStyleSheet(id);
\r
12805 var ss = doc.createElement("link");
\r
12806 ss.setAttribute("rel", "stylesheet");
\r
12807 ss.setAttribute("type", "text/css");
\r
12808 ss.setAttribute("id", id);
\r
12809 ss.setAttribute("href", url);
\r
12810 doc.getElementsByTagName("head")[0].appendChild(ss);
\r
12814 * Refresh the rule cache if you have dynamically added stylesheets
\r
12815 * @return {Object} An object (hash) of rules indexed by selector
\r
12817 refreshCache : function(){
\r
12818 return this.getRules(true);
\r
12822 cacheStyleSheet : function(ss){
\r
12826 try{// try catch for cross domain access issue
\r
12827 var ssRules = ss.cssRules || ss.rules;
\r
12828 for(var j = ssRules.length-1; j >= 0; --j){
\r
12829 rules[ssRules[j].selectorText.toLowerCase()] = ssRules[j];
\r
12835 * Gets all css rules for the document
\r
12836 * @param {Boolean} refreshCache true to refresh the internal cache
\r
12837 * @return {Object} An object (hash) of rules indexed by selector
\r
12839 getRules : function(refreshCache){
\r
12840 if(rules === null || refreshCache){
\r
12842 var ds = doc.styleSheets;
\r
12843 for(var i =0, len = ds.length; i < len; i++){
\r
12845 this.cacheStyleSheet(ds[i]);
\r
12853 * Gets an an individual CSS rule by selector(s)
\r
12854 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
\r
12855 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
\r
12856 * @return {CSSRule} The CSS rule or null if one is not found
\r
12858 getRule : function(selector, refreshCache){
\r
12859 var rs = this.getRules(refreshCache);
\r
12860 if(!Ext.isArray(selector)){
\r
12861 return rs[selector.toLowerCase()];
\r
12863 for(var i = 0; i < selector.length; i++){
\r
12864 if(rs[selector[i]]){
\r
12865 return rs[selector[i].toLowerCase()];
\r
12873 * Updates a rule property
\r
12874 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
\r
12875 * @param {String} property The css property
\r
12876 * @param {String} value The new value for the property
\r
12877 * @return {Boolean} true If a rule was found and updated
\r
12879 updateRule : function(selector, property, value){
\r
12880 if(!Ext.isArray(selector)){
\r
12881 var rule = this.getRule(selector);
\r
12883 rule.style[property.replace(camelRe, camelFn)] = value;
\r
12887 for(var i = 0; i < selector.length; i++){
\r
12888 if(this.updateRule(selector[i], property, value)){
\r
12897 @class Ext.util.ClickRepeater
12898 @extends Ext.util.Observable
12900 A wrapper class which can be applied to any element. Fires a "click" event while the
12901 mouse is pressed. The interval between firings may be specified in the config but
12902 defaults to 20 milliseconds.
12904 Optionally, a CSS class may be applied to the element during the time it is pressed.
12906 @cfg {Mixed} el The element to act as a button.
12907 @cfg {Number} delay The initial delay before the repeating event begins firing.
12908 Similar to an autorepeat key delay.
12909 @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms.
12910 @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
12911 @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
12912 "interval" and "delay" are ignored.
12913 @cfg {Boolean} preventDefault True to prevent the default click event
12914 @cfg {Boolean} stopDefault True to stop the default click event
12917 2007-02-02 jvs Original code contributed by Nige "Animal" White
12918 2007-02-02 jvs Renamed to ClickRepeater
12919 2007-02-03 jvs Modifications for FF Mac and Safari
12922 @param {Mixed} el The element to listen on
12923 @param {Object} config
12925 Ext.util.ClickRepeater = function(el, config)
12927 this.el = Ext.get(el);
12928 this.el.unselectable();
12930 Ext.apply(this, config);
12935 * Fires when the mouse button is depressed.
12936 * @param {Ext.util.ClickRepeater} this
12941 * Fires on a specified interval during the time the element is pressed.
12942 * @param {Ext.util.ClickRepeater} this
12947 * Fires when the mouse key is released.
12948 * @param {Ext.util.ClickRepeater} this
12953 if(!this.disabled){
12954 this.disabled = true;
12958 // allow inline handler
12960 this.on("click", this.handler, this.scope || this);
12963 Ext.util.ClickRepeater.superclass.constructor.call(this);
12966 Ext.extend(Ext.util.ClickRepeater, Ext.util.Observable, {
12969 preventDefault : true,
12970 stopDefault : false,
12974 * Enables the repeater and allows events to fire.
12976 enable: function(){
12978 this.el.on('mousedown', this.handleMouseDown, this);
12979 if(this.preventDefault || this.stopDefault){
12980 this.el.on('click', this.eventOptions, this);
12983 this.disabled = false;
12987 * Disables the repeater and stops events from firing.
12989 disable: function(/* private */ force){
12990 if(force || !this.disabled){
12991 clearTimeout(this.timer);
12992 if(this.pressClass){
12993 this.el.removeClass(this.pressClass);
12995 Ext.getDoc().un('mouseup', this.handleMouseUp, this);
12996 this.el.removeAllListeners();
12998 this.disabled = true;
13002 * Convenience function for setting disabled/enabled by boolean.
13003 * @param {Boolean} disabled
13005 setDisabled: function(disabled){
13006 this[disabled ? 'disable' : 'enable']();
13009 eventOptions: function(e){
13010 if(this.preventDefault){
13011 e.preventDefault();
13013 if(this.stopDefault){
13019 destroy : function() {
13020 this.disable(true);
13021 Ext.destroy(this.el);
13022 this.purgeListeners();
13026 handleMouseDown : function(){
13027 clearTimeout(this.timer);
13029 if(this.pressClass){
13030 this.el.addClass(this.pressClass);
13032 this.mousedownTime = new Date();
13034 Ext.getDoc().on("mouseup", this.handleMouseUp, this);
13035 this.el.on("mouseout", this.handleMouseOut, this);
13037 this.fireEvent("mousedown", this);
13038 this.fireEvent("click", this);
13040 // Do not honor delay or interval if acceleration wanted.
13041 if (this.accelerate) {
13044 this.timer = this.click.defer(this.delay || this.interval, this);
13048 click : function(){
13049 this.fireEvent("click", this);
13050 this.timer = this.click.defer(this.accelerate ?
13051 this.easeOutExpo(this.mousedownTime.getElapsed(),
13055 this.interval, this);
13058 easeOutExpo : function (t, b, c, d) {
13059 return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
13063 handleMouseOut : function(){
13064 clearTimeout(this.timer);
13065 if(this.pressClass){
13066 this.el.removeClass(this.pressClass);
13068 this.el.on("mouseover", this.handleMouseReturn, this);
13072 handleMouseReturn : function(){
13073 this.el.un("mouseover", this.handleMouseReturn, this);
13074 if(this.pressClass){
13075 this.el.addClass(this.pressClass);
13081 handleMouseUp : function(){
13082 clearTimeout(this.timer);
13083 this.el.un("mouseover", this.handleMouseReturn, this);
13084 this.el.un("mouseout", this.handleMouseOut, this);
13085 Ext.getDoc().un("mouseup", this.handleMouseUp, this);
13086 this.el.removeClass(this.pressClass);
13087 this.fireEvent("mouseup", this);
13090 * @class Ext.KeyNav
13091 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
13092 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13093 * way to implement custom navigation schemes for any UI component.</p>
13094 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13095 * pageUp, pageDown, del, home, end. Usage:</p>
13097 var nav = new Ext.KeyNav("my-element", {
13098 "left" : function(e){
13099 this.moveLeft(e.ctrlKey);
13101 "right" : function(e){
13102 this.moveRight(e.ctrlKey);
13104 "enter" : function(e){
13111 * @param {Mixed} el The element to bind to
13112 * @param {Object} config The config
13114 Ext.KeyNav = function(el, config){
13115 this.el = Ext.get(el);
13116 Ext.apply(this, config);
13117 if(!this.disabled){
13118 this.disabled = true;
13123 Ext.KeyNav.prototype = {
13125 * @cfg {Boolean} disabled
13126 * True to disable this KeyNav instance (defaults to false)
13130 * @cfg {String} defaultEventAction
13131 * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key. Valid values are
13132 * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and
13133 * {@link Ext.EventObject#stopPropagation} (defaults to 'stopEvent')
13135 defaultEventAction: "stopEvent",
13137 * @cfg {Boolean} forceKeyDown
13138 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
13139 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13140 * handle keydown instead of keypress.
13142 forceKeyDown : false,
13145 relay : function(e){
13146 var k = e.getKey();
13147 var h = this.keyToHandler[k];
13149 if(this.doRelay(e, this[h], h) !== true){
13150 e[this.defaultEventAction]();
13156 doRelay : function(e, h, hname){
13157 return h.call(this.scope || this, e);
13160 // possible handlers
13174 // quick lookup hash
13190 stopKeyUp: function(e) {
13191 var k = e.getKey();
13193 if (k >= 37 && k <= 40) {
13194 // *** bugfix - safari 2.x fires 2 keyup events on cursor keys
13195 // *** (note: this bugfix sacrifices the "keyup" event originating from keyNav elements in Safari 2)
13201 * Enable this KeyNav
13203 enable: function() {
13204 if (this.disabled) {
13205 if (Ext.isSafari2) {
13206 // call stopKeyUp() on "keyup" event
13207 this.el.on('keyup', this.stopKeyUp, this);
13210 this.el.on(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
13211 this.disabled = false;
13216 * Disable this KeyNav
13218 disable: function() {
13219 if (!this.disabled) {
13220 if (Ext.isSafari2) {
13221 // remove "keyup" event handler
13222 this.el.un('keyup', this.stopKeyUp, this);
13225 this.el.un(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
13226 this.disabled = true;
13231 * Convenience function for setting disabled/enabled by boolean.
13232 * @param {Boolean} disabled
13234 setDisabled : function(disabled){
13235 this[disabled ? "disable" : "enable"]();
13239 isKeydown: function(){
13240 return this.forceKeyDown || Ext.EventManager.useKeydown;
13244 * @class Ext.KeyMap
\r
13245 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
\r
13246 * The constructor accepts the same config object as defined by {@link #addBinding}.
\r
13247 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
\r
13248 * combination it will call the function with this signature (if the match is a multi-key
\r
13249 * combination the callback will still be called only once): (String key, Ext.EventObject e)
\r
13250 * A KeyMap can also handle a string representation of keys.<br />
\r
13253 // map one key by key code
\r
13254 var map = new Ext.KeyMap("my-element", {
\r
13255 key: 13, // or Ext.EventObject.ENTER
\r
13260 // map multiple keys to one action by string
\r
13261 var map = new Ext.KeyMap("my-element", {
\r
13267 // map multiple keys to multiple actions by strings and array of codes
\r
13268 var map = new Ext.KeyMap("my-element", [
\r
13271 fn: function(){ alert("Return was pressed"); }
\r
13274 fn: function(){ alert('a, b or c was pressed'); }
\r
13279 fn: function(){ alert('Control + shift + tab was pressed.'); }
\r
13283 * <b>Note: A KeyMap starts enabled</b>
\r
13285 * @param {Mixed} el The element to bind to
\r
13286 * @param {Object} config The config (see {@link #addBinding})
\r
13287 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
\r
13289 Ext.KeyMap = function(el, config, eventName){
\r
13290 this.el = Ext.get(el);
\r
13291 this.eventName = eventName || "keydown";
\r
13292 this.bindings = [];
\r
13294 this.addBinding(config);
\r
13299 Ext.KeyMap.prototype = {
\r
13301 * True to stop the event from bubbling and prevent the default browser action if the
\r
13302 * key was handled by the KeyMap (defaults to false)
\r
13305 stopEvent : false,
\r
13308 * Add a new binding to this KeyMap. The following config object properties are supported:
\r
13310 Property Type Description
\r
13311 ---------- --------------- ----------------------------------------------------------------------
\r
13312 key String/Array A single keycode or an array of keycodes to handle
\r
13313 shift Boolean True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)
\r
13314 ctrl Boolean True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)
\r
13315 alt Boolean True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)
\r
13316 handler Function The function to call when KeyMap finds the expected key combination
\r
13317 fn Function Alias of handler (for backwards-compatibility)
\r
13318 scope Object The scope of the callback function
\r
13319 stopEvent Boolean True to stop the event from bubbling and prevent the default browser action if the key was handled by the KeyMap (defaults to false)
\r
13324 // Create a KeyMap
\r
13325 var map = new Ext.KeyMap(document, {
\r
13326 key: Ext.EventObject.ENTER,
\r
13331 //Add a new binding to the existing KeyMap later
\r
13339 * @param {Object/Array} config A single KeyMap config or an array of configs
\r
13341 addBinding : function(config){
\r
13342 if(Ext.isArray(config)){
\r
13343 Ext.each(config, function(c){
\r
13344 this.addBinding(c);
\r
13348 var keyCode = config.key,
\r
13349 fn = config.fn || config.handler,
\r
13350 scope = config.scope;
\r
13352 if (config.stopEvent) {
\r
13353 this.stopEvent = config.stopEvent;
\r
13356 if(typeof keyCode == "string"){
\r
13358 var keyString = keyCode.toUpperCase();
\r
13359 for(var j = 0, len = keyString.length; j < len; j++){
\r
13360 ks.push(keyString.charCodeAt(j));
\r
13364 var keyArray = Ext.isArray(keyCode);
\r
13366 var handler = function(e){
\r
13367 if(this.checkModifiers(config, e)){
\r
13368 var k = e.getKey();
\r
13370 for(var i = 0, len = keyCode.length; i < len; i++){
\r
13371 if(keyCode[i] == k){
\r
13372 if(this.stopEvent){
\r
13375 fn.call(scope || window, k, e);
\r
13380 if(k == keyCode){
\r
13381 if(this.stopEvent){
\r
13384 fn.call(scope || window, k, e);
\r
13389 this.bindings.push(handler);
\r
13393 checkModifiers: function(config, e){
\r
13394 var val, key, keys = ['shift', 'ctrl', 'alt'];
\r
13395 for (var i = 0, len = keys.length; i < len; ++i){
\r
13397 val = config[key];
\r
13398 if(!(val === undefined || (val === e[key + 'Key']))){
\r
13406 * Shorthand for adding a single key listener
\r
13407 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
\r
13408 * following options:
\r
13409 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
\r
13410 * @param {Function} fn The function to call
\r
13411 * @param {Object} scope (optional) The scope of the function
\r
13413 on : function(key, fn, scope){
\r
13414 var keyCode, shift, ctrl, alt;
\r
13415 if(typeof key == "object" && !Ext.isArray(key)){
\r
13416 keyCode = key.key;
\r
13417 shift = key.shift;
\r
13423 this.addBinding({
\r
13434 handleKeyDown : function(e){
\r
13435 if(this.enabled){ //just in case
\r
13436 var b = this.bindings;
\r
13437 for(var i = 0, len = b.length; i < len; i++){
\r
13438 b[i].call(this, e);
\r
13444 * Returns true if this KeyMap is enabled
\r
13445 * @return {Boolean}
\r
13447 isEnabled : function(){
\r
13448 return this.enabled;
\r
13452 * Enables this KeyMap
\r
13454 enable: function(){
\r
13455 if(!this.enabled){
\r
13456 this.el.on(this.eventName, this.handleKeyDown, this);
\r
13457 this.enabled = true;
\r
13462 * Disable this KeyMap
\r
13464 disable: function(){
\r
13465 if(this.enabled){
\r
13466 this.el.removeListener(this.eventName, this.handleKeyDown, this);
\r
13467 this.enabled = false;
\r
13472 * Convenience function for setting disabled/enabled by boolean.
\r
13473 * @param {Boolean} disabled
\r
13475 setDisabled : function(disabled){
\r
13476 this[disabled ? "disable" : "enable"]();
\r
13479 * @class Ext.util.TextMetrics
13480 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13481 * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and
13482 * should not contain any HTML, otherwise it may not be measured correctly.
13485 Ext.util.TextMetrics = function(){
13489 * Measures the size of the specified text
13490 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13491 * that can affect the size of the rendered text
13492 * @param {String} text The text to measure
13493 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13494 * in order to accurately measure the text height
13495 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13497 measure : function(el, text, fixedWidth){
13499 shared = Ext.util.TextMetrics.Instance(el, fixedWidth);
13502 shared.setFixedWidth(fixedWidth || 'auto');
13503 return shared.getSize(text);
13507 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
13508 * the overhead of multiple calls to initialize the style properties on each measurement.
13509 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13510 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13511 * in order to accurately measure the text height
13512 * @return {Ext.util.TextMetrics.Instance} instance The new instance
13514 createInstance : function(el, fixedWidth){
13515 return Ext.util.TextMetrics.Instance(el, fixedWidth);
13520 Ext.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13521 var ml = new Ext.Element(document.createElement('div'));
13522 document.body.appendChild(ml.dom);
13523 ml.position('absolute');
13524 ml.setLeftTop(-1000, -1000);
13528 ml.setWidth(fixedWidth);
13533 * Returns the size of the specified text based on the internal element's style and width properties
13534 * @param {String} text The text to measure
13535 * @return {Object} An object containing the text's size {width: (width), height: (height)}
13537 getSize : function(text){
13539 var s = ml.getSize();
13545 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13546 * that can affect the size of the rendered text
13547 * @param {String/HTMLElement} el The element, dom node or id
13549 bind : function(el){
13551 Ext.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')
13556 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
13557 * to set a fixed width in order to accurately measure the text height.
13558 * @param {Number} width The width to set on the element
13560 setFixedWidth : function(width){
13561 ml.setWidth(width);
13565 * Returns the measured width of the specified text
13566 * @param {String} text The text to measure
13567 * @return {Number} width The width in pixels
13569 getWidth : function(text){
13570 ml.dom.style.width = 'auto';
13571 return this.getSize(text).width;
13575 * Returns the measured height of the specified text. For multiline text, be sure to call
13576 * {@link #setFixedWidth} if necessary.
13577 * @param {String} text The text to measure
13578 * @return {Number} height The height in pixels
13580 getHeight : function(text){
13581 return this.getSize(text).height;
13585 instance.bind(bindTo);
13590 Ext.Element.addMethods({
13592 * Returns the width in pixels of the passed text, or the width of the text in this Element.
13593 * @param {String} text The text to measure. Defaults to the innerHTML of the element.
13594 * @param {Number} min (Optional) The minumum value to return.
13595 * @param {Number} max (Optional) The maximum value to return.
13596 * @return {Number} The text width in pixels.
13597 * @member Ext.Element getTextWidth
13599 getTextWidth : function(text, min, max){
13600 return (Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width).constrain(min || 0, max || 1000000);
13604 * @class Ext.util.Cookies
\r
13605 * Utility class for managing and interacting with cookies.
\r
13608 Ext.util.Cookies = {
\r
13610 * Create a cookie with the specified name and value. Additional settings
\r
13611 * for the cookie may be optionally specified (for example: expiration,
\r
13612 * access restriction, SSL).
\r
13613 * @param {String} name The name of the cookie to set.
\r
13614 * @param {Mixed} value The value to set for the cookie.
\r
13615 * @param {Object} expires (Optional) Specify an expiration date the
\r
13616 * cookie is to persist until. Note that the specified Date object will
\r
13617 * be converted to Greenwich Mean Time (GMT).
\r
13618 * @param {String} path (Optional) Setting a path on the cookie restricts
\r
13619 * access to pages that match that path. Defaults to all pages (<tt>'/'</tt>).
\r
13620 * @param {String} domain (Optional) Setting a domain restricts access to
\r
13621 * pages on a given domain (typically used to allow cookie access across
\r
13622 * subdomains). For example, "extjs.com" will create a cookie that can be
\r
13623 * accessed from any subdomain of extjs.com, including www.extjs.com,
\r
13624 * support.extjs.com, etc.
\r
13625 * @param {Boolean} secure (Optional) Specify true to indicate that the cookie
\r
13626 * should only be accessible via SSL on a page using the HTTPS protocol.
\r
13627 * Defaults to <tt>false</tt>. Note that this will only work if the page
\r
13628 * calling this code uses the HTTPS protocol, otherwise the cookie will be
\r
13629 * created with default options.
\r
13631 set : function(name, value){
\r
13632 var argv = arguments;
\r
13633 var argc = arguments.length;
\r
13634 var expires = (argc > 2) ? argv[2] : null;
\r
13635 var path = (argc > 3) ? argv[3] : '/';
\r
13636 var domain = (argc > 4) ? argv[4] : null;
\r
13637 var secure = (argc > 5) ? argv[5] : false;
\r
13638 document.cookie = name + "=" + escape(value) + ((expires === null) ? "" : ("; expires=" + expires.toGMTString())) + ((path === null) ? "" : ("; path=" + path)) + ((domain === null) ? "" : ("; domain=" + domain)) + ((secure === true) ? "; secure" : "");
\r
13642 * Retrieves cookies that are accessible by the current page. If a cookie
\r
13643 * does not exist, <code>get()</code> returns <tt>null</tt>. The following
\r
13644 * example retrieves the cookie called "valid" and stores the String value
\r
13645 * in the variable <tt>validStatus</tt>.
\r
13647 * var validStatus = Ext.util.Cookies.get("valid");
\r
13649 * @param {String} name The name of the cookie to get
\r
13650 * @return {Mixed} Returns the cookie value for the specified name;
\r
13651 * null if the cookie name does not exist.
\r
13653 get : function(name){
\r
13654 var arg = name + "=";
\r
13655 var alen = arg.length;
\r
13656 var clen = document.cookie.length;
\r
13661 if(document.cookie.substring(i, j) == arg){
\r
13662 return Ext.util.Cookies.getCookieVal(j);
\r
13664 i = document.cookie.indexOf(" ", i) + 1;
\r
13673 * Removes a cookie with the provided name from the browser
\r
13674 * if found by setting its expiration date to sometime in the past.
\r
13675 * @param {String} name The name of the cookie to remove
\r
13677 clear : function(name){
\r
13678 if(Ext.util.Cookies.get(name)){
\r
13679 document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
\r
13685 getCookieVal : function(offset){
\r
13686 var endstr = document.cookie.indexOf(";", offset);
\r
13687 if(endstr == -1){
\r
13688 endstr = document.cookie.length;
\r
13690 return unescape(document.cookie.substring(offset, endstr));
\r
13693 * Framework-wide error-handler. Developers can override this method to provide
13694 * custom exception-handling. Framework errors will often extend from the base
13696 * @param {Object/Error} e The thrown exception object.
13698 Ext.handleError = function(e) {
13705 * <p>A base error class. Future implementations are intended to provide more
13706 * robust error handling throughout the framework (<b>in the debug build only</b>)
13707 * to check for common errors and problems. The messages issued by this class
13708 * will aid error checking. Error checks will be automatically removed in the
13709 * production build so that performance is not negatively impacted.</p>
13710 * <p>Some sample messages currently implemented:</p><pre>
13711 "DataProxy attempted to execute an API-action but found an undefined
13712 url / function. Please review your Proxy url/api-configuration."
13714 "Could not locate your "root" property in your server response.
13715 Please review your JsonReader config to ensure the config-property
13716 "root" matches the property your server-response. See the JsonReader
13717 docs for additional assistance."
13719 * <p>An example of the code used for generating error messages:</p><pre><code>
13728 function generateError(data) {
13729 throw new Ext.Error('foo-error', data);
13732 * @param {String} message
13734 Ext.Error = function(message) {
13735 // Try to read the message from Ext.Error.lang
13736 this.message = (this.lang[message]) ? this.lang[message] : message;
13738 Ext.Error.prototype = new Error();
13739 Ext.apply(Ext.Error.prototype, {
13740 // protected. Extensions place their error-strings here.
13748 getName : function() {
13755 getMessage : function() {
13756 return this.message;
13762 toJson : function() {
13763 return Ext.encode(this);