3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.DomHelper
17 * @alternateClassName Ext.core.DomHelper
19 * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
20 * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
21 * from your DOM building code.</p>
23 * <p><b><u>DomHelper element specification object</u></b></p>
24 * <p>A specification object is used when creating elements. Attributes of this object
25 * are assumed to be element attributes, except for 4 special attributes:
26 * <div class="mdetail-params"><ul>
27 * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
28 * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
29 * same kind of element definition objects to be created and appended. These can be nested
30 * as deep as you want.</div></li>
31 * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
32 * This will end up being either the "class" attribute on a HTML fragment or className
33 * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
34 * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
36 * <p><b>NOTE:</b> For other arbitrary attributes, the value will currently <b>not</b> be automatically
37 * HTML-escaped prior to building the element's HTML string. This means that if your attribute value
38 * contains special characters that would not normally be allowed in a double-quoted attribute value,
39 * you <b>must</b> manually HTML-encode it beforehand (see {@link Ext.String#htmlEncode}) or risk
40 * malformed HTML being created. This behavior may change in a future release.</p>
42 * <p><b><u>Insertion methods</u></b></p>
43 * <p>Commonly used insertion methods:
44 * <div class="mdetail-params"><ul>
45 * <li><tt>{@link #append}</tt> : <div class="sub-desc"></div></li>
46 * <li><tt>{@link #insertBefore}</tt> : <div class="sub-desc"></div></li>
47 * <li><tt>{@link #insertAfter}</tt> : <div class="sub-desc"></div></li>
48 * <li><tt>{@link #overwrite}</tt> : <div class="sub-desc"></div></li>
49 * <li><tt>{@link #createTemplate}</tt> : <div class="sub-desc"></div></li>
50 * <li><tt>{@link #insertHtml}</tt> : <div class="sub-desc"></div></li>
53 * <p><b><u>Example</u></b></p>
54 * <p>This is an example, where an unordered list with 3 children items is appended to an existing
55 * element with id <tt>'my-div'</tt>:<br>
57 var dh = Ext.DomHelper; // create shorthand alias
58 // specification object
63 // append children after creating
64 children: [ // may also specify 'cn' instead of 'children'
65 {tag: 'li', id: 'item0', html: 'List Item 0'},
66 {tag: 'li', id: 'item1', html: 'List Item 1'},
67 {tag: 'li', id: 'item2', html: 'List Item 2'}
71 'my-div', // the context element 'my-div' can either be the id or the actual node
72 spec // the specification object
75 * <p>Element creation specification parameters in this class may also be passed as an Array of
76 * specification objects. This can be used to insert multiple sibling nodes into an existing
77 * container very efficiently. For example, to add more list items to the example above:<pre><code>
79 {tag: 'li', id: 'item3', html: 'List Item 3'},
80 {tag: 'li', id: 'item4', html: 'List Item 4'}
84 * <p><b><u>Templating</u></b></p>
85 * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
86 * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
87 * insert new elements. Revisiting the example above, we could utilize templating this time:
90 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
92 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
94 for(var i = 0; i < 5, i++){
95 tpl.append(list, [i]); // use template to append to the actual node
98 * <p>An example using a template:<pre><code>
99 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
101 var tpl = new Ext.DomHelper.createTemplate(html);
102 tpl.append('blog-roll', ['link1', 'http://www.edspencer.net/', "Ed's Site"]);
103 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin's Site"]);
106 * <p>The same example using named parameters:<pre><code>
107 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
109 var tpl = new Ext.DomHelper.createTemplate(html);
110 tpl.append('blog-roll', {
112 url: 'http://www.edspencer.net/',
113 text: "Ed's Site"
115 tpl.append('blog-roll', {
117 url: 'http://www.dustindiaz.com/',
118 text: "Dustin's Site"
122 * <p><b><u>Compiling Templates</u></b></p>
123 * <p>Templates are applied using regular expressions. The performance is great, but if
124 * you are adding a bunch of DOM elements using the same template, you can increase
125 * performance even further by {@link Ext.Template#compile "compiling"} the template.
126 * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
127 * broken up at the different variable points and a dynamic function is created and eval'ed.
128 * The generated function performs string concatenation of these parts and the passed
129 * variables instead of using regular expressions.
131 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
133 var tpl = new Ext.DomHelper.createTemplate(html);
136 //... use template like normal
139 * <p><b><u>Performance Boost</u></b></p>
140 * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
141 * of DOM can significantly boost performance.</p>
142 * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
143 * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
144 * results in the creation of a text node. Usage:</p>
146 Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
151 Ext.core.DomHelper = Ext.DomHelper = function(){
152 var tempTableEl = null,
153 emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
154 tableRe = /^table|tbody|tr|td$/i,
155 confRe = /tag|children|cn|html$/i,
156 tableElRe = /td|tr|tbody/i,
159 // kill repeat to save bytes
160 afterbegin = 'afterbegin',
161 afterend = 'afterend',
162 beforebegin = 'beforebegin',
163 beforeend = 'beforeend',
172 function doInsert(el, o, returnElement, pos, sibling, append){
176 newNode = createDom(o, null);
178 el.appendChild(newNode);
180 (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
183 newNode = Ext.DomHelper.insertHtml(pos, el, Ext.DomHelper.createHtml(o));
185 return returnElement ? Ext.get(newNode, true) : newNode;
188 function createDom(o, parentNode){
196 if (Ext.isArray(o)) { // Allow Arrays of siblings to be inserted
197 el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
198 for (var i = 0, l = o.length; i < l; i++) {
201 } else if (typeof o == 'string') { // Allow a string as a child spec.
202 el = doc.createTextNode(o);
204 el = doc.createElement( o.tag || 'div' );
205 useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
207 if(!confRe.test(attr)){
213 el.setAttribute(attr, val);
220 Ext.DomHelper.applyStyles(el, o.style);
222 if ((cn = o.children || o.cn)) {
225 el.innerHTML = o.html;
229 parentNode.appendChild(el);
234 // build as innerHTML where available
235 function createHtml(o){
243 if(typeof o == "string"){
245 } else if (Ext.isArray(o)) {
246 for (i=0; i < o.length; i++) {
248 b += createHtml(o[i]);
252 b += '<' + (o.tag = o.tag || 'div');
255 if(!confRe.test(attr)){
256 if (typeof val == "object") {
257 b += ' ' + attr + '="';
259 b += key + ':' + val[key] + ';';
263 b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
267 // Now either just close the tag or try to add children and close the tag.
268 if (emptyTags.test(o.tag)) {
272 if ((cn = o.children || o.cn)) {
277 b += '</' + o.tag + '>';
283 function ieTable(depth, s, h, e){
284 tempTableEl.innerHTML = [s, h, e].join('');
291 // If the result is multiple siblings, then encapsulate them into one fragment.
294 var df = document.createDocumentFragment();
307 * Nasty code for IE's broken table implementation
309 function insertIntoTable(tag, where, el, html) {
313 tempTableEl = tempTableEl || document.createElement('div');
315 if(tag == 'td' && (where == afterbegin || where == beforeend) ||
316 !tableElRe.test(tag) && (where == beforebegin || where == afterend)) {
319 before = where == beforebegin ? el :
320 where == afterend ? el.nextSibling :
321 where == afterbegin ? el.firstChild : null;
323 if (where == beforebegin || where == afterend) {
327 if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
328 node = ieTable(4, trs, html, tre);
329 } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
330 (tag == 'tr' && (where == beforebegin || where == afterend))) {
331 node = ieTable(3, tbs, html, tbe);
333 node = ieTable(2, ts, html, te);
335 el.insertBefore(node, before);
341 * Fix for IE9 createContextualFragment missing method
343 function createContextualFragment(html){
344 var div = document.createElement("div"),
345 fragment = document.createDocumentFragment(),
349 div.innerHTML = html;
350 childNodes = div.childNodes;
351 length = childNodes.length;
353 for (; i < length; i++) {
354 fragment.appendChild(childNodes[i].cloneNode(true));
362 * Returns the markup for the passed Element(s) config.
363 * @param {Object} o The DOM object spec (and children)
366 markup : function(o){
367 return createHtml(o);
371 * Applies a style specification to an element.
372 * @param {String/HTMLElement} el The element to apply styles to
373 * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
374 * a function which returns such a specification.
376 applyStyles : function(el, styles){
379 if (typeof styles == "function") {
380 styles = styles.call();
382 if (typeof styles == "string") {
383 styles = Ext.Element.parseStyles(styles);
385 if (typeof styles == "object") {
392 * Inserts an HTML fragment into the DOM.
393 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
395 * For example take the following HTML: `<div>Contents</div>`
397 * Using different `where` values inserts element to the following places:
399 * - beforeBegin: `<HERE><div>Contents</div>`
400 * - afterBegin: `<div><HERE>Contents</div>`
401 * - beforeEnd: `<div>Contents<HERE></div>`
402 * - afterEnd: `<div>Contents</div><HERE>`
404 * @param {HTMLElement/TextNode} el The context element
405 * @param {String} html The HTML fragment
406 * @return {HTMLElement} The new node
408 insertHtml : function(where, el, html){
417 where = where.toLowerCase();
418 // add these here because they are used in both branches of the condition.
419 hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
420 hash[afterend] = ['AfterEnd', 'nextSibling'];
422 // if IE and context element is an HTMLElement
423 if (el.insertAdjacentHTML) {
424 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
428 // add these two to the hash.
429 hash[afterbegin] = ['AfterBegin', 'firstChild'];
430 hash[beforeend] = ['BeforeEnd', 'lastChild'];
431 if ((hashVal = hash[where])) {
432 el.insertAdjacentHTML(hashVal[0], html);
433 return el[hashVal[1]];
435 // if (not IE and context element is an HTMLElement) or TextNode
437 // we cannot insert anything inside a textnode so...
438 if (Ext.isTextNode(el)) {
439 where = where === 'afterbegin' ? 'beforebegin' : where;
440 where = where === 'beforeend' ? 'afterend' : where;
442 range = Ext.supports.CreateContextualFragment ? el.ownerDocument.createRange() : undefined;
443 setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
447 frag = range.createContextualFragment(html);
449 frag = createContextualFragment(html);
451 el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
452 return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
454 rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
457 range[setStart](el[rangeEl]);
458 frag = range.createContextualFragment(html);
460 frag = createContextualFragment(html);
463 if(where == afterbegin){
464 el.insertBefore(frag, el.firstChild);
466 el.appendChild(frag);
476 sourceClass: 'Ext.DomHelper',
477 sourceMethod: 'insertHtml',
480 msg: 'Illegal insertion point reached: "' + where + '"'
486 * Creates new DOM element(s) and inserts them before el.
487 * @param {String/HTMLElement/Ext.Element} el The context element
488 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
489 * @param {Boolean} returnElement (optional) true to return a Ext.Element
490 * @return {HTMLElement/Ext.Element} The new node
492 insertBefore : function(el, o, returnElement){
493 return doInsert(el, o, returnElement, beforebegin);
497 * Creates new DOM element(s) and inserts them after el.
498 * @param {String/HTMLElement/Ext.Element} el The context element
499 * @param {Object} o The DOM object spec (and children)
500 * @param {Boolean} returnElement (optional) true to return a Ext.Element
501 * @return {HTMLElement/Ext.Element} The new node
503 insertAfter : function(el, o, returnElement){
504 return doInsert(el, o, returnElement, afterend, 'nextSibling');
508 * Creates new DOM element(s) and inserts them as the first child of el.
509 * @param {String/HTMLElement/Ext.Element} el The context element
510 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
511 * @param {Boolean} returnElement (optional) true to return a Ext.Element
512 * @return {HTMLElement/Ext.Element} The new node
514 insertFirst : function(el, o, returnElement){
515 return doInsert(el, o, returnElement, afterbegin, 'firstChild');
519 * Creates new DOM element(s) and appends them to el.
520 * @param {String/HTMLElement/Ext.Element} el The context element
521 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
522 * @param {Boolean} returnElement (optional) true to return a Ext.Element
523 * @return {HTMLElement/Ext.Element} The new node
525 append : function(el, o, returnElement){
526 return doInsert(el, o, returnElement, beforeend, '', true);
530 * Creates new DOM element(s) and overwrites the contents of el with them.
531 * @param {String/HTMLElement/Ext.Element} el The context element
532 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
533 * @param {Boolean} returnElement (optional) true to return a Ext.Element
534 * @return {HTMLElement/Ext.Element} The new node
536 overwrite : function(el, o, returnElement){
538 el.innerHTML = createHtml(o);
539 return returnElement ? Ext.get(el.firstChild) : el.firstChild;
542 createHtml : createHtml,
545 * Creates new DOM element(s) without inserting them to the document.
546 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
547 * @return {HTMLElement} The new uninserted node
550 createDom: createDom,
552 /** True to force the use of DOM instead of html fragments @type Boolean */
556 * Creates a new Ext.Template from the DOM object spec.
557 * @param {Object} o The DOM object spec (and children)
558 * @return {Ext.Template} The new template
560 createTemplate : function(o){
561 var html = Ext.DomHelper.createHtml(o);
562 return Ext.create('Ext.Template', html);
569 * This is code is also distributed under MIT license for use
570 * with jQuery and prototype JavaScript libraries.
573 * @class Ext.DomQuery
574 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).
576 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>
579 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.
581 <h4>Element Selectors:</h4>
583 <li> <b>*</b> any element</li>
584 <li> <b>E</b> an element with the tag E</li>
585 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
586 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
587 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
588 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
590 <h4>Attribute Selectors:</h4>
591 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
593 <li> <b>E[foo]</b> has an attribute "foo"</li>
594 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
595 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
596 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
597 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
598 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
599 <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li>
601 <h4>Pseudo Classes:</h4>
603 <li> <b>E:first-child</b> E is the first child of its parent</li>
604 <li> <b>E:last-child</b> E is the last child of its parent</li>
605 <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>
606 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
607 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
608 <li> <b>E:only-child</b> E is the only child of its parent</li>
609 <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>
610 <li> <b>E:first</b> the first E in the resultset</li>
611 <li> <b>E:last</b> the last E in the resultset</li>
612 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
613 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
614 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
615 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
616 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
617 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
618 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
619 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
620 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
621 <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
623 <h4>CSS Value Selectors:</h4>
625 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
626 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
627 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
628 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
629 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
630 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
636 Ext.core.DomQuery = Ext.DomQuery = function(){
641 trimRe = /^\s+|\s+$/g,
642 tplRe = /\{(\d+)\}/g,
643 modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
644 tagTokenRe = /^(#)?([\w-\*]+)/,
645 nthRe = /(\d*)n\+?(\d*)/,
647 startIdRe = /^\s*\#/,
648 // This is for IE MSXML which does not support expandos.
649 // IE runs the same speed using setAttribute, however FF slows way down
650 // and Safari completely fails so they need to continue to use expandos.
651 isIE = window.ActiveXObject ? true : false,
654 // this eval is stop the compressor from
655 // renaming the variable to something shorter
656 eval("var batch = 30803;");
658 // Retrieve the child node from a particular
659 // parent at the specified index.
660 function child(parent, index){
662 n = parent.firstChild;
674 // retrieve the next element node
676 while((n = n.nextSibling) && n.nodeType != 1);
680 // retrieve the previous element node
682 while((n = n.previousSibling) && n.nodeType != 1);
686 // Mark each child node with a nodeIndex skipping and
687 // removing empty text nodes.
688 function children(parent){
689 var n = parent.firstChild,
693 nextNode = n.nextSibling;
694 // clean worthless empty nodes.
695 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
696 parent.removeChild(n);
698 // add an expando nodeIndex
699 n.nodeIndex = ++nodeIndex;
707 // nodeSet - array of nodes
709 function byClassName(nodeSet, cls){
713 var result = [], ri = -1;
714 for(var i = 0, ci; ci = nodeSet[i]; i++){
715 if((' '+ci.className+' ').indexOf(cls) != -1){
722 function attrValue(n, attr){
723 // if its an array, use the first node.
724 if(!n.tagName && typeof n.length != "undefined"){
734 if(attr == "class" || attr == "className"){
737 return n.getAttribute(attr) || n[attr];
743 // mode - false, /, >, +, ~
744 // tagName - defaults to "*"
745 function getNodes(ns, mode, tagName){
746 var result = [], ri = -1, cs;
750 tagName = tagName || "*";
752 if(typeof ns.getElementsByTagName != "undefined"){
756 // no mode specified, grab all elements by tagName
759 for(var i = 0, ni; ni = ns[i]; i++){
760 cs = ni.getElementsByTagName(tagName);
761 for(var j = 0, ci; ci = cs[j]; j++){
765 // Direct Child mode (/ or >)
766 // E > F or E/F all direct children elements of E that have the tag
767 } else if(mode == "/" || mode == ">"){
768 var utag = tagName.toUpperCase();
769 for(var i = 0, ni, cn; ni = ns[i]; i++){
771 for(var j = 0, cj; cj = cn[j]; j++){
772 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
777 // Immediately Preceding mode (+)
778 // E + F all elements with the tag F that are immediately preceded by an element with the tag E
779 }else if(mode == "+"){
780 var utag = tagName.toUpperCase();
781 for(var i = 0, n; n = ns[i]; i++){
782 while((n = n.nextSibling) && n.nodeType != 1);
783 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
788 // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
789 }else if(mode == "~"){
790 var utag = tagName.toUpperCase();
791 for(var i = 0, n; n = ns[i]; i++){
792 while((n = n.nextSibling)){
793 if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
802 function concat(a, b){
806 for(var i = 0, l = b.length; i < l; i++){
812 function byTag(cs, tagName){
813 if(cs.tagName || cs == document){
819 var result = [], ri = -1;
820 tagName = tagName.toLowerCase();
821 for(var i = 0, ci; ci = cs[i]; i++){
822 if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
829 function byId(cs, id){
830 if(cs.tagName || cs == document){
836 var result = [], ri = -1;
837 for(var i = 0, ci; ci = cs[i]; i++){
838 if(ci && ci.id == id){
846 // operators are =, !=, ^=, $=, *=, %=, |= and ~=
848 function byAttribute(cs, attr, value, op, custom){
851 useGetStyle = custom == "{",
852 fn = Ext.DomQuery.operators[op],
857 for(var i = 0, ci; ci = cs[i]; i++){
858 // skip non-element nodes.
859 if(ci.nodeType != 1){
862 // only need to do this for the first node
864 xml = Ext.DomQuery.isXml(ci);
868 // we only need to change the property names if we're dealing with html nodes, not XML
871 a = Ext.DomQuery.getStyle(ci, attr);
872 } else if (attr == "class" || attr == "className"){
874 } else if (attr == "for"){
876 } else if (attr == "href"){
877 // getAttribute href bug
878 // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
879 a = ci.getAttribute("href", 2);
881 a = ci.getAttribute(attr);
884 a = ci.getAttribute(attr);
886 if((fn && fn(a, value)) || (!fn && a)){
893 function byPseudo(cs, name, value){
894 return Ext.DomQuery.pseudos[name](cs, value);
897 function nodupIEXml(cs){
900 cs[0].setAttribute("_nodup", d);
902 for(var i = 1, len = cs.length; i < len; i++){
904 if(!c.getAttribute("_nodup") != d){
905 c.setAttribute("_nodup", d);
909 for(var i = 0, len = cs.length; i < len; i++){
910 cs[i].removeAttribute("_nodup");
919 var len = cs.length, c, i, r = cs, cj, ri = -1;
920 if(!len || typeof cs.nodeType != "undefined" || len == 1){
923 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
924 return nodupIEXml(cs);
928 for(i = 1; c = cs[i]; i++){
933 for(var j = 0; j < i; j++){
936 for(j = i+1; cj = cs[j]; j++){
948 function quickDiffIEXml(c1, c2){
951 for(var i = 0, len = c1.length; i < len; i++){
952 c1[i].setAttribute("_qdiff", d);
954 for(var i = 0, len = c2.length; i < len; i++){
955 if(c2[i].getAttribute("_qdiff") != d){
959 for(var i = 0, len = c1.length; i < len; i++){
960 c1[i].removeAttribute("_qdiff");
965 function quickDiff(c1, c2){
966 var len1 = c1.length,
972 if(isIE && typeof c1[0].selectSingleNode != "undefined"){
973 return quickDiffIEXml(c1, c2);
975 for(var i = 0; i < len1; i++){
978 for(var i = 0, len = c2.length; i < len; i++){
979 if(c2[i]._qdiff != d){
986 function quickId(ns, mode, root, id){
988 var d = root.ownerDocument || root;
989 return d.getElementById(id);
991 ns = getNodes(ns, mode, "*");
996 getStyle : function(el, name){
997 return Ext.fly(el).getStyle(name);
1000 * Compiles a selector/xpath query into a reusable function. The returned function
1001 * takes one parameter "root" (optional), which is the context node from where the query should start.
1002 * @param {String} selector The selector/xpath query
1003 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
1004 * @return {Function}
1006 compile : function(path, type){
1007 type = type || "select";
1009 // setup fn preamble
1010 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
1013 matchers = Ext.DomQuery.matchers,
1014 matchersLn = matchers.length,
1016 // accept leading mode switch
1017 lmode = path.match(modeRe);
1019 if(lmode && lmode[1]){
1020 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
1021 path = path.replace(lmode[1], "");
1024 // strip leading slashes
1025 while(path.substr(0, 1)=="/"){
1026 path = path.substr(1);
1029 while(path && lastPath != path){
1031 var tokenMatch = path.match(tagTokenRe);
1032 if(type == "select"){
1035 if(tokenMatch[1] == "#"){
1036 fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';
1038 fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
1040 path = path.replace(tokenMatch[0], "");
1041 }else if(path.substr(0, 1) != '@'){
1042 fn[fn.length] = 'n = getNodes(n, mode, "*");';
1047 if(tokenMatch[1] == "#"){
1048 fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
1050 fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
1052 path = path.replace(tokenMatch[0], "");
1055 while(!(modeMatch = path.match(modeRe))){
1056 var matched = false;
1057 for(var j = 0; j < matchersLn; j++){
1058 var t = matchers[j];
1059 var m = path.match(t.re);
1061 fn[fn.length] = t.select.replace(tplRe, function(x, i){
1064 path = path.replace(m[0], "");
1069 // prevent infinite loop on bad selector
1073 sourceClass: 'Ext.DomQuery',
1074 sourceMethod: 'compile',
1075 msg: 'Error parsing selector. Parsing failed at "' + path + '"'
1081 fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
1082 path = path.replace(modeMatch[1], "");
1086 fn[fn.length] = "return nodup(n);\n}";
1088 // eval fn and return it
1094 * Selects an array of DOM nodes using JavaScript-only implementation.
1096 * Use {@link #select} to take advantage of browsers built-in support for CSS selectors.
1098 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
1099 * @param {HTMLElement/String} root (optional) The start of the query (defaults to document).
1100 * @return {HTMLElement[]} An Array of DOM elements which match the selector. If there are
1101 * no matches, and empty Array is returned.
1103 jsSelect: function(path, root, type){
1104 // set root to doc if not specified.
1105 root = root || document;
1107 if(typeof root == "string"){
1108 root = document.getElementById(root);
1110 var paths = path.split(","),
1113 // loop over each selector
1114 for(var i = 0, len = paths.length; i < len; i++){
1115 var subPath = paths[i].replace(trimRe, "");
1116 // compile and place in cache
1117 if(!cache[subPath]){
1118 cache[subPath] = Ext.DomQuery.compile(subPath);
1119 if(!cache[subPath]){
1122 sourceClass: 'Ext.DomQuery',
1123 sourceMethod: 'jsSelect',
1124 msg: subPath + ' is not a valid selector'
1129 var result = cache[subPath](root);
1130 if(result && result != document){
1131 results = results.concat(result);
1135 // if there were multiple selectors, make sure dups
1137 if(paths.length > 1){
1138 return nodup(results);
1143 isXml: function(el) {
1144 var docEl = (el ? el.ownerDocument || el : 0).documentElement;
1145 return docEl ? docEl.nodeName !== "HTML" : false;
1149 * Selects an array of DOM nodes by CSS/XPath selector.
1151 * Uses [document.querySelectorAll][0] if browser supports that, otherwise falls back to
1152 * {@link Ext.DomQuery#jsSelect} to do the work.
1154 * Aliased as {@link Ext#query}.
1156 * [0]: https://developer.mozilla.org/en/DOM/document.querySelectorAll
1158 * @param {String} path The selector/xpath query
1159 * @param {HTMLElement} root (optional) The start of the query (defaults to document).
1160 * @return {HTMLElement[]} An array of DOM elements (not a NodeList as returned by `querySelectorAll`).
1161 * Empty array when no matches.
1164 select : document.querySelectorAll ? function(path, root, type) {
1165 root = root || document;
1167 * Safari 3.x can't handle uppercase or unicode characters when in quirks mode.
1169 if (!Ext.DomQuery.isXml(root) && !(Ext.isSafari3 && !Ext.isStrict)) {
1172 * This checking here is to "fix" the behaviour of querySelectorAll
1173 * for non root document queries. The way qsa works is intentional,
1174 * however it's definitely not the expected way it should work.
1175 * More info: http://ejohn.org/blog/thoughts-on-queryselectorall/
1177 * We only modify the path for single selectors (ie, no multiples),
1178 * without a full parser it makes it difficult to do this correctly.
1180 var isDocumentRoot = root.nodeType === 9,
1184 if (!isDocumentRoot && path.indexOf(',') === -1 && !startIdRe.test(path)) {
1185 _path = '#' + Ext.id(root) + ' ' + path;
1186 _root = root.parentNode;
1188 return Ext.Array.toArray(_root.querySelectorAll(_path));
1193 return Ext.DomQuery.jsSelect.call(this, path, root, type);
1194 } : function(path, root, type) {
1195 return Ext.DomQuery.jsSelect.call(this, path, root, type);
1199 * Selects a single element.
1200 * @param {String} selector The selector/xpath query
1201 * @param {HTMLElement} root (optional) The start of the query (defaults to document).
1202 * @return {HTMLElement} The DOM element which matched the selector.
1204 selectNode : function(path, root){
1205 return Ext.DomQuery.select(path, root)[0];
1209 * Selects the value of a node, optionally replacing null with the defaultValue.
1210 * @param {String} selector The selector/xpath query
1211 * @param {HTMLElement} root (optional) The start of the query (defaults to document).
1212 * @param {String} defaultValue (optional) When specified, this is return as empty value.
1215 selectValue : function(path, root, defaultValue){
1216 path = path.replace(trimRe, "");
1217 if(!valueCache[path]){
1218 valueCache[path] = Ext.DomQuery.compile(path, "select");
1220 var n = valueCache[path](root), v;
1221 n = n[0] ? n[0] : n;
1223 // overcome a limitation of maximum textnode size
1224 // Rumored to potentially crash IE6 but has not been confirmed.
1225 // http://reference.sitepoint.com/javascript/Node/normalize
1226 // https://developer.mozilla.org/En/DOM/Node.normalize
1227 if (typeof n.normalize == 'function') n.normalize();
1229 v = (n && n.firstChild ? n.firstChild.nodeValue : null);
1230 return ((v === null||v === undefined||v==='') ? defaultValue : v);
1234 * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
1235 * @param {String} selector The selector/xpath query
1236 * @param {HTMLElement} root (optional) The start of the query (defaults to document).
1237 * @param {Number} defaultValue (optional) When specified, this is return as empty value.
1240 selectNumber : function(path, root, defaultValue){
1241 var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
1242 return parseFloat(v);
1246 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
1247 * @param {String/HTMLElement/HTMLElement[]} el An element id, element or array of elements
1248 * @param {String} selector The simple selector to test
1251 is : function(el, ss){
1252 if(typeof el == "string"){
1253 el = document.getElementById(el);
1255 var isArray = Ext.isArray(el),
1256 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
1257 return isArray ? (result.length == el.length) : (result.length > 0);
1261 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
1262 * @param {HTMLElement[]} el An array of elements to filter
1263 * @param {String} selector The simple selector to test
1264 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
1265 * the selector instead of the ones that match
1266 * @return {HTMLElement[]} An Array of DOM elements which match the selector. If there are
1267 * no matches, and empty Array is returned.
1269 filter : function(els, ss, nonMatches){
1270 ss = ss.replace(trimRe, "");
1271 if(!simpleCache[ss]){
1272 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
1274 var result = simpleCache[ss](els);
1275 return nonMatches ? quickDiff(result, els) : result;
1279 * Collection of matching regular expressions and code snippets.
1280 * Each capture group within () will be replace the {} in the select
1281 * statement as specified by their index.
1285 select: 'n = byClassName(n, " {1} ");'
1287 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
1288 select: 'n = byPseudo(n, "{1}", "{2}");'
1290 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
1291 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
1294 select: 'n = byId(n, "{1}");'
1297 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
1302 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
1303 * 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, > <.
1306 "=" : function(a, v){
1309 "!=" : function(a, v){
1312 "^=" : function(a, v){
1313 return a && a.substr(0, v.length) == v;
1315 "$=" : function(a, v){
1316 return a && a.substr(a.length-v.length) == v;
1318 "*=" : function(a, v){
1319 return a && a.indexOf(v) !== -1;
1321 "%=" : function(a, v){
1322 return (a % v) == 0;
1324 "|=" : function(a, v){
1325 return a && (a == v || a.substr(0, v.length+1) == v+'-');
1327 "~=" : function(a, v){
1328 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
1333 Object hash of "pseudo class" filter functions which are used when filtering selections.
1334 Each function is passed two parameters:
1337 An Array of DOM elements to filter.
1340 The argument (if any) supplied in the selector.
1342 A filter function returns an Array of DOM elements which conform to the pseudo class.
1343 In addition to the provided pseudo classes listed above such as `first-child` and `nth-child`,
1344 developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.
1346 For example, to filter `a` elements to only return links to __external__ resources:
1348 Ext.DomQuery.pseudos.external = function(c, v){
1349 var r = [], ri = -1;
1350 for(var i = 0, ci; ci = c[i]; i++){
1351 // Include in result set only if it's a link to an external resource
1352 if(ci.hostname != location.hostname){
1359 Then external links could be gathered with the following statement:
1361 var externalLinks = Ext.select("a:external");
1366 "first-child" : function(c){
1367 var r = [], ri = -1, n;
1368 for(var i = 0, ci; ci = n = c[i]; i++){
1369 while((n = n.previousSibling) && n.nodeType != 1);
1377 "last-child" : function(c){
1378 var r = [], ri = -1, n;
1379 for(var i = 0, ci; ci = n = c[i]; i++){
1380 while((n = n.nextSibling) && n.nodeType != 1);
1388 "nth-child" : function(c, a) {
1389 var r = [], ri = -1,
1390 m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
1391 f = (m[1] || 1) - 0, l = m[2] - 0;
1392 for(var i = 0, n; n = c[i]; i++){
1393 var pn = n.parentNode;
1394 if (batch != pn._batch) {
1396 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
1397 if(cn.nodeType == 1){
1404 if (l == 0 || n.nodeIndex == l){
1407 } else if ((n.nodeIndex + l) % f == 0){
1415 "only-child" : function(c){
1416 var r = [], ri = -1;;
1417 for(var i = 0, ci; ci = c[i]; i++){
1418 if(!prev(ci) && !next(ci)){
1425 "empty" : function(c){
1426 var r = [], ri = -1;
1427 for(var i = 0, ci; ci = c[i]; i++){
1428 var cns = ci.childNodes, j = 0, cn, empty = true;
1431 if(cn.nodeType == 1 || cn.nodeType == 3){
1443 "contains" : function(c, v){
1444 var r = [], ri = -1;
1445 for(var i = 0, ci; ci = c[i]; i++){
1446 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
1453 "nodeValue" : function(c, v){
1454 var r = [], ri = -1;
1455 for(var i = 0, ci; ci = c[i]; i++){
1456 if(ci.firstChild && ci.firstChild.nodeValue == v){
1463 "checked" : function(c){
1464 var r = [], ri = -1;
1465 for(var i = 0, ci; ci = c[i]; i++){
1466 if(ci.checked == true){
1473 "not" : function(c, ss){
1474 return Ext.DomQuery.filter(c, ss, true);
1477 "any" : function(c, selectors){
1478 var ss = selectors.split('|'),
1480 for(var i = 0, ci; ci = c[i]; i++){
1481 for(var j = 0; s = ss[j]; j++){
1482 if(Ext.DomQuery.is(ci, s)){
1491 "odd" : function(c){
1492 return this["nth-child"](c, "odd");
1495 "even" : function(c){
1496 return this["nth-child"](c, "even");
1499 "nth" : function(c, a){
1500 return c[a-1] || [];
1503 "first" : function(c){
1507 "last" : function(c){
1508 return c[c.length-1] || [];
1511 "has" : function(c, ss){
1512 var s = Ext.DomQuery.select,
1514 for(var i = 0, ci; ci = c[i]; i++){
1515 if(s(ss, ci).length > 0){
1522 "next" : function(c, ss){
1523 var is = Ext.DomQuery.is,
1525 for(var i = 0, ci; ci = c[i]; i++){
1534 "prev" : function(c, ss){
1535 var is = Ext.DomQuery.is,
1537 for(var i = 0, ci; ci = c[i]; i++){
1550 * Shorthand of {@link Ext.DomQuery#select}
1553 * @alias Ext.DomQuery#select
1555 Ext.query = Ext.DomQuery.select;
1558 * @class Ext.Element
1559 * @alternateClassName Ext.core.Element
1561 * Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.
1563 * All instances of this class inherit the methods of {@link Ext.fx.Anim} making visual effects easily available to all
1566 * Note that the events documented in this class are not Ext events, they encapsulate browser events. Some older browsers
1567 * may not support the full range of events. Which events are supported is beyond the control of Ext JS.
1572 * var el = Ext.get("my-div");
1574 * // by DOM element reference
1575 * var el = Ext.get(myDivElement);
1579 * When an element is manipulated, by default there is no animation.
1581 * var el = Ext.get("my-div");
1586 * Many of the functions for manipulating an element have an optional "animate" parameter. This parameter can be
1587 * specified as boolean (true) for default animation effects.
1589 * // default animation
1590 * el.setWidth(100, true);
1592 * To configure the effects, an object literal with animation options to use as the Element animation configuration
1593 * object can also be specified. Note that the supported Element animation configuration options are a subset of the
1594 * {@link Ext.fx.Anim} animation options specific to Fx effects. The supported Element animation configuration options
1597 * Option Default Description
1598 * --------- -------- ---------------------------------------------
1599 * {@link Ext.fx.Anim#duration duration} .35 The duration of the animation in seconds
1600 * {@link Ext.fx.Anim#easing easing} easeOut The easing method
1601 * {@link Ext.fx.Anim#callback callback} none A function to execute when the anim completes
1602 * {@link Ext.fx.Anim#scope scope} this The scope (this) of the callback function
1606 * // Element animation options object
1608 * {@link Ext.fx.Anim#duration duration}: 1,
1609 * {@link Ext.fx.Anim#easing easing}: 'elasticIn',
1610 * {@link Ext.fx.Anim#callback callback}: this.foo,
1611 * {@link Ext.fx.Anim#scope scope}: this
1613 * // animation with some options set
1614 * el.setWidth(100, opt);
1616 * The Element animation object being used for the animation will be set on the options object as "anim", which allows
1617 * you to stop or manipulate the animation. Here is an example:
1619 * // using the "anim" property to get the Anim object
1620 * if(opt.anim.isAnimated()){
1624 * # Composite (Collections of) Elements
1626 * For working with collections of Elements, see {@link Ext.CompositeElement}
1629 * Creates new Element directly.
1630 * @param {String/HTMLElement} element
1631 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this
1632 * element in the cache and if there is it returns the same instance. This will skip that check (useful for extending
1640 Ext.Element = Ext.core.Element = function(element, forceNew) {
1641 var dom = typeof element == "string" ? DOC.getElementById(element) : element,
1650 if (!forceNew && id && EC[id]) {
1651 // element object already exists
1656 * @property {HTMLElement} dom
1662 * @property {String} id
1663 * The DOM element ID
1665 this.id = id || Ext.id(dom);
1668 var DH = Ext.DomHelper,
1674 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
1675 * @param {Object} o The object with the attributes
1676 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
1677 * @return {Ext.Element} this
1679 set: function(o, useSet) {
1683 useSet = (useSet !== false) && !!el.setAttribute;
1686 if (o.hasOwnProperty(attr)) {
1688 if (attr == 'style') {
1689 DH.applyStyles(el, val);
1690 } else if (attr == 'cls') {
1692 } else if (useSet) {
1693 el.setAttribute(attr, val);
1705 * Fires when a mouse click is detected within the element.
1706 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1707 * @param {HTMLElement} t The target of the event.
1710 * @event contextmenu
1711 * Fires when a right click is detected within the element.
1712 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1713 * @param {HTMLElement} t The target of the event.
1717 * Fires when a mouse double click is detected within the element.
1718 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1719 * @param {HTMLElement} t The target of the event.
1723 * Fires when a mousedown is detected within the element.
1724 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1725 * @param {HTMLElement} t The target of the event.
1729 * Fires when a mouseup is detected within the element.
1730 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1731 * @param {HTMLElement} t The target of the event.
1735 * Fires when a mouseover is detected within the element.
1736 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1737 * @param {HTMLElement} t The target of the event.
1741 * Fires when a mousemove is detected with the element.
1742 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1743 * @param {HTMLElement} t The target of the event.
1747 * Fires when a mouseout is detected with the element.
1748 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1749 * @param {HTMLElement} t The target of the event.
1753 * Fires when the mouse enters the element.
1754 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1755 * @param {HTMLElement} t The target of the event.
1759 * Fires when the mouse leaves the element.
1760 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1761 * @param {HTMLElement} t The target of the event.
1767 * Fires when a keypress is detected within the element.
1768 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1769 * @param {HTMLElement} t The target of the event.
1773 * Fires when a keydown is detected within the element.
1774 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1775 * @param {HTMLElement} t The target of the event.
1779 * Fires when a keyup is detected within the element.
1780 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1781 * @param {HTMLElement} t The target of the event.
1785 // HTML frame/object events
1788 * Fires when the user agent finishes loading all content within the element. Only supported by window, frames,
1789 * objects and images.
1790 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1791 * @param {HTMLElement} t The target of the event.
1795 * Fires when the user agent removes all content from a window or frame. For elements, it fires when the target
1796 * element or any of its content has been removed.
1797 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1798 * @param {HTMLElement} t The target of the event.
1802 * Fires when an object/image is stopped from loading before completely loaded.
1803 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1804 * @param {HTMLElement} t The target of the event.
1808 * Fires when an object/image/frame cannot be loaded properly.
1809 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1810 * @param {HTMLElement} t The target of the event.
1814 * Fires when a document view is resized.
1815 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1816 * @param {HTMLElement} t The target of the event.
1820 * Fires when a document view is scrolled.
1821 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1822 * @param {HTMLElement} t The target of the event.
1828 * Fires when a user selects some text in a text field, including input and textarea.
1829 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1830 * @param {HTMLElement} t The target of the event.
1834 * Fires when a control loses the input focus and its value has been modified since gaining focus.
1835 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1836 * @param {HTMLElement} t The target of the event.
1840 * Fires when a form is submitted.
1841 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1842 * @param {HTMLElement} t The target of the event.
1846 * Fires when a form is reset.
1847 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1848 * @param {HTMLElement} t The target of the event.
1852 * Fires when an element receives focus either via the pointing device or by tab navigation.
1853 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1854 * @param {HTMLElement} t The target of the event.
1858 * Fires when an element loses focus either via the pointing device or by tabbing navigation.
1859 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1860 * @param {HTMLElement} t The target of the event.
1863 // User Interface events
1866 * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
1867 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1868 * @param {HTMLElement} t The target of the event.
1871 * @event DOMFocusOut
1872 * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
1873 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1874 * @param {HTMLElement} t The target of the event.
1877 * @event DOMActivate
1878 * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
1879 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1880 * @param {HTMLElement} t The target of the event.
1883 // DOM Mutation events
1885 * @event DOMSubtreeModified
1886 * Where supported. Fires when the subtree is modified.
1887 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1888 * @param {HTMLElement} t The target of the event.
1891 * @event DOMNodeInserted
1892 * Where supported. Fires when a node has been added as a child of another node.
1893 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1894 * @param {HTMLElement} t The target of the event.
1897 * @event DOMNodeRemoved
1898 * Where supported. Fires when a descendant node of the element is removed.
1899 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1900 * @param {HTMLElement} t The target of the event.
1903 * @event DOMNodeRemovedFromDocument
1904 * Where supported. Fires when a node is being removed from a document.
1905 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1906 * @param {HTMLElement} t The target of the event.
1909 * @event DOMNodeInsertedIntoDocument
1910 * Where supported. Fires when a node is being inserted into a document.
1911 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1912 * @param {HTMLElement} t The target of the event.
1915 * @event DOMAttrModified
1916 * Where supported. Fires when an attribute has been modified.
1917 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1918 * @param {HTMLElement} t The target of the event.
1921 * @event DOMCharacterDataModified
1922 * Where supported. Fires when the character data has been modified.
1923 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
1924 * @param {HTMLElement} t The target of the event.
1928 * @property {String} defaultUnit
1929 * The default unit to append to CSS values where a unit isn't provided.
1934 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
1935 * @param {String} selector The simple selector to test
1936 * @return {Boolean} True if this element matches the selector, else false
1938 is: function(simpleSelector) {
1939 return Ext.DomQuery.is(this.dom, simpleSelector);
1943 * Tries to focus the element. Any exceptions are caught and ignored.
1944 * @param {Number} defer (optional) Milliseconds to defer the focus
1945 * @return {Ext.Element} this
1947 focus: function(defer,
1951 dom = dom || me.dom;
1953 if (Number(defer)) {
1954 Ext.defer(me.focus, defer, null, [null, dom]);
1963 * Tries to blur the element. Any exceptions are caught and ignored.
1964 * @return {Ext.Element} this
1974 * Returns the value of the "value" attribute
1975 * @param {Boolean} asNumber true to parse the value as a number
1976 * @return {String/Number}
1978 getValue: function(asNumber) {
1979 var val = this.dom.value;
1980 return asNumber ? parseInt(val, 10) : val;
1984 * Appends an event handler to this element.
1986 * @param {String} eventName The name of event to handle.
1988 * @param {Function} fn The handler function the event invokes. This function is passed the following parameters:
1990 * - **evt** : EventObject
1992 * The {@link Ext.EventObject EventObject} describing the event.
1994 * - **el** : HtmlElement
1996 * The DOM element which was the target of the event. Note that this may be filtered by using the delegate option.
2000 * The options object from the addListener call.
2002 * @param {Object} scope (optional) The scope (**this** reference) in which the handler function is executed. **If
2003 * omitted, defaults to this Element.**
2005 * @param {Object} options (optional) An object containing handler configuration properties. This may contain any of
2006 * the following properties:
2008 * - **scope** Object :
2010 * The scope (**this** reference) in which the handler function is executed. **If omitted, defaults to this
2013 * - **delegate** String:
2015 * A simple selector to filter the target or look for a descendant of the target. See below for additional details.
2017 * - **stopEvent** Boolean:
2019 * True to stop the event. That is stop propagation, and prevent the default action.
2021 * - **preventDefault** Boolean:
2023 * True to prevent the default action
2025 * - **stopPropagation** Boolean:
2027 * True to prevent event propagation
2029 * - **normalized** Boolean:
2031 * False to pass a browser event to the handler function instead of an Ext.EventObject
2033 * - **target** Ext.Element:
2035 * Only call the handler if the event was fired on the target Element, _not_ if the event was bubbled up from a
2038 * - **delay** Number:
2040 * The number of milliseconds to delay the invocation of the handler after the event fires.
2042 * - **single** Boolean:
2044 * True to add a handler to handle just the next firing of the event, and then remove itself.
2046 * - **buffer** Number:
2048 * Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed by the specified number of
2049 * milliseconds. If the event fires again within that time, the original handler is _not_ invoked, but the new
2050 * handler is scheduled in its place.
2052 * **Combining Options**
2054 * In the following examples, the shorthand form {@link #on} is used rather than the more verbose addListener. The
2055 * two are equivalent. Using the options argument, it is possible to combine different types of listeners:
2057 * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the options
2058 * object. The options object is available as the third parameter in the handler function.
2062 * el.on('click', this.onClick, this, {
2069 * **Attaching multiple handlers in 1 call**
2071 * The method also allows for a single argument to be passed which is a config object containing properties which
2072 * specify multiple handlers.
2083 * fn: this.onMouseOver,
2087 * fn: this.onMouseOut,
2092 * Or a shorthand syntax:
2097 * 'click' : this.onClick,
2098 * 'mouseover' : this.onMouseOver,
2099 * 'mouseout' : this.onMouseOut,
2105 * This is a configuration option that you can pass along when registering a handler for an event to assist with
2106 * event delegation. Event delegation is a technique that is used to reduce memory consumption and prevent exposure
2107 * to memory-leaks. By registering an event for a container element as opposed to each element within a container.
2108 * By setting this configuration option to a simple selector, the target element will be filtered to look for a
2109 * descendant of the target. For example:
2111 * // using this markup:
2113 * <p id='p1'>paragraph one</p>
2114 * <p id='p2' class='clickable'>paragraph two</p>
2115 * <p id='p3'>paragraph three</p>
2118 * // utilize event delegation to registering just one handler on the container element:
2119 * el = Ext.get('elId');
2124 * console.info(t.id); // 'p2'
2128 * // filter the target element to be a descendant with the class 'clickable'
2129 * delegate: '.clickable'
2133 * @return {Ext.Element} this
2135 addListener: function(eventName, fn, scope, options) {
2136 Ext.EventManager.on(this.dom, eventName, fn, scope || this, options);
2141 * Removes an event handler from this element.
2143 * **Note**: if a *scope* was explicitly specified when {@link #addListener adding} the listener,
2144 * the same scope must be specified here.
2148 * el.removeListener('click', this.handlerFn);
2150 * el.un('click', this.handlerFn);
2152 * @param {String} eventName The name of the event from which to remove the handler.
2153 * @param {Function} fn The handler function to remove. **This must be a reference to the function passed into the
2154 * {@link #addListener} call.**
2155 * @param {Object} scope If a scope (**this** reference) was specified when the listener was added, then this must
2156 * refer to the same object.
2157 * @return {Ext.Element} this
2159 removeListener: function(eventName, fn, scope) {
2160 Ext.EventManager.un(this.dom, eventName, fn, scope || this);
2165 * Removes all previous added listeners from this element
2166 * @return {Ext.Element} this
2168 removeAllListeners: function() {
2169 Ext.EventManager.removeAll(this.dom);
2174 * Recursively removes all previous added listeners from this element and its children
2175 * @return {Ext.Element} this
2177 purgeAllListeners: function() {
2178 Ext.EventManager.purgeElement(this);
2183 * Test if size has a unit, otherwise appends the passed unit string, or the default for this Element.
2184 * @param size {Mixed} The size to set
2185 * @param units {String} The units to append to a numeric size value
2188 addUnits: function(size, units) {
2190 // Most common case first: Size is set to a number
2191 if (Ext.isNumber(size)) {
2192 return size + (units || this.defaultUnit || 'px');
2195 // Size set to a value which means "auto"
2196 if (size === "" || size == "auto" || size == null) {
2200 // Otherwise, warn if it's not a valid CSS measurement
2201 if (!unitPattern.test(size)) {
2203 if (Ext.isDefined(Ext.global.console)) {
2204 Ext.global.console.warn("Warning, size detected as NaN on Element.addUnits.");
2213 * Tests various css rules/browsers to determine if this element uses a border box
2216 isBorderBox: function() {
2217 return Ext.isBorderBox || noBoxAdjust[(this.dom.tagName || "").toLowerCase()];
2221 * Removes this element's dom reference. Note that event and cache removal is handled at {@link Ext#removeNode
2224 remove: function() {
2230 Ext.removeNode(dom);
2235 * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
2236 * @param {Function} overFn The function to call when the mouse enters the Element.
2237 * @param {Function} outFn The function to call when the mouse leaves the Element.
2238 * @param {Object} scope (optional) The scope (`this` reference) in which the functions are executed. Defaults
2239 * to the Element's DOM element.
2240 * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the
2241 * options parameter}.
2242 * @return {Ext.Element} this
2244 hover: function(overFn, outFn, scope, options) {
2246 me.on('mouseenter', overFn, scope || me.dom, options);
2247 me.on('mouseleave', outFn, scope || me.dom, options);
2252 * Returns true if this element is an ancestor of the passed element
2253 * @param {HTMLElement/String} el The element to check
2254 * @return {Boolean} True if this element is an ancestor of el, else false
2256 contains: function(el) {
2257 return ! el ? false: Ext.Element.isAncestor(this.dom, el.dom ? el.dom: el);
2261 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2262 * @param {String} namespace The namespace in which to look for the attribute
2263 * @param {String} name The attribute name
2264 * @return {String} The attribute value
2266 getAttributeNS: function(ns, name) {
2267 return this.getAttribute(name, ns);
2271 * Returns the value of an attribute from the element's underlying DOM node.
2272 * @param {String} name The attribute name
2273 * @param {String} namespace (optional) The namespace in which to look for the attribute
2274 * @return {String} The attribute value
2277 getAttribute: (Ext.isIE && !(Ext.isIE9 && document.documentMode === 9)) ?
2278 function(name, ns) {
2282 type = typeof d[ns + ":" + name];
2283 if (type != 'undefined' && type != 'unknown') {
2284 return d[ns + ":" + name] || null;
2288 if (name === "for") {
2291 return d[name] || null;
2292 }: function(name, ns) {
2295 return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name);
2297 return d.getAttribute(name) || d[name] || null;
2301 * Update the innerHTML of this element
2302 * @param {String} html The new HTML
2303 * @return {Ext.Element} this
2305 update: function(html) {
2307 this.dom.innerHTML = html;
2313 var ep = El.prototype;
2315 El.addMethods = function(o) {
2321 * @alias Ext.Element#addListener
2322 * Shorthand for {@link #addListener}.
2324 ep.on = ep.addListener;
2328 * @alias Ext.Element#removeListener
2329 * Shorthand for {@link #removeListener}.
2331 ep.un = ep.removeListener;
2335 * @alias Ext.Element#removeAllListeners
2336 * Alias for {@link #removeAllListeners}.
2338 ep.clearListeners = ep.removeAllListeners;
2342 * @member Ext.Element
2343 * Removes this element's dom reference. Note that event and cache removal is handled at {@link Ext#removeNode
2344 * Ext.removeNode}. Alias to {@link #remove}.
2346 ep.destroy = ep.remove;
2349 * @property {Boolean} autoBoxAdjust
2350 * true to automatically adjust width and height settings for box-model issues (default to true)
2352 ep.autoBoxAdjust = true;
2355 var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
2359 * Retrieves Ext.Element objects. {@link Ext#get} is an alias for {@link Ext.Element#get}.
2361 * **This method does not retrieve {@link Ext.Component Component}s.** This method retrieves Ext.Element
2362 * objects which encapsulate DOM elements. To retrieve a Component by its ID, use {@link Ext.ComponentManager#get}.
2364 * Uses simple caching to consistently return the same object. Automatically fixes if an object was recreated with
2365 * the same id via AJAX or DOM.
2367 * @param {String/HTMLElement/Ext.Element} el The id of the node, a DOM Node or an existing Element.
2368 * @return {Ext.Element} The Element object (or null if no matching element was found)
2371 El.get = function(el) {
2378 if (typeof el == "string") {
2380 if (! (elm = DOC.getElementById(el))) {
2383 if (EC[el] && EC[el].el) {
2387 ex = El.addToCache(new El(elm));
2390 } else if (el.tagName) {
2392 if (! (id = el.id)) {
2395 if (EC[id] && EC[id].el) {
2399 ex = El.addToCache(new El(el));
2402 } else if (el instanceof El) {
2404 // refresh dom element in case no longer valid,
2405 // catch case where it hasn't been appended
2406 // If an el instance is passed, don't pass to getElementById without some kind of id
2407 if (Ext.isIE && (el.id == undefined || el.id == '')) {
2410 el.dom = DOC.getElementById(el.id) || el.dom;
2414 } else if (el.isComposite) {
2416 } else if (Ext.isArray(el)) {
2417 return El.select(el);
2418 } else if (el == DOC) {
2419 // create a bogus element object representing the document object
2421 var f = function() {};
2422 f.prototype = El.prototype;
2432 * Retrieves Ext.Element objects like {@link Ext#get} but is optimized for sub-elements.
2433 * This is helpful for performance, because in IE (prior to IE 9), `getElementById` uses
2434 * an non-optimized search. In those browsers, starting the search for an element with a
2435 * matching ID at a parent of that element will greatly speed up the process.
2437 * Unlike {@link Ext#get}, this method only accepts ID's. If the ID is not a child of
2438 * this element, it will still be found if it exists in the document, but will be slower
2439 * than calling {@link Ext#get} directly.
2441 * @param {String} id The id of the element to get.
2442 * @return {Ext.Element} The Element object (or null if no matching element was found)
2443 * @member Ext.Element
2447 ep.getById = (!Ext.isIE6 && !Ext.isIE7 && !Ext.isIE8) ? El.get :
2455 // calling El.get here is a real hit (2x slower) because it has to
2456 // redetermine that we are giving it a dom el.
2458 if (cached && cached.el) {
2462 ret = El.addToCache(new El(el));
2471 El.addToCache = function(el, id) {
2483 // private method for getting and setting element data
2484 El.data = function(el, key, value) {
2489 var c = EC[el.id].data;
2490 if (arguments.length == 2) {
2493 return (c[key] = value);
2498 // Garbage collection - uncache elements/purge listeners on orphaned elements
2499 // so we don't hold a reference and cause the browser to retain them
2500 function garbageCollect() {
2501 if (!Ext.enableGarbageCollector) {
2502 clearInterval(El.collectorThreadId);
2510 if (!EC.hasOwnProperty(eid)) {
2514 if (o.skipGarbageCollection) {
2519 // -------------------------------------------------------
2520 // Determining what is garbage:
2521 // -------------------------------------------------------
2523 // dom node is null, definitely garbage
2524 // -------------------------------------------------------
2526 // no parentNode == direct orphan, definitely garbage
2527 // -------------------------------------------------------
2528 // !d.offsetParent && !document.getElementById(eid)
2529 // display none elements have no offsetParent so we will
2530 // also try to look it up by it's id. However, check
2531 // offsetParent first so we don't do unneeded lookups.
2532 // This enables collection of elements that are not orphans
2533 // directly, but somewhere up the line they have an orphan
2535 // -------------------------------------------------------
2536 if (!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))) {
2537 if (d && Ext.enableListenerCollection) {
2538 Ext.EventManager.removeAll(d);
2543 // Cleanup IE Object leaks
2547 if (!EC.hasOwnProperty(eid)) {
2556 El.collectorThreadId = setInterval(garbageCollect, 30000);
2558 var flyFn = function() {};
2559 flyFn.prototype = El.prototype;
2562 El.Flyweight = function(dom) {
2566 El.Flyweight.prototype = new flyFn();
2567 El.Flyweight.prototype.isFlyweight = true;
2568 El._flyweights = {};
2571 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference
2572 * to this element - the dom node can be overwritten by other code. {@link Ext#fly} is alias for
2573 * {@link Ext.Element#fly}.
2575 * Use this to make one-time references to DOM elements which are not going to be accessed again either by
2576 * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link
2577 * Ext#get Ext.get} will be more appropriate to take advantage of the caching provided by the Ext.Element
2580 * @param {String/HTMLElement} el The dom node or id
2581 * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts (e.g.
2582 * internally Ext uses "_global")
2583 * @return {Ext.Element} The shared Element object (or null if no matching element was found)
2586 El.fly = function(el, named) {
2588 named = named || '_global';
2589 el = Ext.getDom(el);
2591 (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
2592 ret = El._flyweights[named];
2600 * @alias Ext.Element#get
2607 * @alias Ext.Element#fly
2611 // speedy lookup for elements never to box adjust
2612 var noBoxAdjust = Ext.isStrict ? {
2619 if (Ext.isIE || Ext.isGecko) {
2620 noBoxAdjust['button'] = 1;
2625 * @class Ext.Element
2627 Ext.Element.addMethods({
2629 * 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)
2630 * @param {String} selector The simple selector to test
2631 * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
2632 * The max depth to search as a number or element (defaults to 50 || document.body)
2633 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
2634 * @return {HTMLElement} The matching DOM node (or null if no match was found)
2636 findParent : function(simpleSelector, maxDepth, returnEl) {
2642 maxDepth = maxDepth || 50;
2643 if (isNaN(maxDepth)) {
2644 stopEl = Ext.getDom(maxDepth);
2645 maxDepth = Number.MAX_VALUE;
2647 while (p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl) {
2648 if (Ext.DomQuery.is(p, simpleSelector)) {
2649 return returnEl ? Ext.get(p) : p;
2658 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
2659 * @param {String} selector The simple selector to test
2660 * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
2661 * The max depth to search as a number or element (defaults to 10 || document.body)
2662 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
2663 * @return {HTMLElement} The matching DOM node (or null if no match was found)
2665 findParentNode : function(simpleSelector, maxDepth, returnEl) {
2666 var p = Ext.fly(this.dom.parentNode, '_internal');
2667 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
2671 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
2672 * This is a shortcut for findParentNode() that always returns an Ext.Element.
2673 * @param {String} selector The simple selector to test
2674 * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
2675 * The max depth to search as a number or element (defaults to 10 || document.body)
2676 * @return {Ext.Element} The matching DOM node (or null if no match was found)
2678 up : function(simpleSelector, maxDepth) {
2679 return this.findParentNode(simpleSelector, maxDepth, true);
2683 * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
2684 * @param {String} selector The CSS selector
2685 * @return {Ext.CompositeElement/Ext.CompositeElement} The composite element
2687 select : function(selector) {
2688 return Ext.Element.select(selector, false, this.dom);
2692 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
2693 * @param {String} selector The CSS selector
2694 * @return {HTMLElement[]} An array of the matched nodes
2696 query : function(selector) {
2697 return Ext.DomQuery.select(selector, this.dom);
2701 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
2702 * @param {String} selector The CSS selector
2703 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
2704 * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
2706 down : function(selector, returnDom) {
2707 var n = Ext.DomQuery.selectNode(selector, this.dom);
2708 return returnDom ? n : Ext.get(n);
2712 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
2713 * @param {String} selector The CSS selector
2714 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
2715 * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
2717 child : function(selector, returnDom) {
2721 id = Ext.get(me).id;
2723 id = id.replace(/[\.:]/g, "\\$0");
2724 node = Ext.DomQuery.selectNode('#' + id + " > " + selector, me.dom);
2725 return returnDom ? node : Ext.get(node);
2729 * Gets the parent node for this element, optionally chaining up trying to match a selector
2730 * @param {String} selector (optional) Find a parent node that matches the passed simple selector
2731 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2732 * @return {Ext.Element/HTMLElement} The parent node or null
2734 parent : function(selector, returnDom) {
2735 return this.matchNode('parentNode', 'parentNode', selector, returnDom);
2739 * Gets the next sibling, skipping text nodes
2740 * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
2741 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2742 * @return {Ext.Element/HTMLElement} The next sibling or null
2744 next : function(selector, returnDom) {
2745 return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
2749 * Gets the previous sibling, skipping text nodes
2750 * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
2751 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2752 * @return {Ext.Element/HTMLElement} The previous sibling or null
2754 prev : function(selector, returnDom) {
2755 return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
2760 * Gets the first child, skipping text nodes
2761 * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
2762 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2763 * @return {Ext.Element/HTMLElement} The first child or null
2765 first : function(selector, returnDom) {
2766 return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
2770 * Gets the last child, skipping text nodes
2771 * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
2772 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2773 * @return {Ext.Element/HTMLElement} The last child or null
2775 last : function(selector, returnDom) {
2776 return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
2779 matchNode : function(dir, start, selector, returnDom) {
2784 var n = this.dom[start];
2786 if (n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))) {
2787 return !returnDom ? Ext.get(n) : n;
2796 * @class Ext.Element
2798 Ext.Element.addMethods({
2800 * Appends the passed element(s) to this element
2801 * @param {String/HTMLElement/Ext.Element} el
2802 * The id of the node, a DOM Node or an existing Element.
2803 * @return {Ext.Element} this
2805 appendChild : function(el) {
2806 return Ext.get(el).appendTo(this);
2810 * Appends this element to the passed element
2811 * @param {String/HTMLElement/Ext.Element} el The new parent element.
2812 * The id of the node, a DOM Node or an existing Element.
2813 * @return {Ext.Element} this
2815 appendTo : function(el) {
2816 Ext.getDom(el).appendChild(this.dom);
2821 * Inserts this element before the passed element in the DOM
2822 * @param {String/HTMLElement/Ext.Element} el The element before which this element will be inserted.
2823 * The id of the node, a DOM Node or an existing Element.
2824 * @return {Ext.Element} this
2826 insertBefore : function(el) {
2827 el = Ext.getDom(el);
2828 el.parentNode.insertBefore(this.dom, el);
2833 * Inserts this element after the passed element in the DOM
2834 * @param {String/HTMLElement/Ext.Element} el The element to insert after.
2835 * The id of the node, a DOM Node or an existing Element.
2836 * @return {Ext.Element} this
2838 insertAfter : function(el) {
2839 el = Ext.getDom(el);
2840 el.parentNode.insertBefore(this.dom, el.nextSibling);
2845 * Inserts (or creates) an element (or DomHelper config) as the first child of this element
2846 * @param {String/HTMLElement/Ext.Element/Object} el The id or element to insert or a DomHelper config
2847 * to create and insert
2848 * @return {Ext.Element} The new child
2850 insertFirst : function(el, returnDom) {
2852 if (el.nodeType || el.dom || typeof el == 'string') { // element
2853 el = Ext.getDom(el);
2854 this.dom.insertBefore(el, this.dom.firstChild);
2855 return !returnDom ? Ext.get(el) : el;
2858 return this.createChild(el, this.dom.firstChild, returnDom);
2863 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2864 * @param {String/HTMLElement/Ext.Element/Object/Array} el The id, element to insert or a DomHelper config
2865 * to create and insert *or* an array of any of those.
2866 * @param {String} where (optional) 'before' or 'after' defaults to before
2867 * @param {Boolean} returnDom (optional) True to return the .;ll;l,raw DOM element instead of Ext.Element
2868 * @return {Ext.Element} The inserted Element. If an array is passed, the last inserted element is returned.
2870 insertSibling: function(el, where, returnDom){
2872 isAfter = (where || 'before').toLowerCase() == 'after',
2875 if(Ext.isArray(el)){
2877 Ext.each(el, function(e) {
2878 rt = Ext.fly(insertEl, '_internal').insertSibling(e, where, returnDom);
2888 if(el.nodeType || el.dom){
2889 rt = me.dom.parentNode.insertBefore(Ext.getDom(el), isAfter ? me.dom.nextSibling : me.dom);
2894 if (isAfter && !me.dom.nextSibling) {
2895 rt = Ext.DomHelper.append(me.dom.parentNode, el, !returnDom);
2897 rt = Ext.DomHelper[isAfter ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);
2904 * Replaces the passed element with this element
2905 * @param {String/HTMLElement/Ext.Element} el The element to replace.
2906 * The id of the node, a DOM Node or an existing Element.
2907 * @return {Ext.Element} this
2909 replace : function(el) {
2911 this.insertBefore(el);
2917 * Replaces this element with the passed element
2918 * @param {String/HTMLElement/Ext.Element/Object} el The new element (id of the node, a DOM Node
2919 * or an existing Element) or a DomHelper config of an element to create
2920 * @return {Ext.Element} this
2922 replaceWith: function(el){
2925 if(el.nodeType || el.dom || typeof el == 'string'){
2927 me.dom.parentNode.insertBefore(el, me.dom);
2929 el = Ext.DomHelper.insertBefore(me.dom, el);
2932 delete Ext.cache[me.id];
2933 Ext.removeNode(me.dom);
2934 me.id = Ext.id(me.dom = el);
2935 Ext.Element.addToCache(me.isFlyweight ? new Ext.Element(me.dom) : me);
2940 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2941 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
2942 * automatically generated with the specified attributes.
2943 * @param {HTMLElement} insertBefore (optional) a child element of this element
2944 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2945 * @return {Ext.Element} The new child element
2947 createChild : function(config, insertBefore, returnDom) {
2948 config = config || {tag:'div'};
2950 return Ext.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2953 return Ext.DomHelper[!this.dom.firstChild ? 'insertFirst' : 'append'](this.dom, config, returnDom !== true);
2958 * Creates and wraps this element with another element
2959 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2960 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
2961 * @return {HTMLElement/Ext.Element} The newly created wrapper element
2963 wrap : function(config, returnDom) {
2964 var newEl = Ext.DomHelper.insertBefore(this.dom, config || {tag: "div"}, !returnDom),
2965 d = newEl.dom || newEl;
2967 d.appendChild(this.dom);
2972 * Inserts an html fragment into this element
2973 * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2974 * See {@link Ext.DomHelper#insertHtml} for details.
2975 * @param {String} html The HTML fragment
2976 * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)
2977 * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)
2979 insertHtml : function(where, html, returnEl) {
2980 var el = Ext.DomHelper.insertHtml(where, this.dom, html);
2981 return returnEl ? Ext.get(el) : el;
2986 * @class Ext.Element
2989 // local style camelizing for speed
2990 var ELEMENT = Ext.Element,
2991 supports = Ext.supports,
2992 view = document.defaultView,
2993 opacityRe = /alpha\(opacity=(.*)\)/i,
2994 trimRe = /^\s+|\s+$/g,
2997 adjustDirect2DTableRe = /table-row|table-.*-group/,
2998 INTERNAL = '_internal',
2999 PADDING = 'padding',
3009 ISCLIPPED = 'isClipped',
3010 OVERFLOW = 'overflow',
3011 OVERFLOWX = 'overflow-x',
3012 OVERFLOWY = 'overflow-y',
3013 ORIGINALCLIP = 'originalClip',
3014 // special markup used throughout Ext when box wrapping elements
3015 borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
3016 paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
3017 margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
3018 data = ELEMENT.data;
3020 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>';
3022 // These property values are read from the parentNode if they cannot be read
3024 ELEMENT.inheritedProps = {
3030 Ext.override(ELEMENT, {
3033 * TODO: Look at this
3035 // private ==> used by Fx
3036 adjustWidth : function(width) {
3038 isNum = (typeof width == 'number');
3040 if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
3041 width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
3043 return (isNum && width < 0) ? 0 : width;
3046 // private ==> used by Fx
3047 adjustHeight : function(height) {
3049 isNum = (typeof height == "number");
3051 if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
3052 height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
3054 return (isNum && height < 0) ? 0 : height;
3059 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
3060 * @param {String/String[]} className The CSS classes to add separated by space, or an array of classes
3061 * @return {Ext.Element} this
3063 addCls : function(className){
3066 space = ((me.dom.className.replace(trimRe, '') == '') ? "" : " "),
3068 if (className === undefined) {
3071 // Separate case is for speed
3072 if (Object.prototype.toString.call(className) !== '[object Array]') {
3073 if (typeof className === 'string') {
3074 className = className.replace(trimRe, '').split(spacesRe);
3075 if (className.length === 1) {
3076 className = className[0];
3077 if (!me.hasCls(className)) {
3078 me.dom.className += space + className;
3081 this.addCls(className);
3085 for (i = 0, len = className.length; i < len; i++) {
3087 if (typeof v == 'string' && (' ' + me.dom.className + ' ').indexOf(' ' + v + ' ') == -1) {
3092 me.dom.className += space + cls.join(" ");
3099 * Removes one or more CSS classes from the element.
3100 * @param {String/String[]} className The CSS classes to remove separated by space, or an array of classes
3101 * @return {Ext.Element} this
3103 removeCls : function(className){
3105 i, idx, len, cls, elClasses;
3106 if (className === undefined) {
3109 if (Object.prototype.toString.call(className) !== '[object Array]') {
3110 className = className.replace(trimRe, '').split(spacesRe);
3112 if (me.dom && me.dom.className) {
3113 elClasses = me.dom.className.replace(trimRe, '').split(spacesRe);
3114 for (i = 0, len = className.length; i < len; i++) {
3116 if (typeof cls == 'string') {
3117 cls = cls.replace(trimRe, '');
3118 idx = Ext.Array.indexOf(elClasses, cls);
3120 Ext.Array.erase(elClasses, idx, 1);
3124 me.dom.className = elClasses.join(" ");
3130 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
3131 * @param {String/String[]} className The CSS class to add, or an array of classes
3132 * @return {Ext.Element} this
3134 radioCls : function(className){
3135 var cn = this.dom.parentNode.childNodes,
3137 className = Ext.isArray(className) ? className : [className];
3138 for (i = 0, len = cn.length; i < len; i++) {
3140 if (v && v.nodeType == 1) {
3141 Ext.fly(v, '_internal').removeCls(className);
3144 return this.addCls(className);
3148 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
3149 * @param {String} className The CSS class to toggle
3150 * @return {Ext.Element} this
3153 toggleCls : Ext.supports.ClassList ?
3154 function(className) {
3155 this.dom.classList.toggle(Ext.String.trim(className));
3158 function(className) {
3159 return this.hasCls(className) ? this.removeCls(className) : this.addCls(className);
3163 * Checks if the specified CSS class exists on this element's DOM node.
3164 * @param {String} className The CSS class to check for
3165 * @return {Boolean} True if the class exists, else false
3168 hasCls : Ext.supports.ClassList ?
3169 function(className) {
3173 className = className.split(spacesRe);
3174 var ln = className.length,
3176 for (; i < ln; i++) {
3177 if (className[i] && this.dom.classList.contains(className[i])) {
3183 function(className){
3184 return className && (' ' + this.dom.className + ' ').indexOf(' ' + className + ' ') != -1;
3188 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
3189 * @param {String} oldClassName The CSS class to replace
3190 * @param {String} newClassName The replacement CSS class
3191 * @return {Ext.Element} this
3193 replaceCls : function(oldClassName, newClassName){
3194 return this.removeCls(oldClassName).addCls(newClassName);
3197 isStyle : function(style, val) {
3198 return this.getStyle(style) == val;
3202 * Normalizes currentStyle and computedStyle.
3203 * @param {String} property The style property whose value is returned.
3204 * @return {String} The current value of the style property for this element.
3207 getStyle : function() {
3208 return view && view.getComputedStyle ?
3211 v, cs, out, display, cleaner;
3216 prop = ELEMENT.normalize(prop);
3217 out = (v = el.style[prop]) ? v :
3218 (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
3220 // Ignore cases when the margin is correctly reported as 0, the bug only shows
3222 if(prop == 'marginRight' && out != '0px' && !supports.RightMargin){
3223 cleaner = ELEMENT.getRightMarginFixCleaner(el);
3224 display = this.getStyle('display');
3225 el.style.display = 'inline-block';
3226 out = view.getComputedStyle(el, '').marginRight;
3227 el.style.display = display;
3231 if(prop == 'backgroundColor' && out == 'rgba(0, 0, 0, 0)' && !supports.TransparentColor){
3232 out = 'transparent';
3240 if (el == document) {
3243 prop = ELEMENT.normalize(prop);
3246 if (prop == 'opacity') {
3247 if (el.style.filter.match) {
3248 m = el.style.filter.match(opacityRe);
3250 var fv = parseFloat(m[1]);
3252 return fv ? fv / 100 : 0;
3259 // the try statement does have a cost, so we avoid it unless we are
3262 return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
3266 return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
3268 // in some cases, IE6 will throw Invalid Argument for properties
3269 // like fontSize (see in /examples/tabs/tabs.html).
3272 if (!ELEMENT.inheritedProps[prop]) {
3277 // this is _not_ perfect, but we can only hope that the style we
3278 // need is inherited from a parentNode. If not and since IE won't
3279 // give us the info we need, we are never going to be 100% right.
3285 msg: 'Failed to get ' + this.dom.id + '.currentStyle.' + prop
3293 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
3294 * are convert to standard 6 digit hex color.
3295 * @param {String} attr The css attribute
3296 * @param {String} defaultValue The default value to use when a valid color isn't found
3297 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
3300 getColor : function(attr, defaultValue, prefix){
3301 var v = this.getStyle(attr),
3302 color = prefix || prefix === '' ? prefix : '#',
3305 if(!v || (/transparent|inherit/.test(v))) {
3306 return defaultValue;
3309 Ext.each(v.slice(4, v.length -1).split(','), function(s){
3310 h = parseInt(s, 10);
3311 color += (h < 16 ? '0' : '') + h.toString(16);
3314 v = v.replace('#', '');
3315 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
3317 return(color.length > 5 ? color.toLowerCase() : defaultValue);
3321 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
3322 * @param {String/Object} property The style property to be set, or an object of multiple styles.
3323 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
3324 * @return {Ext.Element} this
3326 setStyle : function(prop, value){
3333 if (typeof prop === 'string') {
3338 for (style in prop) {
3339 if (prop.hasOwnProperty(style)) {
3340 value = Ext.value(prop[style], '');
3341 if (style == 'opacity') {
3342 me.setOpacity(value);
3345 me.dom.style[ELEMENT.normalize(style)] = value;
3353 * Set the opacity of the element
3354 * @param {Number} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
3355 * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
3356 * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
3357 * @return {Ext.Element} this
3359 setOpacity: function(opacity, animate) {
3369 style = me.dom.style;
3371 if (!animate || !me.anim) {
3372 if (!Ext.supports.Opacity) {
3373 opacity = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')': '';
3374 val = style.filter.replace(opacityRe, '').replace(trimRe, '');
3377 style.filter = val + (val.length > 0 ? ' ': '') + opacity;
3380 style.opacity = opacity;
3384 if (!Ext.isObject(animate)) {
3390 me.animate(Ext.applyIf({
3402 * Clears any opacity settings from this element. Required in some cases for IE.
3403 * @return {Ext.Element} this
3405 clearOpacity : function(){
3406 var style = this.dom.style;
3407 if(!Ext.supports.Opacity){
3408 if(!Ext.isEmpty(style.filter)){
3409 style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
3412 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
3419 * Returns 1 if the browser returns the subpixel dimension rounded to the lowest pixel.
3420 * @return {Number} 0 or 1
3422 adjustDirect2DDimension: function(dimension) {
3425 display = me.getStyle('display'),
3426 inlineDisplay = dom.style['display'],
3427 inlinePosition = dom.style['position'],
3428 originIndex = dimension === 'width' ? 0 : 1,
3431 if (display === 'inline') {
3432 dom.style['display'] = 'inline-block';
3435 dom.style['position'] = display.match(adjustDirect2DTableRe) ? 'absolute' : 'static';
3437 // floating will contain digits that appears after the decimal point
3438 // if height or width are set to auto we fallback to msTransformOrigin calculation
3439 floating = (parseFloat(me.getStyle(dimension)) || parseFloat(dom.currentStyle.msTransformOrigin.split(' ')[originIndex]) * 2) % 1;
3441 dom.style['position'] = inlinePosition;
3443 if (display === 'inline') {
3444 dom.style['display'] = inlineDisplay;
3451 * Returns the offset height of the element
3452 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
3453 * @return {Number} The element's height
3455 getHeight: function(contentHeight, preciseHeight) {
3458 hidden = Ext.isIE && me.isStyle('display', 'none'),
3459 height, overflow, style, floating;
3461 // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
3462 // We will put the overflow back to it's original value when we are done measuring.
3463 if (Ext.isIEQuirks) {
3465 overflow = style.overflow;
3466 me.setStyle({ overflow: 'hidden'});
3469 height = dom.offsetHeight;
3471 height = MATH.max(height, hidden ? 0 : dom.clientHeight) || 0;
3473 // IE9 Direct2D dimension rounding bug
3474 if (!hidden && Ext.supports.Direct2DBug) {
3475 floating = me.adjustDirect2DDimension('height');
3476 if (preciseHeight) {
3479 else if (floating > 0 && floating < 0.5) {
3484 if (contentHeight) {
3485 height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
3488 if (Ext.isIEQuirks) {
3489 me.setStyle({ overflow: overflow});
3499 * Returns the offset width of the element
3500 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
3501 * @return {Number} The element's width
3503 getWidth: function(contentWidth, preciseWidth) {
3506 hidden = Ext.isIE && me.isStyle('display', 'none'),
3507 rect, width, overflow, style, floating, parentPosition;
3509 // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
3510 // We will put the overflow back to it's original value when we are done measuring.
3511 if (Ext.isIEQuirks) {
3513 overflow = style.overflow;
3514 me.setStyle({overflow: 'hidden'});
3517 // Fix Opera 10.5x width calculation issues
3518 if (Ext.isOpera10_5) {
3519 if (dom.parentNode.currentStyle.position === 'relative') {
3520 parentPosition = dom.parentNode.style.position;
3521 dom.parentNode.style.position = 'static';
3522 width = dom.offsetWidth;
3523 dom.parentNode.style.position = parentPosition;
3525 width = Math.max(width || 0, dom.offsetWidth);
3527 // Gecko will in some cases report an offsetWidth that is actually less than the width of the
3528 // text contents, because it measures fonts with sub-pixel precision but rounds the calculated
3529 // value down. Using getBoundingClientRect instead of offsetWidth allows us to get the precise
3530 // subpixel measurements so we can force them to always be rounded up. See
3531 // https://bugzilla.mozilla.org/show_bug.cgi?id=458617
3532 } else if (Ext.supports.BoundingClientRect) {
3533 rect = dom.getBoundingClientRect();
3534 width = rect.right - rect.left;
3535 width = preciseWidth ? width : Math.ceil(width);
3537 width = dom.offsetWidth;
3540 width = MATH.max(width, hidden ? 0 : dom.clientWidth) || 0;
3542 // IE9 Direct2D dimension rounding bug
3543 if (!hidden && Ext.supports.Direct2DBug) {
3544 floating = me.adjustDirect2DDimension('width');
3548 else if (floating > 0 && floating < 0.5) {
3554 width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
3557 if (Ext.isIEQuirks) {
3558 me.setStyle({ overflow: overflow});
3568 * Set the width of this Element.
3569 * @param {Number/String} width The new width. This may be one of:<div class="mdetail-params"><ul>
3570 * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
3571 * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
3573 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
3574 * @return {Ext.Element} this
3576 setWidth : function(width, animate){
3578 width = me.adjustWidth(width);
3579 if (!animate || !me.anim) {
3580 me.dom.style.width = me.addUnits(width);
3583 if (!Ext.isObject(animate)) {
3586 me.animate(Ext.applyIf({
3596 * Set the height of this Element.
3598 // change the height to 200px and animate with default configuration
3599 Ext.fly('elementId').setHeight(200, true);
3601 // change the height to 150px and animate with a custom configuration
3602 Ext.fly('elId').setHeight(150, {
3603 duration : .5, // animation will have a duration of .5 seconds
3604 // will change the content to "finished"
3605 callback: function(){ this.{@link #update}("finished"); }
3608 * @param {Number/String} height The new height. This may be one of:<div class="mdetail-params"><ul>
3609 * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
3610 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
3612 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
3613 * @return {Ext.Element} this
3615 setHeight : function(height, animate){
3617 height = me.adjustHeight(height);
3618 if (!animate || !me.anim) {
3619 me.dom.style.height = me.addUnits(height);
3622 if (!Ext.isObject(animate)) {
3625 me.animate(Ext.applyIf({
3635 * Gets the width of the border(s) for the specified side(s)
3636 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
3637 * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
3638 * @return {Number} The width of the sides passed added together
3640 getBorderWidth : function(side){
3641 return this.addStyles(side, borders);
3645 * Gets the width of the padding(s) for the specified side(s)
3646 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
3647 * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
3648 * @return {Number} The padding of the sides passed added together
3650 getPadding : function(side){
3651 return this.addStyles(side, paddings);
3655 * Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
3656 * @return {Ext.Element} this
3662 if(!data(dom, ISCLIPPED)){
3663 data(dom, ISCLIPPED, true);
3664 data(dom, ORIGINALCLIP, {
3665 o: me.getStyle(OVERFLOW),
3666 x: me.getStyle(OVERFLOWX),
3667 y: me.getStyle(OVERFLOWY)
3669 me.setStyle(OVERFLOW, HIDDEN);
3670 me.setStyle(OVERFLOWX, HIDDEN);
3671 me.setStyle(OVERFLOWY, HIDDEN);
3677 * Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
3678 * @return {Ext.Element} this
3680 unclip : function(){
3685 if(data(dom, ISCLIPPED)){
3686 data(dom, ISCLIPPED, false);
3687 clip = data(dom, ORIGINALCLIP);
3689 me.setStyle(OVERFLOW, clip.o);
3692 me.setStyle(OVERFLOWX, clip.x);
3695 me.setStyle(OVERFLOWY, clip.y);
3702 addStyles : function(sides, styles){
3704 sidesArr = sides.match(wordsRe),
3706 len = sidesArr.length,
3708 for (; i < len; i++) {
3710 size = side && parseInt(this.getStyle(styles[side]), 10);
3712 totalSize += MATH.abs(size);
3721 * More flexible version of {@link #setStyle} for setting style properties.
3722 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
3723 * a function which returns such a specification.
3724 * @return {Ext.Element} this
3726 applyStyles : function(style){
3727 Ext.DomHelper.applyStyles(this.dom, style);
3732 * Returns an object with properties matching the styles requested.
3733 * For example, el.getStyles('color', 'font-size', 'width') might return
3734 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
3735 * @param {String} style1 A style name
3736 * @param {String} style2 A style name
3737 * @param {String} etc.
3738 * @return {Object} The style object
3740 getStyles : function(){
3742 len = arguments.length,
3745 for(; i < len; ++i) {
3746 style = arguments[i];
3747 styles[style] = this.getStyle(style);
3753 * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as
3754 * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>
3755 * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.button.Button},
3756 * {@link Ext.panel.Panel} when <tt>{@link Ext.panel.Panel#frame frame=true}</tt>, {@link Ext.window.Window}). The markup
3757 * is of this form:</p>
3759 Ext.Element.boxMarkup =
3760 '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div>
3761 <div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div>
3762 <div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
3764 * <p>Example usage:</p>
3767 Ext.get("foo").boxWrap();
3769 // You can also add a custom class and use CSS inheritance rules to customize the box look.
3770 // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
3771 // for how to create a custom box wrap style.
3772 Ext.get("foo").boxWrap().addCls("x-box-blue");
3774 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
3775 * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on
3776 * this name to make the overall effect work, so if you supply an alternate base class, make sure you
3777 * also supply all of the necessary rules.
3778 * @return {Ext.Element} The outermost wrapping element of the created box structure.
3780 boxWrap : function(cls){
3781 cls = cls || Ext.baseCSSPrefix + 'box';
3782 var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + Ext.String.format(ELEMENT.boxMarkup, cls) + "</div>"));
3783 Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
3788 * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
3789 * @param {Number/String} width The new width. This may be one of:<div class="mdetail-params"><ul>
3790 * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
3791 * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
3792 * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
3794 * @param {Number/String} height The new height. This may be one of:<div class="mdetail-params"><ul>
3795 * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>
3796 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
3798 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
3799 * @return {Ext.Element} this
3801 setSize : function(width, height, animate){
3803 if (Ext.isObject(width)) { // in case of object from getSize()
3805 height = width.height;
3806 width = width.width;
3808 width = me.adjustWidth(width);
3809 height = me.adjustHeight(height);
3810 if(!animate || !me.anim){
3811 // Must touch some property before setting style.width/height on non-quirk IE6,7, or the
3812 // properties will not reflect the changes on the style immediately
3813 if (!Ext.isIEQuirks && (Ext.isIE6 || Ext.isIE7)) {
3816 me.dom.style.width = me.addUnits(width);
3817 me.dom.style.height = me.addUnits(height);
3820 if (animate === true) {
3823 me.animate(Ext.applyIf({
3834 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
3835 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
3836 * if a height has not been set using CSS.
3839 getComputedHeight : function(){
3841 h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
3843 h = parseFloat(me.getStyle('height')) || 0;
3844 if(!me.isBorderBox()){
3845 h += me.getFrameWidth('tb');
3852 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
3853 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
3854 * if a width has not been set using CSS.
3857 getComputedWidth : function(){
3859 w = Math.max(me.dom.offsetWidth, me.dom.clientWidth);
3862 w = parseFloat(me.getStyle('width')) || 0;
3863 if(!me.isBorderBox()){
3864 w += me.getFrameWidth('lr');
3871 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
3872 for more information about the sides.
3873 * @param {String} sides
3876 getFrameWidth : function(sides, onlyContentBox){
3877 return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
3881 * Sets up event handlers to add and remove a css class when the mouse is over this element
3882 * @param {String} className
3883 * @return {Ext.Element} this
3885 addClsOnOver : function(className){
3889 Ext.fly(dom, INTERNAL).addCls(className);
3892 Ext.fly(dom, INTERNAL).removeCls(className);
3899 * Sets up event handlers to add and remove a css class when this element has the focus
3900 * @param {String} className
3901 * @return {Ext.Element} this
3903 addClsOnFocus : function(className){
3906 me.on("focus", function(){
3907 Ext.fly(dom, INTERNAL).addCls(className);
3909 me.on("blur", function(){
3910 Ext.fly(dom, INTERNAL).removeCls(className);
3916 * 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)
3917 * @param {String} className
3918 * @return {Ext.Element} this
3920 addClsOnClick : function(className){
3922 this.on("mousedown", function(){
3923 Ext.fly(dom, INTERNAL).addCls(className);
3924 var d = Ext.getDoc(),
3926 Ext.fly(dom, INTERNAL).removeCls(className);
3927 d.removeListener("mouseup", fn);
3929 d.on("mouseup", fn);
3935 * <p>Returns the dimensions of the element available to lay content out in.<p>
3936 * <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
3937 * example:<pre><code>
3938 var vpSize = Ext.getBody().getViewSize();
3940 // all Windows created afterwards will have a default value of 90% height and 95% width
3941 Ext.Window.override({
3942 width: vpSize.width * 0.9,
3943 height: vpSize.height * 0.95
3945 // To handle window resizing you would have to hook onto onWindowResize.
3948 * getViewSize utilizes clientHeight/clientWidth which excludes sizing of scrollbars.
3949 * To obtain the size including scrollbars, use getStyleSize
3951 * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
3954 getViewSize : function(){
3957 isDoc = (dom == Ext.getDoc().dom || dom == Ext.getBody().dom),
3958 style, overflow, ret;
3960 // If the body, use static methods
3963 width : ELEMENT.getViewWidth(),
3964 height : ELEMENT.getViewHeight()
3967 // Else use clientHeight/clientWidth
3970 // IE 6 & IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
3971 // We will put the overflow back to it's original value when we are done measuring.
3972 if (Ext.isIE6 || Ext.isIEQuirks) {
3974 overflow = style.overflow;
3975 me.setStyle({ overflow: 'hidden'});
3978 width : dom.clientWidth,
3979 height : dom.clientHeight
3981 if (Ext.isIE6 || Ext.isIEQuirks) {
3982 me.setStyle({ overflow: overflow });
3989 * <p>Returns the dimensions of the element available to lay content out in.<p>
3991 * getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and offsetWidth/clientWidth.
3992 * To obtain the size excluding scrollbars, use getViewSize
3994 * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
3997 getStyleSize : function(){
4001 isDoc = (d == doc || d == doc.body),
4005 // If the body, use static methods
4008 width : ELEMENT.getViewWidth(),
4009 height : ELEMENT.getViewHeight()
4012 // Use Styles if they are set
4013 if(s.width && s.width != 'auto'){
4014 w = parseFloat(s.width);
4015 if(me.isBorderBox()){
4016 w -= me.getFrameWidth('lr');
4019 // Use Styles if they are set
4020 if(s.height && s.height != 'auto'){
4021 h = parseFloat(s.height);
4022 if(me.isBorderBox()){
4023 h -= me.getFrameWidth('tb');
4026 // Use getWidth/getHeight if style not set.
4027 return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
4031 * Returns the size of the element.
4032 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
4033 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
4035 getSize : function(contentSize){
4036 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
4040 * Forces the browser to repaint this element
4041 * @return {Ext.Element} this
4043 repaint : function(){
4045 this.addCls(Ext.baseCSSPrefix + 'repaint');
4046 setTimeout(function(){
4047 Ext.fly(dom).removeCls(Ext.baseCSSPrefix + 'repaint');
4053 * Enable text selection for this element (normalized across browsers)
4054 * @return {Ext.Element} this
4056 selectable : function() {
4058 me.dom.unselectable = "off";
4059 // Prevent it from bubles up and enables it to be selectable
4060 me.on('selectstart', function (e) {
4061 e.stopPropagation();
4064 me.applyStyles("-moz-user-select: text; -khtml-user-select: text;");
4065 me.removeCls(Ext.baseCSSPrefix + 'unselectable');
4070 * Disables text selection for this element (normalized across browsers)
4071 * @return {Ext.Element} this
4073 unselectable : function(){
4075 me.dom.unselectable = "on";
4077 me.swallowEvent("selectstart", true);
4078 me.applyStyles("-moz-user-select:-moz-none;-khtml-user-select:none;");
4079 me.addCls(Ext.baseCSSPrefix + 'unselectable');
4085 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
4086 * then it returns the calculated width of the sides (see getPadding)
4087 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
4088 * @return {Object/Number}
4090 getMargin : function(side){
4092 hash = {t:"top", l:"left", r:"right", b: "bottom"},
4097 for (key in me.margins){
4098 o[hash[key]] = parseFloat(me.getStyle(me.margins[key])) || 0;
4102 return me.addStyles.call(me, side, me.margins);
4108 * @class Ext.Element
4111 * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
4115 Ext.Element.VISIBILITY = 1;
4117 * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
4121 Ext.Element.DISPLAY = 2;
4124 * Visibility mode constant for use with {@link #setVisibilityMode}. Use offsets (x and y positioning offscreen)
4129 Ext.Element.OFFSETS = 3;
4132 Ext.Element.ASCLASS = 4;
4135 * Defaults to 'x-hide-nosize'
4139 Ext.Element.visibilityCls = Ext.baseCSSPrefix + 'hide-nosize';
4141 Ext.Element.addMethods(function(){
4142 var El = Ext.Element,
4143 OPACITY = "opacity",
4144 VISIBILITY = "visibility",
4145 DISPLAY = "display",
4147 OFFSETS = "offsets",
4148 ASCLASS = "asclass",
4151 ORIGINALDISPLAY = 'originalDisplay',
4152 VISMODE = 'visibilityMode',
4153 ISVISIBLE = 'isVisible',
4155 getDisplay = function(dom){
4156 var d = data(dom, ORIGINALDISPLAY);
4157 if(d === undefined){
4158 data(dom, ORIGINALDISPLAY, d = '');
4162 getVisMode = function(dom){
4163 var m = data(dom, VISMODE);
4164 if(m === undefined){
4165 data(dom, VISMODE, m = 1);
4172 * @property {String} originalDisplay
4173 * The element's default display mode
4175 originalDisplay : "",
4179 * Sets the element's visibility mode. When setVisible() is called it
4180 * will use this to determine whether to set the visibility or the display property.
4181 * @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY
4182 * @return {Ext.Element} this
4184 setVisibilityMode : function(visMode){
4185 data(this.dom, VISMODE, visMode);
4190 * Checks whether the element is currently visible using both visibility and display properties.
4191 * @return {Boolean} True if the element is currently visible, else false
4193 isVisible : function() {
4196 visible = data(dom, ISVISIBLE);
4198 if(typeof visible == 'boolean'){ //return the cached value if registered
4201 //Determine the current state based on display states
4202 visible = !me.isStyle(VISIBILITY, HIDDEN) &&
4203 !me.isStyle(DISPLAY, NONE) &&
4204 !((getVisMode(dom) == El.ASCLASS) && me.hasCls(me.visibilityCls || El.visibilityCls));
4206 data(dom, ISVISIBLE, visible);
4211 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
4212 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
4213 * @param {Boolean} visible Whether the element is visible
4214 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4215 * @return {Ext.Element} this
4217 setVisible : function(visible, animate){
4218 var me = this, isDisplay, isVisibility, isOffsets, isNosize,
4220 visMode = getVisMode(dom);
4223 // hideMode string override
4224 if (typeof animate == 'string'){
4227 visMode = El.DISPLAY;
4230 visMode = El.VISIBILITY;
4233 visMode = El.OFFSETS;
4237 visMode = El.ASCLASS;
4240 me.setVisibilityMode(visMode);
4244 if (!animate || !me.anim) {
4245 if(visMode == El.ASCLASS ){
4247 me[visible?'removeCls':'addCls'](me.visibilityCls || El.visibilityCls);
4249 } else if (visMode == El.DISPLAY){
4251 return me.setDisplayed(visible);
4253 } else if (visMode == El.OFFSETS){
4256 // Remember position for restoring, if we are not already hidden by offsets.
4257 if (!me.hideModeStyles) {
4258 me.hideModeStyles = {
4259 position: me.getStyle('position'),
4260 top: me.getStyle('top'),
4261 left: me.getStyle('left')
4264 me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
4267 // Only "restore" as position if we have actually been hidden using offsets.
4268 // Calling setVisible(true) on a positioned element should not reposition it.
4269 else if (me.hideModeStyles) {
4270 me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
4271 delete me.hideModeStyles;
4276 // Show by clearing visibility style. Explicitly setting to "visible" overrides parent visibility setting.
4277 dom.style.visibility = visible ? '' : HIDDEN;
4280 // closure for composites
4282 me.setOpacity(0.01);
4283 me.setVisible(true);
4285 if (!Ext.isObject(animate)) {
4291 me.animate(Ext.applyIf({
4292 callback: function() {
4293 visible || me.setVisible(false).setOpacity(1);
4296 opacity: (visible) ? 1 : 0
4300 data(dom, ISVISIBLE, visible); //set logical visibility state
4307 * Determine if the Element has a relevant height and width available based
4308 * upon current logical visibility state
4310 hasMetrics : function(){
4312 return this.isVisible() || (getVisMode(dom) == El.OFFSETS) || (getVisMode(dom) == El.VISIBILITY);
4316 * Toggles the element's visibility or display, depending on visibility mode.
4317 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4318 * @return {Ext.Element} this
4320 toggle : function(animate){
4322 me.setVisible(!me.isVisible(), me.anim(animate));
4327 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
4328 * @param {Boolean/String} value Boolean value to display the element using its default display, or a string to set the display directly.
4329 * @return {Ext.Element} this
4331 setDisplayed : function(value) {
4332 if(typeof value == "boolean"){
4333 value = value ? getDisplay(this.dom) : NONE;
4335 this.setStyle(DISPLAY, value);
4340 fixDisplay : function(){
4342 if (me.isStyle(DISPLAY, NONE)) {
4343 me.setStyle(VISIBILITY, HIDDEN);
4344 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
4345 if (me.isStyle(DISPLAY, NONE)) { // if that fails, default to block
4346 me.setStyle(DISPLAY, "block");
4352 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
4353 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
4354 * @return {Ext.Element} this
4356 hide : function(animate){
4357 // hideMode override
4358 if (typeof animate == 'string'){
4359 this.setVisible(false, animate);
4362 this.setVisible(false, this.anim(animate));
4367 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
4368 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
4369 * @return {Ext.Element} this
4371 show : function(animate){
4372 // hideMode override
4373 if (typeof animate == 'string'){
4374 this.setVisible(true, animate);
4377 this.setVisible(true, this.anim(animate));
4383 * @class Ext.Element
4385 Ext.applyIf(Ext.Element.prototype, {
4386 // @private override base Ext.util.Animate mixin for animate for backwards compatibility
4387 animate: function(config) {
4390 me = Ext.get(me.dom);
4392 if (Ext.fx.Manager.hasFxBlock(me.id)) {
4395 Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(config)));
4399 // @private override base Ext.util.Animate mixin for animate for backwards compatibility
4400 anim: function(config) {
4401 if (!Ext.isObject(config)) {
4402 return (config) ? {} : false;
4406 duration = config.duration || Ext.fx.Anim.prototype.duration,
4407 easing = config.easing || 'ease',
4410 if (config.stopAnimation) {
4414 Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));
4416 // Clear any 'paused' defaults.
4417 Ext.fx.Manager.setFxDefaults(me.id, {
4423 remove: config.remove,
4424 alternate: config.alternate || false,
4427 callback: config.callback,
4428 listeners: config.listeners,
4429 iterations: config.iterations || 1,
4430 scope: config.scope,
4431 block: config.block,
4432 concurrent: config.concurrent,
4433 delay: config.delay || 0,
4435 keyframes: config.keyframes,
4436 from: config.from || {},
4437 to: Ext.apply({}, config)
4439 Ext.apply(animConfig.to, config.to);
4441 // Anim API properties - backward compat
4442 delete animConfig.to.to;
4443 delete animConfig.to.from;
4444 delete animConfig.to.remove;
4445 delete animConfig.to.alternate;
4446 delete animConfig.to.keyframes;
4447 delete animConfig.to.iterations;
4448 delete animConfig.to.listeners;
4449 delete animConfig.to.target;
4450 delete animConfig.to.paused;
4451 delete animConfig.to.callback;
4452 delete animConfig.to.scope;
4453 delete animConfig.to.duration;
4454 delete animConfig.to.easing;
4455 delete animConfig.to.concurrent;
4456 delete animConfig.to.block;
4457 delete animConfig.to.stopAnimation;
4458 delete animConfig.to.delay;
4463 * Slides the element into view. An anchor point can be optionally passed to set the point of origin for the slide
4464 * effect. This function automatically handles wrapping the element with a fixed-size container if needed. See the
4465 * Fx class overview for valid anchor point options. Usage:
4467 * // default: slide the element in from the top
4470 * // custom: slide the element in from the right with a 2-second duration
4471 * el.slideIn('r', { duration: 2000 });
4473 * // common config options shown with default values
4475 * easing: 'easeOut',
4479 * @param {String} [anchor='t'] One of the valid Fx anchor positions
4480 * @param {Object} [options] Object literal with any of the Fx config options
4481 * @return {Ext.Element} The Element
4483 slideIn: function(anchor, obj, slideOut) {
4485 elStyle = me.dom.style,
4486 beforeAnim, wrapAnim;
4488 anchor = anchor || "t";
4491 beforeAnim = function() {
4492 var animScope = this,
4493 listeners = obj.listeners,
4494 box, position, restoreSize, wrap, anim;
4501 if ((anchor == 't' || anchor == 'b') && box.height === 0) {
4502 box.height = me.dom.scrollHeight;
4504 else if ((anchor == 'l' || anchor == 'r') && box.width === 0) {
4505 box.width = me.dom.scrollWidth;
4508 position = me.getPositioning();
4509 me.setSize(box.width, box.height);
4513 visibility: slideOut ? 'visible' : 'hidden'
4516 wrap.setPositioning(position);
4517 if (wrap.isStyle('position', 'static')) {
4518 wrap.position('relative');
4520 me.clearPositioning('auto');
4523 // This element is temporarily positioned absolute within its wrapper.
4524 // Restore to its default, CSS-inherited visibility setting.
4525 // We cannot explicitly poke visibility:visible into its style because that overrides the visibility of the wrap.
4528 position: 'absolute'
4531 wrap.setSize(box.width, box.height);
4538 width: box.width + 'px',
4542 width: box.width + 'px',
4543 height: box.height + 'px'
4546 elStyle.bottom = '0px';
4552 height: box.height + 'px'
4555 width: box.width + 'px',
4556 height: box.height + 'px'
4559 elStyle.right = '0px';
4564 x: box.x + box.width,
4566 height: box.height + 'px'
4570 width: box.width + 'px',
4571 height: box.height + 'px'
4578 y: box.y + box.height,
4579 width: box.width + 'px',
4584 width: box.width + 'px',
4585 height: box.height + 'px'
4598 width: box.width + 'px',
4599 height: box.height + 'px'
4602 elStyle.bottom = '0px';
4603 elStyle.right = '0px';
4608 x: box.x + box.width,
4614 width: box.width + 'px',
4615 height: box.height + 'px'
4618 elStyle.right = '0px';
4623 x: box.x + box.width,
4624 y: box.y + box.height,
4631 width: box.width + 'px',
4632 height: box.height + 'px'
4639 y: box.y + box.height,
4645 width: box.width + 'px',
4646 height: box.height + 'px'
4649 elStyle.bottom = '0px';
4654 wrapAnim = Ext.apply({}, obj);
4655 delete wrapAnim.listeners;
4656 wrapAnim = Ext.create('Ext.fx.Anim', Ext.applyIf(wrapAnim, {
4660 from: slideOut ? anim.to : anim.from,
4661 to: slideOut ? anim.from : anim.to
4664 // In the absence of a callback, this listener MUST be added first
4665 wrapAnim.on('afteranimate', function() {
4667 me.setPositioning(position);
4668 if (obj.useDisplay) {
4669 me.setDisplayed(false);
4675 me.clearPositioning();
4676 me.setPositioning(position);
4679 wrap.dom.parentNode.insertBefore(me.dom, wrap.dom);
4682 me.setSize(box.width, box.height);
4685 // Add configured listeners after
4687 wrapAnim.on(listeners);
4692 duration: obj.duration ? obj.duration * 2 : 1000,
4699 if (wrapAnim && wrapAnim.running) {
4711 * Slides the element out of view. An anchor point can be optionally passed to set the end point for the slide
4712 * effect. When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will
4713 * still take up space in the document. The element must be removed from the DOM using the 'remove' config option if
4714 * desired. This function automatically handles wrapping the element with a fixed-size container if needed. See the
4715 * Fx class overview for valid anchor point options. Usage:
4717 * // default: slide the element out to the top
4720 * // custom: slide the element out to the right with a 2-second duration
4721 * el.slideOut('r', { duration: 2000 });
4723 * // common config options shown with default values
4724 * el.slideOut('t', {
4725 * easing: 'easeOut',
4731 * @param {String} [anchor='t'] One of the valid Fx anchor positions
4732 * @param {Object} [options] Object literal with any of the Fx config options
4733 * @return {Ext.Element} The Element
4735 slideOut: function(anchor, o) {
4736 return this.slideIn(anchor, o, true);
4740 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the element will
4741 * be hidden (visibility = 'hidden') but block elements will still take up space in the document. Usage:
4746 * // common config options shown with default values
4748 * easing: 'easeOut',
4753 * @param {Object} options (optional) Object literal with any of the Fx config options
4754 * @return {Ext.Element} The Element
4756 puff: function(obj) {
4759 obj = Ext.applyIf(obj || {}, {
4765 beforeAnim = function() {
4769 var box = me.getBox(),
4770 fontSize = me.getStyle('fontSize'),
4771 position = me.getPositioning();
4773 width: box.width * 2,
4774 height: box.height * 2,
4775 x: box.x - (box.width / 2),
4776 y: box.y - (box.height /2),
4780 this.on('afteranimate',function() {
4782 if (obj.useDisplay) {
4783 me.setDisplayed(false);
4788 me.setPositioning(position);
4789 me.setStyle({fontSize: fontSize});
4795 duration: obj.duration,
4807 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
4808 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
4809 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if
4815 * // all config options shown with default values
4823 * @param {Object} options (optional) Object literal with any of the Fx config options
4824 * @return {Ext.Element} The Element
4826 switchOff: function(obj) {
4830 obj = Ext.applyIf(obj || {}, {
4837 beforeAnim = function() {
4838 var animScope = this,
4839 size = me.getSize(),
4844 position = me.getPositioning();
4846 keyframe = Ext.create('Ext.fx.Animator', {
4848 duration: obj.duration,
4856 y: xy[1] + size.height / 2
4860 x: xy[0] + size.width / 2
4864 keyframe.on('afteranimate', function() {
4865 if (obj.useDisplay) {
4866 me.setDisplayed(false);
4871 me.setPositioning(position);
4877 duration: (obj.duration * 2),
4888 * Shows a ripple of exploding, attenuating borders to draw attention to an Element. Usage:
4890 * // default: a single light blue ripple
4893 * // custom: 3 red ripples lasting 3 seconds total
4894 * el.frame("#ff0000", 3, { duration: 3 });
4896 * // common config options shown with default values
4897 * el.frame("#C3DAF9", 1, {
4898 * duration: 1 //duration of each individual ripple.
4899 * // Note: Easing is not configurable and will be ignored if included
4902 * @param {String} [color='C3DAF9'] The color of the border. Should be a 6 char hex color without the leading #
4903 * (defaults to light blue).
4904 * @param {Number} [count=1] The number of ripples to display
4905 * @param {Object} [options] Object literal with any of the Fx config options
4906 * @return {Ext.Element} The Element
4908 frame : function(color, count, obj){
4912 color = color || '#C3DAF9';
4916 beforeAnim = function() {
4918 var animScope = this,
4920 proxy = Ext.getBody().createChild({
4922 position : 'absolute',
4923 'pointer-events': 'none',
4925 border : '0px solid ' + color
4929 proxyAnim = Ext.create('Ext.fx.Anim', {
4931 duration: obj.duration || 1000,
4946 height: box.height + 40,
4947 width: box.width + 40
4950 proxyAnim.on('afteranimate', function() {
4957 duration: (obj.duration * 2) || 2000,
4968 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the ending point
4969 * of the effect. Usage:
4971 * // default: slide the element downward while fading out
4974 * // custom: slide the element out to the right with a 2-second duration
4975 * el.ghost('r', { duration: 2000 });
4977 * // common config options shown with default values
4979 * easing: 'easeOut',
4983 * @param {String} [anchor='b'] One of the valid Fx anchor positions
4984 * @param {Object} [options] Object literal with any of the Fx config options
4985 * @return {Ext.Element} The Element
4987 ghost: function(anchor, obj) {
4991 anchor = anchor || "b";
4992 beforeAnim = function() {
4993 var width = me.getWidth(),
4994 height = me.getHeight(),
4996 position = me.getPositioning(),
5002 to.y = xy[1] - height;
5005 to.x = xy[0] - width;
5008 to.x = xy[0] + width;
5011 to.y = xy[1] + height;
5014 to.x = xy[0] - width;
5015 to.y = xy[1] - height;
5018 to.x = xy[0] - width;
5019 to.y = xy[1] + height;
5022 to.x = xy[0] + width;
5023 to.y = xy[1] + height;
5026 to.x = xy[0] + width;
5027 to.y = xy[1] - height;
5031 this.on('afteranimate', function () {
5035 me.setPositioning(position);
5040 me.animate(Ext.applyIf(obj || {}, {
5053 * Highlights the Element by setting a color (applies to the background-color by default, but can be changed using
5054 * the "attr" config option) and then fading back to the original color. If no original color is available, you
5055 * should provide the "endColor" config option which will be cleared after the animation. Usage:
5057 * // default: highlight background to yellow
5060 * // custom: highlight foreground text to blue for 2 seconds
5061 * el.highlight("0000ff", { attr: 'color', duration: 2000 });
5063 * // common config options shown with default values
5064 * el.highlight("ffff9c", {
5065 * attr: "backgroundColor", //can be any valid CSS property (attribute) that supports a color value
5066 * endColor: (current color) or "ffffff",
5071 * @param {String} [color='ffff9c'] The highlight color. Should be a 6 char hex color without the leading #
5072 * @param {Object} [options] Object literal with any of the Fx config options
5073 * @return {Ext.Element} The Element
5075 highlight: function(color, o) {
5079 restore, to, attr, lns, event, fn;
5082 lns = o.listeners || {};
5083 attr = o.attr || 'backgroundColor';
5084 from[attr] = color || 'ffff9c';
5088 to[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
5094 // Don't apply directly on lns, since we reference it in our own callbacks below
5095 o.listeners = Ext.apply(Ext.apply({}, lns), {
5096 beforeanimate: function() {
5097 restore = dom.style[attr];
5101 event = lns.beforeanimate;
5103 fn = event.fn || event;
5104 return fn.apply(event.scope || lns.scope || window, arguments);
5107 afteranimate: function() {
5109 dom.style[attr] = restore;
5112 event = lns.afteranimate;
5114 fn = event.fn || event;
5115 fn.apply(event.scope || lns.scope || window, arguments);
5120 me.animate(Ext.apply({}, o, {
5131 * Creates a pause before any subsequent queued effects begin. If there are no effects queued after the pause it will
5132 * have no effect. Usage:
5136 * @param {Number} seconds The length of time to pause (in seconds)
5137 * @return {Ext.Element} The Element
5139 pause: function(ms) {
5141 Ext.fx.Manager.setFxDefaults(me.id, {
5148 * Fade an element in (from transparent to opaque). The ending opacity can be specified using the `opacity`
5149 * config option. Usage:
5151 * // default: fade in from opacity 0 to 100%
5154 * // custom: fade in from opacity 0 to 75% over 2 seconds
5155 * el.fadeIn({ opacity: .75, duration: 2000});
5157 * // common config options shown with default values
5159 * opacity: 1, //can be any value between 0 and 1 (e.g. .5)
5160 * easing: 'easeOut',
5164 * @param {Object} options (optional) Object literal with any of the Fx config options
5165 * @return {Ext.Element} The Element
5167 fadeIn: function(o) {
5168 this.animate(Ext.apply({}, o, {
5175 * Fade an element out (from opaque to transparent). The ending opacity can be specified using the `opacity`
5176 * config option. Note that IE may require `useDisplay:true` in order to redisplay correctly.
5179 * // default: fade out from the element's current opacity to 0
5182 * // custom: fade out from the element's current opacity to 25% over 2 seconds
5183 * el.fadeOut({ opacity: .25, duration: 2000});
5185 * // common config options shown with default values
5187 * opacity: 0, //can be any value between 0 and 1 (e.g. .5)
5188 * easing: 'easeOut',
5194 * @param {Object} options (optional) Object literal with any of the Fx config options
5195 * @return {Ext.Element} The Element
5197 fadeOut: function(o) {
5198 this.animate(Ext.apply({}, o, {
5206 * Animates the transition of an element's dimensions from a starting height/width to an ending height/width. This
5207 * method is a convenience implementation of {@link #shift}. Usage:
5209 * // change height and width to 100x100 pixels
5210 * el.scale(100, 100);
5212 * // common config options shown with default values. The height and width will default to
5213 * // the element's existing values if passed as null.
5215 * [element's width],
5216 * [element's height], {
5217 * easing: 'easeOut',
5222 * @param {Number} width The new width (pass undefined to keep the original width)
5223 * @param {Number} height The new height (pass undefined to keep the original height)
5224 * @param {Object} options (optional) Object literal with any of the Fx config options
5225 * @return {Ext.Element} The Element
5227 scale: function(w, h, o) {
5228 this.animate(Ext.apply({}, o, {
5237 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity. Any of these
5238 * properties not specified in the config object will not be changed. This effect requires that at least one new
5239 * dimension, position or opacity setting must be passed in on the config object in order for the function to have
5240 * any effect. Usage:
5242 * // slide the element horizontally to x position 200 while changing the height and opacity
5243 * el.shift({ x: 200, height: 50, opacity: .8 });
5245 * // common config options shown with default values.
5247 * width: [element's width],
5248 * height: [element's height],
5249 * x: [element's x position],
5250 * y: [element's y position],
5251 * opacity: [element's opacity],
5252 * easing: 'easeOut',
5256 * @param {Object} options Object literal with any of the Fx config options
5257 * @return {Ext.Element} The Element
5259 shift: function(config) {
5260 this.animate(config);
5266 * @class Ext.Element
5268 Ext.applyIf(Ext.Element, {
5269 unitRe: /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
5270 camelRe: /(-[a-z])/gi,
5271 opacityRe: /alpha\(opacity=(.*)\)/i,
5272 cssRe: /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
5275 borders: {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'},
5276 paddings: {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'},
5277 margins: {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'},
5279 // Reference the prototype's version of the method. Signatures are identical.
5280 addUnits : Ext.Element.prototype.addUnits,
5283 * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
5284 * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
5286 * @param {Number/String} box The encoded margins
5287 * @return {Object} An object with margin sizes for top, right, bottom and left
5289 parseBox : function(box) {
5290 if (Ext.isObject(box)) {
5293 right: box.right || 0,
5294 bottom: box.bottom || 0,
5298 if (typeof box != 'string') {
5299 box = box.toString();
5301 var parts = box.split(' '),
5305 parts[1] = parts[2] = parts[3] = parts[0];
5308 parts[2] = parts[0];
5309 parts[3] = parts[1];
5312 parts[3] = parts[1];
5316 top :parseFloat(parts[0]) || 0,
5317 right :parseFloat(parts[1]) || 0,
5318 bottom:parseFloat(parts[2]) || 0,
5319 left :parseFloat(parts[3]) || 0
5326 * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
5327 * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
5329 * @param {Number/String} box The encoded margins
5330 * @param {String} units The type of units to add
5331 * @return {String} An string with unitized (px if units is not specified) metrics for top, right, bottom and left
5333 unitizeBox : function(box, units) {
5334 var A = this.addUnits,
5335 B = this.parseBox(box);
5337 return A(B.top, units) + ' ' +
5338 A(B.right, units) + ' ' +
5339 A(B.bottom, units) + ' ' +
5345 camelReplaceFn : function(m, a) {
5346 return a.charAt(1).toUpperCase();
5350 * Normalizes CSS property keys from dash delimited to camel case JavaScript Syntax.
5353 * <li>border-width -> borderWidth</li>
5354 * <li>padding-top -> paddingTop</li>
5357 * @param {String} prop The property to normalize
5358 * @return {String} The normalized string
5360 normalize : function(prop) {
5361 if (prop == 'float') {
5362 prop = Ext.supports.Float ? 'cssFloat' : 'styleFloat';
5364 return this.propertyCache[prop] || (this.propertyCache[prop] = prop.replace(this.camelRe, this.camelReplaceFn));
5368 * Retrieves the document height
5370 * @return {Number} documentHeight
5372 getDocumentHeight: function() {
5373 return Math.max(!Ext.isStrict ? document.body.scrollHeight : document.documentElement.scrollHeight, this.getViewportHeight());
5377 * Retrieves the document width
5379 * @return {Number} documentWidth
5381 getDocumentWidth: function() {
5382 return Math.max(!Ext.isStrict ? document.body.scrollWidth : document.documentElement.scrollWidth, this.getViewportWidth());
5386 * Retrieves the viewport height of the window.
5388 * @return {Number} viewportHeight
5390 getViewportHeight: function(){
5391 return window.innerHeight;
5395 * Retrieves the viewport width of the window.
5397 * @return {Number} viewportWidth
5399 getViewportWidth : function() {
5400 return window.innerWidth;
5404 * Retrieves the viewport size of the window.
5406 * @return {Object} object containing width and height properties
5408 getViewSize : function() {
5410 width: window.innerWidth,
5411 height: window.innerHeight
5416 * Retrieves the current orientation of the window. This is calculated by
5417 * determing if the height is greater than the width.
5419 * @return {String} Orientation of window: 'portrait' or 'landscape'
5421 getOrientation : function() {
5422 if (Ext.supports.OrientationChange) {
5423 return (window.orientation == 0) ? 'portrait' : 'landscape';
5426 return (window.innerHeight > window.innerWidth) ? 'portrait' : 'landscape';
5430 * Returns the top Element that is located at the passed coordinates
5432 * @param {Number} x The x coordinate
5433 * @param {Number} y The y coordinate
5434 * @return {String} The found Element
5436 fromPoint: function(x, y) {
5437 return Ext.get(document.elementFromPoint(x, y));
5441 * Converts a CSS string into an object with a property for each style.
5443 * The sample code below would return an object with 2 properties, one
5444 * for background-color and one for color.</p>
5446 var css = 'background-color: red;color: blue; ';
5447 console.log(Ext.Element.parseStyles(css));
5450 * @param {String} styles A CSS string
5451 * @return {Object} styles
5453 parseStyles: function(styles){
5459 // Since we're using the g flag on the regex, we need to set the lastIndex.
5460 // This automatically happens on some implementations, but not others, see:
5461 // http://stackoverflow.com/questions/2645273/javascript-regular-expression-literal-persists-between-function-calls
5462 // http://blog.stevenlevithan.com/archives/fixing-javascript-regexp
5463 cssRe.lastIndex = 0;
5464 while ((matches = cssRe.exec(styles))) {
5465 out[matches[1]] = matches[2];
5473 * @class Ext.CompositeElementLite
5474 * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
5475 * members, or to perform collective actions upon the whole set.</p>
5476 * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
5477 * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
5478 * Example:<pre><code>
5479 var els = Ext.select("#some-el div.some-class");
5480 // or select directly from an existing element
5481 var el = Ext.get('some-el');
5482 el.select('div.some-class');
5484 els.setWidth(100); // all elements become 100 width
5485 els.hide(true); // all elements fade out and hide
5487 els.setWidth(100).hide(true);
5490 Ext.CompositeElementLite = function(els, root){
5492 * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
5493 * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
5494 * to augment the capabilities of the CompositeElementLite class may use it when adding
5495 * methods to the class.</p>
5496 * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
5497 * following siblings of selected elements, the code would be</p><code><pre>
5498 Ext.override(Ext.CompositeElementLite, {
5499 nextAll: function() {
5500 var els = this.elements, i, l = els.length, n, r = [], ri = -1;
5502 // Loop through all elements in this Composite, accumulating
5503 // an Array of all siblings.
5504 for (i = 0; i < l; i++) {
5505 for (n = els[i].nextSibling; n; n = n.nextSibling) {
5510 // Add all found siblings to this Composite
5514 * @property {HTMLElement} elements
5517 this.add(els, root);
5518 this.el = new Ext.Element.Flyweight();
5521 Ext.CompositeElementLite.prototype = {
5525 getElement : function(el){
5526 // Set the shared flyweight dom property to the current element
5534 transformElement : function(el){
5535 return Ext.getDom(el);
5539 * Returns the number of elements in this Composite.
5542 getCount : function(){
5543 return this.elements.length;
5546 * Adds elements to this Composite object.
5547 * @param {HTMLElement[]/Ext.CompositeElement} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
5548 * @return {Ext.CompositeElement} This Composite object.
5550 add : function(els, root){
5552 elements = me.elements;
5556 if(typeof els == "string"){
5557 els = Ext.Element.selectorFunction(els, root);
5558 }else if(els.isComposite){
5560 }else if(!Ext.isIterable(els)){
5564 for(var i = 0, len = els.length; i < len; ++i){
5565 elements.push(me.transformElement(els[i]));
5570 invoke : function(fn, args){
5577 for(i = 0; i < len; i++) {
5580 Ext.Element.prototype[fn].apply(me.getElement(e), args);
5586 * Returns a flyweight Element of the dom element object at the specified index
5587 * @param {Number} index
5588 * @return {Ext.Element}
5590 item : function(index){
5592 el = me.elements[index],
5596 out = me.getElement(el);
5601 // fixes scope with flyweight
5602 addListener : function(eventName, handler, scope, opt){
5603 var els = this.elements,
5607 for(i = 0; i<len; i++) {
5610 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
5616 * <p>Calls the passed function for each element in this composite.</p>
5617 * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
5618 * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
5619 * <b>This is the flyweight (shared) Ext.Element instance, so if you require a
5620 * a reference to the dom node, use el.dom.</b></div></li>
5621 * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
5622 * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
5624 * @param {Object} [scope] The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
5625 * @return {Ext.CompositeElement} this
5627 each : function(fn, scope){
5633 for(i = 0; i<len; i++) {
5636 e = this.getElement(e);
5637 if(fn.call(scope || e, e, me, i) === false){
5646 * Clears this Composite and adds the elements passed.
5647 * @param {HTMLElement[]/Ext.CompositeElement} els Either an array of DOM elements, or another Composite from which to fill this Composite.
5648 * @return {Ext.CompositeElement} this
5650 fill : function(els){
5658 * Filters this composite to only elements that match the passed selector.
5659 * @param {String/Function} selector A string CSS selector or a comparison function.
5660 * The comparison function will be called with the following arguments:<ul>
5661 * <li><code>el</code> : Ext.Element<div class="sub-desc">The current DOM element.</div></li>
5662 * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
5664 * @return {Ext.CompositeElement} this
5666 filter : function(selector){
5669 fn = Ext.isFunction(selector) ? selector
5671 return el.is(selector);
5674 me.each(function(el, self, i) {
5675 if (fn(el, i) !== false) {
5676 els[els.length] = me.transformElement(el);
5685 * Find the index of the passed element within the composite collection.
5686 * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
5687 * @return Number The index of the passed Ext.Element in the composite collection, or -1 if not found.
5689 indexOf : function(el){
5690 return Ext.Array.indexOf(this.elements, this.transformElement(el));
5694 * Replaces the specified element with the passed element.
5695 * @param {String/HTMLElement/Ext.Element/Number} el The id of an element, the Element itself, the index of the element in this composite
5697 * @param {String/Ext.Element} replacement The id of an element or the Element itself.
5698 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
5699 * @return {Ext.CompositeElement} this
5701 replaceElement : function(el, replacement, domReplace){
5702 var index = !isNaN(el) ? el : this.indexOf(el),
5705 replacement = Ext.getDom(replacement);
5707 d = this.elements[index];
5708 d.parentNode.insertBefore(replacement, d);
5711 Ext.Array.splice(this.elements, index, 1, replacement);
5717 * Removes all elements.
5724 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
5728 * Copies all of the functions from Ext.Element's prototype onto CompositeElementLite's prototype.
5729 * This is called twice - once immediately below, and once again after additional Ext.Element
5730 * are added in Ext JS
5732 Ext.CompositeElementLite.importElementMethods = function() {
5734 ElProto = Ext.Element.prototype,
5735 CelProto = Ext.CompositeElementLite.prototype;
5737 for (fnName in ElProto) {
5738 if (typeof ElProto[fnName] == 'function'){
5740 CelProto[fnName] = CelProto[fnName] || function() {
5741 return this.invoke(fnName, arguments);
5743 }).call(CelProto, fnName);
5749 Ext.CompositeElementLite.importElementMethods();
5752 Ext.Element.selectorFunction = Ext.DomQuery.select;
5756 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
5757 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
5758 * {@link Ext.CompositeElementLite CompositeElementLite} object.
5759 * @param {String/HTMLElement[]} selector The CSS selector or an array of elements
5760 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
5761 * @return {Ext.CompositeElementLite/Ext.CompositeElement}
5762 * @member Ext.Element
5765 Ext.Element.select = function(selector, root){
5767 if(typeof selector == "string"){
5768 els = Ext.Element.selectorFunction(selector, root);
5769 }else if(selector.length !== undefined){
5774 sourceClass: "Ext.Element",
5775 sourceMethod: "select",
5778 msg: "Invalid selector specified: " + selector
5782 return new Ext.CompositeElementLite(els);
5785 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
5786 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
5787 * {@link Ext.CompositeElementLite CompositeElementLite} object.
5788 * @param {String/HTMLElement[]} selector The CSS selector or an array of elements
5789 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
5790 * @return {Ext.CompositeElementLite/Ext.CompositeElement}
5794 Ext.select = Ext.Element.select;
5797 * @class Ext.util.DelayedTask
5799 * The DelayedTask class provides a convenient way to "buffer" the execution of a method,
5800 * performing setTimeout where a new timeout cancels the old timeout. When called, the
5801 * task will wait the specified time period before executing. If durng that time period,
5802 * the task is called again, the original call will be cancelled. This continues so that
5803 * the function is only called a single time for each iteration.
5805 * This method is especially useful for things like detecting whether a user has finished
5806 * typing in a text field. An example would be performing validation on a keypress. You can
5807 * use this class to buffer the keypress events for a certain number of milliseconds, and
5808 * perform only if they stop for that amount of time.
5812 * var task = new Ext.util.DelayedTask(function(){
5813 * alert(Ext.getDom('myInputField').value.length);
5816 * // Wait 500ms before calling our function. If the user presses another key
5817 * // during that 500ms, it will be cancelled and we'll wait another 500ms.
5818 * Ext.get('myInputField').on('keypress', function(){
5819 * task.{@link #delay}(500);
5822 * Note that we are using a DelayedTask here to illustrate a point. The configuration
5823 * option `buffer` for {@link Ext.util.Observable#addListener addListener/on} will
5824 * also setup a delayed task for you to buffer events.
5826 * @constructor The parameters to this constructor serve as defaults and are not required.
5827 * @param {Function} fn (optional) The default function to call. If not specified here, it must be specified during the {@link #delay} call.
5828 * @param {Object} scope (optional) The default scope (The <code><b>this</b></code> reference) in which the
5829 * function is called. If not specified, <code>this</code> will refer to the browser window.
5830 * @param {Array} args (optional) The default Array of arguments.
5832 Ext.util.DelayedTask = function(fn, scope, args) {
5838 fn.apply(scope, args || []);
5842 * Cancels any pending timeout and queues a new one
5843 * @param {Number} delay The milliseconds to delay
5844 * @param {Function} newFn (optional) Overrides function passed to constructor
5845 * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
5846 * is specified, <code>this</code> will refer to the browser window.
5847 * @param {Array} newArgs (optional) Overrides args passed to constructor
5849 this.delay = function(delay, newFn, newScope, newArgs) {
5852 scope = newScope || scope;
5853 args = newArgs || args;
5854 id = setInterval(call, delay);
5858 * Cancel the last queued timeout
5860 this.cancel = function(){
5867 Ext.require('Ext.util.DelayedTask', function() {
5869 Ext.util.Event = Ext.extend(Object, (function() {
5870 function createBuffered(handler, listener, o, scope) {
5871 listener.task = new Ext.util.DelayedTask();
5873 listener.task.delay(o.buffer, handler, scope, Ext.Array.toArray(arguments));
5877 function createDelayed(handler, listener, o, scope) {
5879 var task = new Ext.util.DelayedTask();
5880 if (!listener.tasks) {
5881 listener.tasks = [];
5883 listener.tasks.push(task);
5884 task.delay(o.delay || 10, handler, scope, Ext.Array.toArray(arguments));
5888 function createSingle(handler, listener, o, scope) {
5890 listener.ev.removeListener(listener.fn, scope);
5891 return handler.apply(scope, arguments);
5898 constructor: function(observable, name) {
5900 this.observable = observable;
5901 this.listeners = [];
5904 addListener: function(fn, scope, options) {
5907 scope = scope || me.observable;
5912 sourceClass: Ext.getClassName(this.observable),
5913 sourceMethod: "addListener",
5914 msg: "The specified callback function is undefined"
5919 if (!me.isListening(fn, scope)) {
5920 listener = me.createListener(fn, scope, options);
5922 // if we are currently firing this event, don't disturb the listener loop
5923 me.listeners = me.listeners.slice(0);
5925 me.listeners.push(listener);
5929 createListener: function(fn, scope, o) {
5931 scope = scope || this.observable;
5941 // The order is important. The 'single' wrapper must be wrapped by the 'buffer' and 'delayed' wrapper
5942 // because the event removal that the single listener does destroys the listener's DelayedTask(s)
5944 handler = createSingle(handler, listener, o, scope);
5947 handler = createDelayed(handler, listener, o, scope);
5950 handler = createBuffered(handler, listener, o, scope);
5953 listener.fireFn = handler;
5957 findListener: function(fn, scope) {
5958 var listeners = this.listeners,
5959 i = listeners.length,
5964 listener = listeners[i];
5967 if (listener.fn == fn && (s == scope || s == this.observable)) {
5976 isListening: function(fn, scope) {
5977 return this.findListener(fn, scope) !== -1;
5980 removeListener: function(fn, scope) {
5985 index = me.findListener(fn, scope);
5987 listener = me.listeners[index];
5990 me.listeners = me.listeners.slice(0);
5993 // cancel and remove a buffered handler that hasn't fired yet
5994 if (listener.task) {
5995 listener.task.cancel();
5996 delete listener.task;
5999 // cancel and remove all delayed handlers that haven't fired yet
6000 k = listener.tasks && listener.tasks.length;
6003 listener.tasks[k].cancel();
6005 delete listener.tasks;
6008 // remove this listener from the listeners array
6009 Ext.Array.erase(me.listeners, index, 1);
6016 // Iterate to stop any buffered/delayed events
6017 clearListeners: function() {
6018 var listeners = this.listeners,
6019 i = listeners.length;
6022 this.removeListener(listeners[i].fn, listeners[i].scope);
6028 listeners = me.listeners,
6029 count = listeners.length,
6036 for (i = 0; i < count; i++) {
6037 listener = listeners[i];
6038 args = arguments.length ? Array.prototype.slice.call(arguments, 0) : [];
6040 args.push(listener.o);
6042 if (listener && listener.fireFn.apply(listener.scope || me.observable, args) === false) {
6043 return (me.firing = false);
6055 * @class Ext.EventManager
6056 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6057 * several useful events directly.
6058 * See {@link Ext.EventObject} for more details on normalized event objects.
6061 Ext.EventManager = {
6063 // --------------------- onReady ---------------------
6066 * Check if we have bound our global onReady listener
6069 hasBoundOnReady: false,
6072 * Check if fireDocReady has been called
6075 hasFiredReady: false,
6078 * Timer for the document ready event in old IE versions
6084 * Checks if we have bound an onreadystatechange event
6087 hasOnReadyStateChange: false,
6090 * Holds references to any onReady functions
6093 readyEvent: new Ext.util.Event(),
6096 * Check the ready state for old IE versions
6098 * @return {Boolean} True if the document is ready
6100 checkReadyState: function(){
6101 var me = Ext.EventManager;
6103 if(window.attachEvent){
6104 // See here for reference: http://javascript.nwbox.com/IEContentLoaded/
6105 // licensed courtesy of http://developer.yahoo.com/yui/license.html
6106 if (window != top) {
6110 document.documentElement.doScroll('left');
6117 if (document.readyState == 'complete') {
6121 me.readyTimeout = setTimeout(arguments.callee, 2);
6126 * Binds the appropriate browser event for checking if the DOM has loaded.
6129 bindReadyEvent: function(){
6130 var me = Ext.EventManager;
6131 if (me.hasBoundOnReady) {
6135 if (document.addEventListener) {
6136 document.addEventListener('DOMContentLoaded', me.fireDocReady, false);
6137 // fallback, load will ~always~ fire
6138 window.addEventListener('load', me.fireDocReady, false);
6140 // check if the document is ready, this will also kick off the scroll checking timer
6141 if (!me.checkReadyState()) {
6142 document.attachEvent('onreadystatechange', me.checkReadyState);
6143 me.hasOnReadyStateChange = true;
6145 // fallback, onload will ~always~ fire
6146 window.attachEvent('onload', me.fireDocReady, false);
6148 me.hasBoundOnReady = true;
6152 * We know the document is loaded, so trigger any onReady events.
6155 fireDocReady: function(){
6156 var me = Ext.EventManager;
6158 // only unbind these events once
6159 if (!me.hasFiredReady) {
6160 me.hasFiredReady = true;
6162 if (document.addEventListener) {
6163 document.removeEventListener('DOMContentLoaded', me.fireDocReady, false);
6164 window.removeEventListener('load', me.fireDocReady, false);
6166 if (me.readyTimeout !== null) {
6167 clearTimeout(me.readyTimeout);
6169 if (me.hasOnReadyStateChange) {
6170 document.detachEvent('onreadystatechange', me.checkReadyState);
6172 window.detachEvent('onload', me.fireDocReady);
6174 Ext.supports.init();
6178 me.onWindowUnload();
6179 me.readyEvent.fire();
6184 * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
6185 * accessed shorthanded as Ext.onReady().
6186 * @param {Function} fn The method the event invokes.
6187 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
6188 * @param {Boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}.
6190 onDocumentReady: function(fn, scope, options){
6191 options = options || {};
6192 var me = Ext.EventManager,
6193 readyEvent = me.readyEvent;
6195 // force single to be true so our event is only ever fired once.
6196 options.single = true;
6198 // Document already loaded, let's just fire it
6200 readyEvent.addListener(fn, scope, options);
6203 options.delay = options.delay || 1;
6204 readyEvent.addListener(fn, scope, options);
6205 me.bindReadyEvent();
6210 // --------------------- event binding ---------------------
6213 * Contains a list of all document mouse downs, so we can ensure they fire even when stopEvent is called.
6216 stoppedMouseDownEvent: new Ext.util.Event(),
6219 * Options to parse for the 4th argument to addListener.
6222 propRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|freezeEvent)$/,
6225 * Get the id of the element. If one has not been assigned, automatically assign it.
6226 * @param {HTMLElement/Ext.Element} element The element to get the id for.
6227 * @return {String} id
6229 getId : function(element) {
6230 var skipGarbageCollection = false,
6233 element = Ext.getDom(element);
6235 if (element === document || element === window) {
6236 id = element === document ? Ext.documentId : Ext.windowId;
6239 id = Ext.id(element);
6241 // skip garbage collection for special elements (window, document, iframes)
6242 if (element && (element.getElementById || element.navigator)) {
6243 skipGarbageCollection = true;
6246 if (!Ext.cache[id]){
6247 Ext.Element.addToCache(new Ext.Element(element), id);
6248 if (skipGarbageCollection) {
6249 Ext.cache[id].skipGarbageCollection = true;
6256 * Convert a "config style" listener into a set of flat arguments so they can be passed to addListener
6258 * @param {Object} element The element the event is for
6259 * @param {Object} event The event configuration
6260 * @param {Object} isRemove True if a removal should be performed, otherwise an add will be done.
6262 prepareListenerConfig: function(element, config, isRemove){
6267 // loop over all the keys in the object
6268 for (key in config) {
6269 if (config.hasOwnProperty(key)) {
6270 // if the key is something else then an event option
6271 if (!propRe.test(key)) {
6272 value = config[key];
6273 // if the value is a function it must be something like click: function(){}, scope: this
6274 // which means that there might be multiple event listeners with shared options
6275 if (Ext.isFunction(value)) {
6277 args = [element, key, value, config.scope, config];
6279 // if its not a function, it must be an object like click: {fn: function(){}, scope: this}
6280 args = [element, key, value.fn, value.scope, value];
6283 if (isRemove === true) {
6284 me.removeListener.apply(this, args);
6286 me.addListener.apply(me, args);
6294 * Normalize cross browser event differences
6296 * @param {Object} eventName The event name
6297 * @param {Object} fn The function to execute
6298 * @return {Object} The new event name/function
6300 normalizeEvent: function(eventName, fn){
6301 if (/mouseenter|mouseleave/.test(eventName) && !Ext.supports.MouseEnterLeave) {
6303 fn = Ext.Function.createInterceptor(fn, this.contains, this);
6305 eventName = eventName == 'mouseenter' ? 'mouseover' : 'mouseout';
6306 } else if (eventName == 'mousewheel' && !Ext.supports.MouseWheel && !Ext.isOpera){
6307 eventName = 'DOMMouseScroll';
6310 eventName: eventName,
6316 * Checks whether the event's relatedTarget is contained inside (or <b>is</b>) the element.
6318 * @param {Object} event
6320 contains: function(event){
6321 var parent = event.browserEvent.currentTarget,
6322 child = this.getRelatedTarget(event);
6324 if (parent && parent.firstChild) {
6326 if (child === parent) {
6329 child = child.parentNode;
6330 if (child && (child.nodeType != 1)) {
6339 * Appends an event handler to an element. The shorthand version {@link #on} is equivalent. Typically you will
6340 * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
6341 * @param {String/HTMLElement} el The html element or id to assign the event handler to.
6342 * @param {String} eventName The name of the event to listen for.
6343 * @param {Function} handler The handler function the event invokes. This function is passed
6344 * the following parameters:<ul>
6345 * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
6346 * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
6347 * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
6348 * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
6350 * @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>.
6351 * @param {Object} options (optional) An object containing handler configuration properties.
6352 * This may contain any of the following properties:<ul>
6353 * <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>
6354 * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
6355 * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
6356 * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
6357 * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
6358 * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
6359 * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
6360 * <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>
6361 * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
6362 * by the specified number of milliseconds. If the event fires again within that time, the original
6363 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
6364 * <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>
6366 * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
6368 addListener: function(element, eventName, fn, scope, options){
6369 // Check if we've been passed a "config style" event.
6370 if (typeof eventName !== 'string') {
6371 this.prepareListenerConfig(element, eventName);
6375 var dom = Ext.getDom(element),
6382 sourceClass: 'Ext.EventManager',
6383 sourceMethod: 'addListener',
6384 targetElement: element,
6385 eventName: eventName,
6386 msg: 'Error adding "' + eventName + '\" listener for nonexistent element "' + element + '"'
6391 sourceClass: 'Ext.EventManager',
6392 sourceMethod: 'addListener',
6393 targetElement: element,
6394 eventName: eventName,
6395 msg: 'Error adding "' + eventName + '\" listener. The handler function is undefined.'
6400 // create the wrapper function
6401 options = options || {};
6403 bind = this.normalizeEvent(eventName, fn);
6404 wrap = this.createListenerWrap(dom, eventName, bind.fn, scope, options);
6407 if (dom.attachEvent) {
6408 dom.attachEvent('on' + bind.eventName, wrap);
6410 dom.addEventListener(bind.eventName, wrap, options.capture || false);
6413 if (dom == document && eventName == 'mousedown') {
6414 this.stoppedMouseDownEvent.addListener(wrap);
6417 // add all required data into the event cache
6418 this.getEventListenerCache(dom, eventName).push({
6426 * Removes an event handler from an element. The shorthand version {@link #un} is equivalent. Typically
6427 * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
6428 * @param {String/HTMLElement} el The id or html element from which to remove the listener.
6429 * @param {String} eventName The name of the event.
6430 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
6431 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
6432 * then this must refer to the same object.
6434 removeListener : function(element, eventName, fn, scope) {
6435 // handle our listener config object syntax
6436 if (typeof eventName !== 'string') {
6437 this.prepareListenerConfig(element, eventName, true);
6441 var dom = Ext.getDom(element),
6442 cache = this.getEventListenerCache(dom, eventName),
6443 bindName = this.normalizeEvent(eventName).eventName,
6444 i = cache.length, j,
6445 listener, wrap, tasks;
6449 listener = cache[i];
6451 if (listener && (!fn || listener.fn == fn) && (!scope || listener.scope === scope)) {
6452 wrap = listener.wrap;
6454 // clear buffered calls
6456 clearTimeout(wrap.task);
6460 // clear delayed calls
6461 j = wrap.tasks && wrap.tasks.length;
6464 clearTimeout(wrap.tasks[j]);
6469 if (dom.detachEvent) {
6470 dom.detachEvent('on' + bindName, wrap);
6472 dom.removeEventListener(bindName, wrap, false);
6475 if (wrap && dom == document && eventName == 'mousedown') {
6476 this.stoppedMouseDownEvent.removeListener(wrap);
6479 // remove listener from cache
6480 Ext.Array.erase(cache, i, 1);
6486 * Removes all event handers from an element. Typically you will use {@link Ext.Element#removeAllListeners}
6487 * directly on an Element in favor of calling this version.
6488 * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
6490 removeAll : function(element){
6491 var dom = Ext.getDom(element),
6496 cache = this.getElementEventCache(dom);
6499 if (cache.hasOwnProperty(ev)) {
6500 this.removeListener(dom, ev);
6503 Ext.cache[dom.id].events = {};
6507 * Recursively removes all previous added listeners from an element and its children. Typically you will use {@link Ext.Element#purgeAllListeners}
6508 * directly on an Element in favor of calling this version.
6509 * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
6510 * @param {String} eventName (optional) The name of the event.
6512 purgeElement : function(element, eventName) {
6513 var dom = Ext.getDom(element),
6517 this.removeListener(dom, eventName);
6520 this.removeAll(dom);
6523 if(dom && dom.childNodes) {
6524 for(len = element.childNodes.length; i < len; i++) {
6525 this.purgeElement(element.childNodes[i], eventName);
6531 * Create the wrapper function for the event
6533 * @param {HTMLElement} dom The dom element
6534 * @param {String} ename The event name
6535 * @param {Function} fn The function to execute
6536 * @param {Object} scope The scope to execute callback in
6537 * @param {Object} options The options
6538 * @return {Function} the wrapper function
6540 createListenerWrap : function(dom, ename, fn, scope, options) {
6541 options = options || {};
6545 return function wrap(e, args) {
6546 // Compile the implementation upon first firing
6548 f = ['if(!Ext) {return;}'];
6550 if(options.buffer || options.delay || options.freezeEvent) {
6551 f.push('e = new Ext.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
6553 f.push('e = Ext.EventObject.setEvent(e);');
6556 if (options.delegate) {
6557 f.push('var t = e.getTarget("' + options.delegate + '", this);');
6558 f.push('if(!t) {return;}');
6560 f.push('var t = e.target;');
6563 if (options.target) {
6564 f.push('if(e.target !== options.target) {return;}');
6567 if(options.stopEvent) {
6568 f.push('e.stopEvent();');
6570 if(options.preventDefault) {
6571 f.push('e.preventDefault();');
6573 if(options.stopPropagation) {
6574 f.push('e.stopPropagation();');
6578 if(options.normalized === false) {
6579 f.push('e = e.browserEvent;');
6582 if(options.buffer) {
6583 f.push('(wrap.task && clearTimeout(wrap.task));');
6584 f.push('wrap.task = setTimeout(function(){');
6588 f.push('wrap.tasks = wrap.tasks || [];');
6589 f.push('wrap.tasks.push(setTimeout(function(){');
6592 // finally call the actual handler fn
6593 f.push('fn.call(scope || dom, e, t, options);');
6595 if(options.single) {
6596 f.push('Ext.EventManager.removeListener(dom, ename, fn, scope);');
6600 f.push('}, ' + options.delay + '));');
6603 if(options.buffer) {
6604 f.push('}, ' + options.buffer + ');');
6607 gen = Ext.functionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', f.join('\n'));
6610 gen.call(dom, e, options, fn, scope, ename, dom, wrap, args);
6615 * Get the event cache for a particular element for a particular event
6617 * @param {HTMLElement} element The element
6618 * @param {Object} eventName The event name
6619 * @return {Array} The events for the element
6621 getEventListenerCache : function(element, eventName) {
6626 var eventCache = this.getElementEventCache(element);
6627 return eventCache[eventName] || (eventCache[eventName] = []);
6631 * Gets the event cache for the object
6633 * @param {HTMLElement} element The element
6634 * @return {Object} The event cache for the object
6636 getElementEventCache : function(element) {
6640 var elementCache = Ext.cache[this.getId(element)];
6641 return elementCache.events || (elementCache.events = {});
6644 // --------------------- utility methods ---------------------
6645 mouseLeaveRe: /(mouseout|mouseleave)/,
6646 mouseEnterRe: /(mouseover|mouseenter)/,
6649 * Stop the event (preventDefault and stopPropagation)
6650 * @param {Event} The event to stop
6652 stopEvent: function(event) {
6653 this.stopPropagation(event);
6654 this.preventDefault(event);
6658 * Cancels bubbling of the event.
6659 * @param {Event} The event to stop bubbling.
6661 stopPropagation: function(event) {
6662 event = event.browserEvent || event;
6663 if (event.stopPropagation) {
6664 event.stopPropagation();
6666 event.cancelBubble = true;
6671 * Prevents the browsers default handling of the event.
6672 * @param {Event} The event to prevent the default
6674 preventDefault: function(event) {
6675 event = event.browserEvent || event;
6676 if (event.preventDefault) {
6677 event.preventDefault();
6679 event.returnValue = false;
6680 // Some keys events require setting the keyCode to -1 to be prevented
6682 // all ctrl + X and F1 -> F12
6683 if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {
6687 // see this outdated document http://support.microsoft.com/kb/934364/en-us for more info
6693 * Gets the related target from the event.
6694 * @param {Object} event The event
6695 * @return {HTMLElement} The related target.
6697 getRelatedTarget: function(event) {
6698 event = event.browserEvent || event;
6699 var target = event.relatedTarget;
6701 if (this.mouseLeaveRe.test(event.type)) {
6702 target = event.toElement;
6703 } else if (this.mouseEnterRe.test(event.type)) {
6704 target = event.fromElement;
6707 return this.resolveTextNode(target);
6711 * Gets the x coordinate from the event
6712 * @param {Object} event The event
6713 * @return {Number} The x coordinate
6715 getPageX: function(event) {
6716 return this.getXY(event)[0];
6720 * Gets the y coordinate from the event
6721 * @param {Object} event The event
6722 * @return {Number} The y coordinate
6724 getPageY: function(event) {
6725 return this.getXY(event)[1];
6729 * Gets the x & y coordinate from the event
6730 * @param {Object} event The event
6731 * @return {Number[]} The x/y coordinate
6733 getPageXY: function(event) {
6734 event = event.browserEvent || event;
6735 var x = event.pageX,
6737 doc = document.documentElement,
6738 body = document.body;
6740 // pageX/pageY not available (undefined, not null), use clientX/clientY instead
6741 if (!x && x !== 0) {
6742 x = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
6743 y = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
6749 * Gets the target of the event.
6750 * @param {Object} event The event
6751 * @return {HTMLElement} target
6753 getTarget: function(event) {
6754 event = event.browserEvent || event;
6755 return this.resolveTextNode(event.target || event.srcElement);
6759 * Resolve any text nodes accounting for browser differences.
6761 * @param {HTMLElement} node The node
6762 * @return {HTMLElement} The resolved node
6764 // technically no need to browser sniff this, however it makes no sense to check this every time, for every event, whether the string is equal.
6765 resolveTextNode: Ext.isGecko ?
6770 // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
6771 var s = HTMLElement.prototype.toString.call(node);
6772 if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]') {
6775 return node.nodeType == 3 ? node.parentNode: node;
6777 return node && node.nodeType == 3 ? node.parentNode: node;
6780 // --------------------- custom event binding ---------------------
6782 // Keep track of the current width/height
6787 * Adds a listener to be notified when the browser window is resized and provides resize event buffering (100 milliseconds),
6788 * passes new viewport width and height to handlers.
6789 * @param {Function} fn The handler function the window resize event invokes.
6790 * @param {Object} scope The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
6791 * @param {Boolean} options Options object as passed to {@link Ext.Element#addListener}
6793 onWindowResize: function(fn, scope, options){
6794 var resize = this.resizeEvent;
6796 this.resizeEvent = resize = new Ext.util.Event();
6797 this.on(window, 'resize', this.fireResize, this, {buffer: 100});
6799 resize.addListener(fn, scope, options);
6803 * Fire the resize event.
6806 fireResize: function(){
6808 w = Ext.Element.getViewWidth(),
6809 h = Ext.Element.getViewHeight();
6811 //whacky problem in IE where the resize event will sometimes fire even though the w/h are the same.
6812 if(me.curHeight != h || me.curWidth != w){
6815 me.resizeEvent.fire(w, h);
6820 * Removes the passed window resize listener.
6821 * @param {Function} fn The method the event invokes
6822 * @param {Object} scope The scope of handler
6824 removeResizeListener: function(fn, scope){
6825 if (this.resizeEvent) {
6826 this.resizeEvent.removeListener(fn, scope);
6830 onWindowUnload: function() {
6831 var unload = this.unloadEvent;
6833 this.unloadEvent = unload = new Ext.util.Event();
6834 this.addListener(window, 'unload', this.fireUnload, this);
6839 * Fires the unload event for items bound with onWindowUnload
6842 fireUnload: function() {
6843 // wrap in a try catch, could have some problems during unload
6845 this.removeUnloadListener();
6846 // Work around FF3 remembering the last scroll position when refreshing the grid and then losing grid view
6848 var gridviews = Ext.ComponentQuery.query('gridview'),
6850 ln = gridviews.length;
6851 for (; i < ln; i++) {
6852 gridviews[i].scrollToTop();
6855 // Purge all elements in the cache
6859 if (cache.hasOwnProperty(el)) {
6860 Ext.EventManager.removeAll(el);
6868 * Removes the passed window unload listener.
6869 * @param {Function} fn The method the event invokes
6870 * @param {Object} scope The scope of handler
6872 removeUnloadListener: function(){
6873 if (this.unloadEvent) {
6874 this.removeListener(window, 'unload', this.fireUnload);
6879 * note 1: IE fires ONLY the keydown event on specialkey autorepeat
6880 * note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat
6881 * (research done by Jan Wolter at http://unixpapa.com/js/key.html)
6884 useKeyDown: Ext.isWebKit ?
6885 parseInt(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1], 10) >= 525 :
6886 !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera),
6889 * Indicates which event to use for getting key presses.
6890 * @return {String} The appropriate event name.
6892 getKeyEvent: function(){
6893 return this.useKeyDown ? 'keydown' : 'keypress';
6898 * Alias for {@link Ext.Loader#onReady Ext.Loader.onReady} with withDomReady set to true
6902 Ext.onReady = function(fn, scope, options) {
6903 Ext.Loader.onReady(fn, scope, true, options);
6907 * Alias for {@link Ext.EventManager#onDocumentReady Ext.EventManager.onDocumentReady}
6909 * @method onDocumentReady
6911 Ext.onDocumentReady = Ext.EventManager.onDocumentReady;
6914 * Alias for {@link Ext.EventManager#addListener Ext.EventManager.addListener}
6915 * @member Ext.EventManager
6918 Ext.EventManager.on = Ext.EventManager.addListener;
6921 * Alias for {@link Ext.EventManager#removeListener Ext.EventManager.removeListener}
6922 * @member Ext.EventManager
6925 Ext.EventManager.un = Ext.EventManager.removeListener;
6928 var initExtCss = function() {
6929 // find the body element
6930 var bd = document.body || document.getElementsByTagName('body')[0],
6931 baseCSSPrefix = Ext.baseCSSPrefix,
6932 cls = [baseCSSPrefix + 'body'],
6940 html = bd.parentNode;
6943 cls.push(baseCSSPrefix + c);
6946 //Let's keep this human readable!
6950 // very often CSS needs to do checks like "IE7+" or "IE6 or 7". To help
6951 // reduce the clutter (since CSS/SCSS cannot do these tests), we add some
6952 // additional classes:
6954 // x-ie7p : IE7+ : 7 <= ieVer
6955 // x-ie7m : IE7- : ieVer <= 7
6956 // x-ie8p : IE8+ : 8 <= ieVer
6957 // x-ie8m : IE8- : ieVer <= 8
6958 // x-ie9p : IE9+ : 9 <= ieVer
6959 // x-ie78 : IE7 or 8 : 7 <= ieVer <= 8
6963 } else { // ignore pre-IE6 :)
6983 if (Ext.isIE6 || Ext.isIE7) {
6986 if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
6989 if (Ext.isIE7 || Ext.isIE8) {
7013 if (Ext.isSafari2) {
7016 if (Ext.isSafari3) {
7019 if (Ext.isSafari4) {
7022 if (Ext.isSafari5) {
7035 if (!Ext.supports.CSS3BorderRadius) {
7038 if (!Ext.supports.CSS3LinearGradient) {
7041 if (!Ext.scopeResetCSS) {
7045 // add to the parent to allow for selectors x-strict x-border-box, also set the isBorderBox property correctly
7047 if (Ext.isStrict && (Ext.isIE6 || Ext.isIE7)) {
7048 Ext.isBorderBox = false;
7051 Ext.isBorderBox = true;
7054 htmlCls.push(baseCSSPrefix + (Ext.isBorderBox ? 'border-box' : 'strict'));
7055 if (!Ext.isStrict) {
7056 htmlCls.push(baseCSSPrefix + 'quirks');
7058 Ext.fly(html, '_internal').addCls(htmlCls);
7061 Ext.fly(bd, '_internal').addCls(cls);
7065 Ext.onReady(initExtCss);
7069 * @class Ext.EventObject
7071 Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject
7072 wraps the browser's native event-object normalizing cross-browser differences,
7073 such as which mouse button is clicked, keys pressed, mechanisms to stop
7074 event-propagation along with a method to prevent default actions from taking place.
7078 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
7080 var target = e.getTarget(); // same as t (the target HTMLElement)
7084 var myDiv = {@link Ext#get Ext.get}("myDiv"); // get reference to an {@link Ext.Element}
7085 myDiv.on( // 'on' is shorthand for addListener
7086 "click", // perform an action on click of myDiv
7087 handleClick // reference to the action handler
7090 // other methods to do the same:
7091 Ext.EventManager.on("myDiv", 'click', handleClick);
7092 Ext.EventManager.addListener("myDiv", 'click', handleClick);
7097 Ext.define('Ext.EventObjectImpl', {
7098 uses: ['Ext.util.Point'],
7100 /** Key constant @type Number */
7102 /** Key constant @type Number */
7104 /** Key constant @type Number */
7106 /** Key constant @type Number */
7108 /** Key constant @type Number */
7110 /** Key constant @type Number */
7112 /** Key constant @type Number */
7114 /** Key constant @type Number */
7116 /** Key constant @type Number */
7118 /** Key constant @type Number */
7120 /** Key constant @type Number */
7122 /** Key constant @type Number */
7124 /** Key constant @type Number */
7126 /** Key constant @type Number */
7128 /** Key constant @type Number */
7130 /** Key constant @type Number */
7132 /** Key constant @type Number */
7134 /** Key constant @type Number */
7136 /** Key constant @type Number */
7138 /** Key constant @type Number */
7140 /** Key constant @type Number */
7142 /** Key constant @type Number */
7144 /** Key constant @type Number */
7146 /** Key constant @type Number */
7148 /** Key constant @type Number */
7150 /** Key constant @type Number */
7152 /** Key constant @type Number */
7154 /** Key constant @type Number */
7156 /** Key constant @type Number */
7158 /** Key constant @type Number */
7160 /** Key constant @type Number */
7162 /** Key constant @type Number */
7164 /** Key constant @type Number */
7166 /** Key constant @type Number */
7168 /** Key constant @type Number */
7170 /** Key constant @type Number */
7172 /** Key constant @type Number */
7174 /** Key constant @type Number */
7176 /** Key constant @type Number */
7178 /** Key constant @type Number */
7180 /** Key constant @type Number */
7182 /** Key constant @type Number */
7184 /** Key constant @type Number */
7186 /** Key constant @type Number */
7188 /** Key constant @type Number */
7190 /** Key constant @type Number */
7192 /** Key constant @type Number */
7194 /** Key constant @type Number */
7196 /** Key constant @type Number */
7198 /** Key constant @type Number */
7200 /** Key constant @type Number */
7202 /** Key constant @type Number */
7204 /** Key constant @type Number */
7206 /** Key constant @type Number */
7208 /** Key constant @type Number */
7210 /** Key constant @type Number */
7212 /** Key constant @type Number */
7214 /** Key constant @type Number */
7216 /** Key constant @type Number */
7218 /** Key constant @type Number */
7220 /** Key constant @type Number */
7222 /** Key constant @type Number */
7224 /** Key constant @type Number */
7226 /** Key constant @type Number */
7228 /** Key constant @type Number */
7230 /** Key constant @type Number */
7232 /** Key constant @type Number */
7234 /** Key constant @type Number */
7236 /** Key constant @type Number */
7238 /** Key constant @type Number */
7240 /** Key constant @type Number */
7242 /** Key constant @type Number */
7244 /** Key constant @type Number */
7246 /** Key constant @type Number */
7248 /** Key constant @type Number */
7250 /** Key constant @type Number */
7252 /** Key constant @type Number */
7254 /** Key constant @type Number */
7256 /** Key constant @type Number */
7258 /** Key constant @type Number */
7260 /** Key constant @type Number */
7262 /** Key constant @type Number */
7264 /** Key constant @type Number */
7266 /** Key constant @type Number */
7268 /** Key constant @type Number */
7270 /** Key constant @type Number */
7272 /** Key constant @type Number */
7275 * The mouse wheel delta scaling factor. This value depends on browser version and OS and
7276 * attempts to produce a similar scrolling experience across all platforms and browsers.
7278 * To change this value:
7280 * Ext.EventObjectImpl.prototype.WHEEL_SCALE = 72;
7285 WHEEL_SCALE: (function () {
7289 // Firefox uses 3 on all platforms
7291 } else if (Ext.isMac) {
7292 // Continuous scrolling devices have momentum and produce much more scroll than
7293 // discrete devices on the same OS and browser. To make things exciting, Safari
7294 // (and not Chrome) changed from small values to 120 (like IE).
7296 if (Ext.isSafari && Ext.webKitVersion >= 532.0) {
7297 // Safari changed the scrolling factor to match IE (for details see
7298 // https://bugs.webkit.org/show_bug.cgi?id=24368). The WebKit version where this
7299 // change was introduced was 532.0
7300 // Detailed discussion:
7301 // https://bugs.webkit.org/show_bug.cgi?id=29601
7302 // http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063
7305 // MS optical wheel mouse produces multiples of 12 which is close enough
7306 // to help tame the speed of the continuous mice...
7310 // Momentum scrolling produces very fast scrolling, so increase the scale factor
7311 // to help produce similar results cross platform. This could be even larger and
7312 // it would help those mice, but other mice would become almost unusable as a
7313 // result (since we cannot tell which device type is in use).
7316 // IE, Opera and other Windows browsers use 120.
7324 * Simple click regex
7327 clickRe: /(dbl)?click/,
7328 // safari keypress events for special keys return bad keycodes
7335 63276: 33, // page up
7336 63277: 34, // page down
7337 63272: 46, // delete
7341 // normalize button clicks, don't see any way to feature detect this.
7342 btnMap: Ext.isIE ? {
7352 constructor: function(event, freezeEvent){
7354 this.setEvent(event.browserEvent || event, freezeEvent);
7358 setEvent: function(event, freezeEvent){
7359 var me = this, button, options;
7361 if (event == me || (event && event.browserEvent)) { // already wrapped
7364 me.browserEvent = event;
7366 // normalize buttons
7367 button = event.button ? me.btnMap[event.button] : (event.which ? event.which - 1 : -1);
7368 if (me.clickRe.test(event.type) && button == -1) {
7374 shiftKey: event.shiftKey,
7375 // mac metaKey behaves like ctrlKey
7376 ctrlKey: event.ctrlKey || event.metaKey || false,
7377 altKey: event.altKey,
7378 // in getKey these will be normalized for the mac
7379 keyCode: event.keyCode,
7380 charCode: event.charCode,
7381 // cache the targets for the delayed and or buffered events
7382 target: Ext.EventManager.getTarget(event),
7383 relatedTarget: Ext.EventManager.getRelatedTarget(event),
7384 currentTarget: event.currentTarget,
7385 xy: (freezeEvent ? me.getXY() : null)
7399 Ext.apply(me, options);
7404 * Stop the event (preventDefault and stopPropagation)
7406 stopEvent: function(){
7407 this.stopPropagation();
7408 this.preventDefault();
7412 * Prevents the browsers default handling of the event.
7414 preventDefault: function(){
7415 if (this.browserEvent) {
7416 Ext.EventManager.preventDefault(this.browserEvent);
7421 * Cancels bubbling of the event.
7423 stopPropagation: function(){
7424 var browserEvent = this.browserEvent;
7427 if (browserEvent.type == 'mousedown') {
7428 Ext.EventManager.stoppedMouseDownEvent.fire(this);
7430 Ext.EventManager.stopPropagation(browserEvent);
7435 * Gets the character code for the event.
7438 getCharCode: function(){
7439 return this.charCode || this.keyCode;
7443 * Returns a normalized keyCode for the event.
7444 * @return {Number} The key code
7447 return this.normalizeKey(this.keyCode || this.charCode);
7451 * Normalize key codes across browsers
7453 * @param {Number} key The key code
7454 * @return {Number} The normalized code
7456 normalizeKey: function(key){
7457 // can't feature detect this
7458 return Ext.isWebKit ? (this.safariKeys[key] || key) : key;
7462 * Gets the x coordinate of the event.
7464 * @deprecated 4.0 Replaced by {@link #getX}
7466 getPageX: function(){
7471 * Gets the y coordinate of the event.
7473 * @deprecated 4.0 Replaced by {@link #getY}
7475 getPageY: function(){
7480 * Gets the x coordinate of the event.
7484 return this.getXY()[0];
7488 * Gets the y coordinate of the event.
7492 return this.getXY()[1];
7496 * Gets the page coordinates of the event.
7497 * @return {Number[]} The xy values like [x, y]
7502 this.xy = Ext.EventManager.getPageXY(this.browserEvent);
7508 * Gets the target for the event.
7509 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7510 * @param {Number/HTMLElement} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
7511 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
7512 * @return {HTMLElement}
7514 getTarget : function(selector, maxDepth, returnEl){
7516 return Ext.fly(this.target).findParent(selector, maxDepth, returnEl);
7518 return returnEl ? Ext.get(this.target) : this.target;
7522 * Gets the related target.
7523 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7524 * @param {Number/HTMLElement} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
7525 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
7526 * @return {HTMLElement}
7528 getRelatedTarget : function(selector, maxDepth, returnEl){
7530 return Ext.fly(this.relatedTarget).findParent(selector, maxDepth, returnEl);
7532 return returnEl ? Ext.get(this.relatedTarget) : this.relatedTarget;
7536 * Correctly scales a given wheel delta.
7537 * @param {Number} delta The delta value.
7539 correctWheelDelta : function (delta) {
7540 var scale = this.WHEEL_SCALE,
7541 ret = Math.round(delta / scale);
7543 if (!ret && delta) {
7544 ret = (delta < 0) ? -1 : 1; // don't allow non-zero deltas to go to zero!
7551 * Returns the mouse wheel deltas for this event.
7552 * @return {Object} An object with "x" and "y" properties holding the mouse wheel deltas.
7554 getWheelDeltas : function () {
7556 event = me.browserEvent,
7557 dx = 0, dy = 0; // the deltas
7559 if (Ext.isDefined(event.wheelDeltaX)) { // WebKit has both dimensions
7560 dx = event.wheelDeltaX;
7561 dy = event.wheelDeltaY;
7562 } else if (event.wheelDelta) { // old WebKit and IE
7563 dy = event.wheelDelta;
7564 } else if (event.detail) { // Gecko
7565 dy = -event.detail; // gecko is backwards
7567 // Gecko sometimes returns really big values if the user changes settings to
7568 // scroll a whole page per scroll
7571 } else if (dy < -100) {
7575 // Firefox 3.1 adds an axis field to the event to indicate direction of
7576 // scroll. See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events
7577 if (Ext.isDefined(event.axis) && event.axis === event.HORIZONTAL_AXIS) {
7584 x: me.correctWheelDelta(dx),
7585 y: me.correctWheelDelta(dy)
7590 * Normalizes mouse wheel y-delta across browsers. To get x-delta information, use
7591 * {@link #getWheelDeltas} instead.
7592 * @return {Number} The mouse wheel y-delta
7594 getWheelDelta : function(){
7595 var deltas = this.getWheelDeltas();
7601 * 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.
7602 * Example usage:<pre><code>
7603 // Handle click on any child of an element
7604 Ext.getBody().on('click', function(e){
7605 if(e.within('some-el')){
7606 alert('Clicked on a child of some-el!');
7610 // Handle click directly on an element, ignoring clicks on child nodes
7611 Ext.getBody().on('click', function(e,t){
7612 if((t.id == 'some-el') && !e.within(t, true)){
7613 alert('Clicked directly on some-el!');
7617 * @param {String/HTMLElement/Ext.Element} el The id, DOM element or Ext.Element to check
7618 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7619 * @param {Boolean} allowEl (optional) true to also check if the passed element is the target or related target
7622 within : function(el, related, allowEl){
7624 var t = related ? this.getRelatedTarget() : this.getTarget(),
7628 result = Ext.fly(el).contains(t);
7629 if (!result && allowEl) {
7630 result = t == Ext.getDom(el);
7639 * Checks if the key pressed was a "navigation" key
7640 * @return {Boolean} True if the press is a navigation keypress
7642 isNavKeyPress : function(){
7644 k = this.normalizeKey(me.keyCode);
7646 return (k >= 33 && k <= 40) || // Page Up/Down, End, Home, Left, Up, Right, Down
7653 * Checks if the key pressed was a "special" key
7654 * @return {Boolean} True if the press is a special keypress
7656 isSpecialKey : function(){
7657 var k = this.normalizeKey(this.keyCode);
7658 return (this.type == 'keypress' && this.ctrlKey) ||
7659 this.isNavKeyPress() ||
7660 (k == this.BACKSPACE) || // Backspace
7661 (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
7662 (k >= 44 && k <= 46); // Print Screen, Insert, Delete
7666 * Returns a point object that consists of the object coordinates.
7667 * @return {Ext.util.Point} point
7669 getPoint : function(){
7670 var xy = this.getXY();
7671 return Ext.create('Ext.util.Point', xy[0], xy[1]);
7675 * Returns true if the control, meta, shift or alt key was pressed during this event.
7678 hasModifier : function(){
7679 return this.ctrlKey || this.altKey || this.shiftKey || this.metaKey;
7683 * Injects a DOM event using the data in this object and (optionally) a new target.
7684 * This is a low-level technique and not likely to be used by application code. The
7685 * currently supported event types are:
7686 * <p><b>HTMLEvents</b></p>
7697 * <p><b>MouseEvents</b></p>
7701 * <li>mousedown</li>
7703 * <li>mouseover</li>
7704 * <li>mousemove</li>
7707 * <p><b>UIEvents</b></p>
7715 * @param {Ext.Element/HTMLElement} target (optional) If specified, the target for the event. This
7716 * is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}
7717 * is used to determine the target.
7719 injectEvent: function () {
7721 dispatchers = {}; // keyed by event type (e.g., 'mousedown')
7723 // Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html
7725 // IE9 has createEvent, but this code causes major problems with htmleditor (it
7726 // blocks all mouse events and maybe more). TODO
7728 if (!Ext.isIE && document.createEvent) { // if (DOM compliant)
7730 createHtmlEvent: function (doc, type, bubbles, cancelable) {
7731 var event = doc.createEvent('HTMLEvents');
7733 event.initEvent(type, bubbles, cancelable);
7737 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
7738 clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
7739 button, relatedTarget) {
7740 var event = doc.createEvent('MouseEvents'),
7741 view = doc.defaultView || window;
7743 if (event.initMouseEvent) {
7744 event.initMouseEvent(type, bubbles, cancelable, view, detail,
7745 clientX, clientY, clientX, clientY, ctrlKey, altKey,
7746 shiftKey, metaKey, button, relatedTarget);
7747 } else { // old Safari
7748 event = doc.createEvent('UIEvents');
7749 event.initEvent(type, bubbles, cancelable);
7751 event.detail = detail;
7752 event.screenX = clientX;
7753 event.screenY = clientY;
7754 event.clientX = clientX;
7755 event.clientY = clientY;
7756 event.ctrlKey = ctrlKey;
7757 event.altKey = altKey;
7758 event.metaKey = metaKey;
7759 event.shiftKey = shiftKey;
7760 event.button = button;
7761 event.relatedTarget = relatedTarget;
7767 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
7768 var event = doc.createEvent('UIEvents'),
7769 view = doc.defaultView || window;
7771 event.initUIEvent(type, bubbles, cancelable, view, detail);
7775 fireEvent: function (target, type, event) {
7776 target.dispatchEvent(event);
7779 fixTarget: function (target) {
7780 // Safari3 doesn't have window.dispatchEvent()
7781 if (target == window && !target.dispatchEvent) {
7788 } else if (document.createEventObject) { // else if (IE)
7789 var crazyIEButtons = { 0: 1, 1: 4, 2: 2 };
7792 createHtmlEvent: function (doc, type, bubbles, cancelable) {
7793 var event = doc.createEventObject();
7794 event.bubbles = bubbles;
7795 event.cancelable = cancelable;
7799 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
7800 clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
7801 button, relatedTarget) {
7802 var event = doc.createEventObject();
7803 event.bubbles = bubbles;
7804 event.cancelable = cancelable;
7805 event.detail = detail;
7806 event.screenX = clientX;
7807 event.screenY = clientY;
7808 event.clientX = clientX;
7809 event.clientY = clientY;
7810 event.ctrlKey = ctrlKey;
7811 event.altKey = altKey;
7812 event.shiftKey = shiftKey;
7813 event.metaKey = metaKey;
7814 event.button = crazyIEButtons[button] || button;
7815 event.relatedTarget = relatedTarget; // cannot assign to/fromElement
7819 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
7820 var event = doc.createEventObject();
7821 event.bubbles = bubbles;
7822 event.cancelable = cancelable;
7826 fireEvent: function (target, type, event) {
7827 target.fireEvent('on' + type, event);
7830 fixTarget: function (target) {
7831 if (target == document) {
7832 // IE6,IE7 thinks window==document and doesn't have window.fireEvent()
7833 // IE6,IE7 cannot properly call document.fireEvent()
7834 return document.documentElement;
7846 load: [false, false],
7847 unload: [false, false],
7848 select: [true, false],
7849 change: [true, false],
7850 submit: [true, true],
7851 reset: [true, false],
7852 resize: [true, false],
7853 scroll: [true, false]
7855 function (name, value) {
7856 var bubbles = value[0], cancelable = value[1];
7857 dispatchers[name] = function (targetEl, srcEvent) {
7858 var e = API.createHtmlEvent(name, bubbles, cancelable);
7859 API.fireEvent(targetEl, name, e);
7866 function createMouseEventDispatcher (type, detail) {
7867 var cancelable = (type != 'mousemove');
7868 return function (targetEl, srcEvent) {
7869 var xy = srcEvent.getXY(),
7870 e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,
7871 detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,
7872 srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,
7873 srcEvent.relatedTarget);
7874 API.fireEvent(targetEl, type, e);
7878 Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],
7879 function (eventName) {
7880 dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
7887 focusin: [true, false],
7888 focusout: [true, false],
7889 activate: [true, true],
7890 focus: [false, false],
7891 blur: [false, false]
7893 function (name, value) {
7894 var bubbles = value[0], cancelable = value[1];
7895 dispatchers[name] = function (targetEl, srcEvent) {
7896 var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
7897 API.fireEvent(targetEl, name, e);
7903 // not even sure what ancient browsers fall into this category...
7905 dispatchers = {}; // never mind all those we just built :P
7908 fixTarget: function (t) {
7914 function cannotInject (target, srcEvent) {
7916 // TODO log something
7920 return function (target) {
7922 dispatcher = dispatchers[me.type] || cannotInject,
7923 t = target ? (target.dom || target) : me.getTarget();
7925 t = API.fixTarget(t);
7928 }() // call to produce method
7932 Ext.EventObject = new Ext.EventObjectImpl();
7938 * @class Ext.Element
7942 activeElement = null,
7943 isCSS1 = doc.compatMode == "CSS1Compat",
7944 ELEMENT = Ext.Element,
7947 _fly = new Ext.Element.Flyweight();
7953 // If the browser does not support document.activeElement we need some assistance.
7954 // This covers old Safari 3.2 (4.0 added activeElement along with just about all
7955 // other browsers). We need this support to handle issues with old Safari.
7956 if (!('activeElement' in doc) && doc.addEventListener) {
7957 doc.addEventListener('focus',
7959 if (ev && ev.target) {
7960 activeElement = (ev.target == doc) ? null : ev.target;
7966 * Helper function to create the function that will restore the selection.
7968 function makeSelectionRestoreFn (activeEl, start, end) {
7969 return function () {
7970 activeEl.selectionStart = start;
7971 activeEl.selectionEnd = end;
7975 Ext.apply(ELEMENT, {
7976 isAncestor : function(p, c) {
7983 return p.contains(c);
7984 } else if (p.compareDocumentPosition) {
7985 return !!(p.compareDocumentPosition(c) & 16);
7987 while ((c = c.parentNode)) {
7988 ret = c == p || ret;
7996 * Returns the active element in the DOM. If the browser supports activeElement
7997 * on the document, this is returned. If not, the focus is tracked and the active
7998 * element is maintained internally.
7999 * @return {HTMLElement} The active (focused) element in the document.
8001 getActiveElement: function () {
8002 return doc.activeElement || activeElement;
8006 * Creates a function to call to clean up problems with the work-around for the
8007 * WebKit RightMargin bug. The work-around is to add "display: 'inline-block'" to
8008 * the element before calling getComputedStyle and then to restore its original
8009 * display value. The problem with this is that it corrupts the selection of an
8010 * INPUT or TEXTAREA element (as in the "I-beam" goes away but ths focus remains).
8011 * To cleanup after this, we need to capture the selection of any such element and
8012 * then restore it after we have restored the display style.
8014 * @param target {Element} The top-most element being adjusted.
8017 getRightMarginFixCleaner: function (target) {
8018 var supports = Ext.supports,
8019 hasInputBug = supports.DisplayChangeInputSelectionBug,
8020 hasTextAreaBug = supports.DisplayChangeTextAreaSelectionBug;
8022 if (hasInputBug || hasTextAreaBug) {
8023 var activeEl = doc.activeElement || activeElement, // save a call
8024 tag = activeEl && activeEl.tagName,
8028 if ((hasTextAreaBug && tag == 'TEXTAREA') ||
8029 (hasInputBug && tag == 'INPUT' && activeEl.type == 'text')) {
8030 if (ELEMENT.isAncestor(target, activeEl)) {
8031 start = activeEl.selectionStart;
8032 end = activeEl.selectionEnd;
8034 if (Ext.isNumber(start) && Ext.isNumber(end)) { // to be safe...
8035 // We don't create the raw closure here inline because that
8036 // will be costly even if we don't want to return it (nested
8037 // function decls and exprs are often instantiated on entry
8038 // regardless of whether execution ever reaches them):
8039 return makeSelectionRestoreFn(activeEl, start, end);
8045 return Ext.emptyFn; // avoid special cases, just return a nop
8048 getViewWidth : function(full) {
8049 return full ? ELEMENT.getDocumentWidth() : ELEMENT.getViewportWidth();
8052 getViewHeight : function(full) {
8053 return full ? ELEMENT.getDocumentHeight() : ELEMENT.getViewportHeight();
8056 getDocumentHeight: function() {
8057 return Math.max(!isCSS1 ? doc.body.scrollHeight : doc.documentElement.scrollHeight, ELEMENT.getViewportHeight());
8060 getDocumentWidth: function() {
8061 return Math.max(!isCSS1 ? doc.body.scrollWidth : doc.documentElement.scrollWidth, ELEMENT.getViewportWidth());
8064 getViewportHeight: function(){
8066 (Ext.isStrict ? doc.documentElement.clientHeight : doc.body.clientHeight) :
8070 getViewportWidth : function() {
8071 return (!Ext.isStrict && !Ext.isOpera) ? doc.body.clientWidth :
8072 Ext.isIE ? doc.documentElement.clientWidth : self.innerWidth;
8075 getY : function(el) {
8076 return ELEMENT.getXY(el)[1];
8079 getX : function(el) {
8080 return ELEMENT.getXY(el)[0];
8083 getOffsetParent: function (el) {
8084 el = Ext.getDom(el);
8086 // accessing offsetParent can throw "Unspecified Error" in IE6-8 (not 9)
8087 return el.offsetParent;
8089 var body = document.body; // safe bet, unless...
8090 return (el == body) ? null : body;
8094 getXY : function(el) {
8105 bd = (doc.body || doc.documentElement),
8108 el = Ext.getDom(el);
8111 hasAbsolute = fly(el).isStyle("position", "absolute");
8113 if (el.getBoundingClientRect) {
8115 b = el.getBoundingClientRect();
8116 scroll = fly(document).getScroll();
8117 ret = [ Math.round(b.left + scroll.left), Math.round(b.top + scroll.top) ];
8119 // IE6-8 can also throw from getBoundingClientRect...
8124 for (p = el; p; p = ELEMENT.getOffsetParent(p)) {
8129 hasAbsolute = hasAbsolute || pe.isStyle("position", "absolute");
8132 y += bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
8133 x += bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
8135 if (p != el && !pe.isStyle('overflow','visible')) {
8142 if (Ext.isSafari && hasAbsolute) {
8147 if (Ext.isGecko && !hasAbsolute) {
8149 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
8150 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
8154 while (p && p != bd) {
8155 if (!Ext.isOpera || (p.tagName != 'TR' && !fly(p).isStyle("display", "inline"))) {
8164 return ret || [0,0];
8167 setXY : function(el, xy) {
8168 (el = Ext.fly(el, '_setXY')).position();
8170 var pts = el.translatePoints(xy),
8171 style = el.dom.style,
8175 if (!isNaN(pts[pos])) {
8176 style[pos] = pts[pos] + "px";
8181 setX : function(el, x) {
8182 ELEMENT.setXY(el, [x, false]);
8185 setY : function(el, y) {
8186 ELEMENT.setXY(el, [false, y]);
8190 * Serializes a DOM form into a url encoded string
8191 * @param {Object} form The form
8192 * @return {String} The url encoded form
8194 serializeForm: function(form) {
8195 var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements,
8197 encoder = encodeURIComponent,
8203 Ext.each(fElements, function(element){
8204 name = element.name;
8205 type = element.type;
8207 if (!element.disabled && name) {
8208 if (/select-(one|multiple)/i.test(type)) {
8209 Ext.each(element.options, function(opt){
8211 hasValue = opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttributeNode('value').specified;
8212 data += Ext.String.format("{0}={1}&", encoder(name), encoder(hasValue ? opt.value : opt.text));
8215 } else if (!(/file|undefined|reset|button/i.test(type))) {
8216 if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) {
8217 data += encoder(name) + '=' + encoder(element.value) + '&';
8218 hasSubmit = /submit/i.test(type);
8223 return data.substr(0, data.length - 1);
8229 * @class Ext.Element
8232 Ext.Element.addMethods((function(){
8233 var focusRe = /button|input|textarea|select|object/;
8236 * Monitors this Element for the mouse leaving. Calls the function after the specified delay only if
8237 * the mouse was not moved back into the Element within the delay. If the mouse <i>was</i> moved
8238 * back in, the function is not called.
8239 * @param {Number} delay The delay <b>in milliseconds</b> to wait for possible mouse re-entry before calling the handler function.
8240 * @param {Function} handler The function to call if the mouse remains outside of this Element for the specified time.
8241 * @param {Object} scope The scope (<code>this</code> reference) in which the handler function executes. Defaults to this Element.
8242 * @return {Object} The listeners object which was added to this element so that monitoring can be stopped. Example usage:<pre><code>
8243 // Hide the menu if the mouse moves out for 250ms or more
8244 this.mouseLeaveMonitor = this.menuEl.monitorMouseLeave(250, this.hideMenu, this);
8247 // Remove mouseleave monitor on menu destroy
8248 this.menuEl.un(this.mouseLeaveMonitor);
8251 monitorMouseLeave: function(delay, handler, scope) {
8255 mouseleave: function(e) {
8256 timer = setTimeout(Ext.Function.bind(handler, scope||me, [e]), delay);
8258 mouseenter: function() {
8259 clearTimeout(timer);
8269 * Stops the specified event(s) from bubbling and optionally prevents the default action
8270 * @param {String/String[]} eventName an event / array of events to stop from bubbling
8271 * @param {Boolean} preventDefault (optional) true to prevent the default action too
8272 * @return {Ext.Element} this
8274 swallowEvent : function(eventName, preventDefault) {
8277 e.stopPropagation();
8278 if (preventDefault) {
8283 if (Ext.isArray(eventName)) {
8284 Ext.each(eventName, function(e) {
8289 me.on(eventName, fn);
8294 * Create an event handler on this element such that when the event fires and is handled by this element,
8295 * it will be relayed to another object (i.e., fired again as if it originated from that object instead).
8296 * @param {String} eventName The type of event to relay
8297 * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
8298 * for firing the relayed event
8300 relayEvent : function(eventName, observable) {
8301 this.on(eventName, function(e) {
8302 observable.fireEvent(eventName, e);
8307 * Removes Empty, or whitespace filled text nodes. Combines adjacent text nodes.
8308 * @param {Boolean} forceReclean (optional) By default the element
8309 * keeps track if it has been cleaned already so
8310 * you can call this over and over. However, if you update the element and
8311 * need to force a reclean, you can pass true.
8313 clean : function(forceReclean) {
8320 if (Ext.Element.data(dom, 'isCleaned') && forceReclean !== true) {
8326 if (n.nodeType == 3) {
8327 // Remove empty/whitespace text nodes
8328 if (!(/\S/.test(n.nodeValue))) {
8330 // Combine adjacent text nodes
8331 } else if (nx && nx.nodeType == 3) {
8332 n.appendData(Ext.String.trim(nx.data));
8333 dom.removeChild(nx);
8338 // Recursively clean
8345 Ext.Element.data(dom, 'isCleaned', true);
8350 * Direct access to the Ext.ElementLoader {@link Ext.ElementLoader#load} method. The method takes the same object
8351 * parameter as {@link Ext.ElementLoader#load}
8352 * @return {Ext.Element} this
8354 load : function(options) {
8355 this.getLoader().load(options);
8360 * Gets this element's {@link Ext.ElementLoader ElementLoader}
8361 * @return {Ext.ElementLoader} The loader
8363 getLoader : function() {
8365 data = Ext.Element.data,
8366 loader = data(dom, 'loader');
8369 loader = Ext.create('Ext.ElementLoader', {
8372 data(dom, 'loader', loader);
8378 * Update the innerHTML of this element, optionally searching for and processing scripts
8379 * @param {String} html The new HTML
8380 * @param {Boolean} [loadScripts=false] True to look for and process scripts
8381 * @param {Function} [callback] For async script loading you can be notified when the update completes
8382 * @return {Ext.Element} this
8384 update : function(html, loadScripts, callback) {
8396 if (loadScripts !== true) {
8397 dom.innerHTML = html;
8398 Ext.callback(callback, me);
8403 html += '<span id="' + id + '"></span>';
8405 interval = setInterval(function(){
8406 if (!document.getElementById(id)) {
8409 clearInterval(interval);
8411 hd = DOC.getElementsByTagName("head")[0],
8412 re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
8413 srcRe = /\ssrc=([\'\"])(.*?)\1/i,
8414 typeRe = /\stype=([\'\"])(.*?)\1/i,
8422 while ((match = re.exec(html))) {
8424 srcMatch = attrs ? attrs.match(srcRe) : false;
8425 if (srcMatch && srcMatch[2]) {
8426 s = DOC.createElement("script");
8427 s.src = srcMatch[2];
8428 typeMatch = attrs.match(typeRe);
8429 if (typeMatch && typeMatch[2]) {
8430 s.type = typeMatch[2];
8433 } else if (match[2] && match[2].length > 0) {
8434 if (window.execScript) {
8435 window.execScript(match[2]);
8437 window.eval(match[2]);
8442 el = DOC.getElementById(id);
8446 Ext.callback(callback, me);
8448 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, '');
8452 // inherit docs, overridden so we can add removeAnchor
8453 removeAllListeners : function() {
8454 this.removeAnchor();
8455 Ext.EventManager.removeAll(this.dom);
8460 * Gets the parent node of the current element taking into account Ext.scopeResetCSS
8462 * @return {HTMLElement} The parent element
8464 getScopeParent: function(){
8465 var parent = this.dom.parentNode;
8466 return Ext.scopeResetCSS ? parent.parentNode : parent;
8470 * Creates a proxy element of this element
8471 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8472 * @param {String/HTMLElement} [renderTo] The element or element id to render the proxy to (defaults to document.body)
8473 * @param {Boolean} [matchBox=false] True to align and size the proxy to this element now.
8474 * @return {Ext.Element} The new proxy element
8476 createProxy : function(config, renderTo, matchBox) {
8477 config = (typeof config == 'object') ? config : {tag : "div", cls: config};
8480 proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) :
8481 Ext.DomHelper.insertBefore(me.dom, config, true);
8483 proxy.setVisibilityMode(Ext.Element.DISPLAY);
8485 if (matchBox && me.setBox && me.getBox) { // check to make sure Element.position.js is loaded
8486 proxy.setBox(me.getBox());
8492 * Checks whether this element can be focused.
8493 * @return {Boolean} True if the element is focusable
8495 focusable: function(){
8497 nodeName = dom.nodeName.toLowerCase(),
8499 hasTabIndex = !isNaN(dom.tabIndex);
8501 if (!dom.disabled) {
8502 if (focusRe.test(nodeName)) {
8505 canFocus = nodeName == 'a' ? dom.href || hasTabIndex : hasTabIndex;
8508 return canFocus && this.isVisible(true);
8512 Ext.Element.prototype.clearListeners = Ext.Element.prototype.removeAllListeners;
8515 * @class Ext.Element
8517 Ext.Element.addMethods({
8519 * Gets the x,y coordinates specified by the anchor position on the element.
8520 * @param {String} [anchor='c'] The specified anchor position. See {@link #alignTo}
8521 * for details on supported anchor positions.
8522 * @param {Boolean} [local] True to get the local (element top/left-relative) anchor position instead
8523 * of page coordinates
8524 * @param {Object} [size] An object containing the size to use for calculating anchor position
8525 * {width: (target width), height: (target height)} (defaults to the element's current size)
8526 * @return {Number[]} [x, y] An array containing the element's x and y coordinates
8528 getAnchorXY : function(anchor, local, s){
8529 //Passing a different size is useful for pre-calculating anchors,
8530 //especially for anchored animations that change the el size.
8531 anchor = (anchor || "tl").toLowerCase();
8535 vp = me.dom == document.body || me.dom == document,
8536 w = s.width || vp ? Ext.Element.getViewWidth() : me.getWidth(),
8537 h = s.height || vp ? Ext.Element.getViewHeight() : me.getHeight(),
8541 scroll = me.getScroll(),
8542 extraX = vp ? scroll.left : !local ? o[0] : 0,
8543 extraY = vp ? scroll.top : !local ? o[1] : 0,
8545 c : [r(w * 0.5), r(h * 0.5)],
8546 t : [r(w * 0.5), 0],
8547 l : [0, r(h * 0.5)],
8548 r : [w, r(h * 0.5)],
8549 b : [r(w * 0.5), h],
8557 return [xy[0] + extraX, xy[1] + extraY];
8561 * Anchors an element to another element and realigns it when the window is resized.
8562 * @param {String/HTMLElement/Ext.Element} element The element to align to.
8563 * @param {String} position The position to align to.
8564 * @param {Number[]} [offsets] Offset the positioning by [x, y]
8565 * @param {Boolean/Object} [animate] True for the default animation or a standard Element animation config object
8566 * @param {Boolean/Number} [monitorScroll] True to monitor body scroll and reposition. If this parameter
8567 * is a number, it is used as the buffer delay (defaults to 50ms).
8568 * @param {Function} [callback] The function to call after the animation finishes
8569 * @return {Ext.Element} this
8571 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8574 scroll = !Ext.isEmpty(monitorScroll),
8575 action = function(){
8576 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
8577 Ext.callback(callback, Ext.fly(dom));
8579 anchor = this.getAnchor();
8581 // previous listener anchor, remove it
8582 this.removeAnchor();
8588 Ext.EventManager.onWindowResize(action, null);
8591 Ext.EventManager.on(window, 'scroll', action, null,
8592 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
8594 action.call(me); // align immediately
8599 * Remove any anchor to this element. See {@link #anchorTo}.
8600 * @return {Ext.Element} this
8602 removeAnchor : function(){
8604 anchor = this.getAnchor();
8606 if(anchor && anchor.fn){
8607 Ext.EventManager.removeResizeListener(anchor.fn);
8609 Ext.EventManager.un(window, 'scroll', anchor.fn);
8617 getAnchor : function(){
8618 var data = Ext.Element.data,
8623 var anchor = data(dom, '_anchor');
8626 anchor = data(dom, '_anchor', {});
8631 getAlignVector: function(el, spec, offset) {
8633 side = {t:"top", l:"left", r:"right", b: "bottom"},
8634 thisRegion = me.getRegion(),
8641 sourceClass: 'Ext.Element',
8642 sourceMethod: 'getAlignVector',
8643 msg: 'Attempted to align an element that doesn\'t exist'
8648 elRegion = el.getRegion();
8652 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8653 * supported position values.
8654 * @param {String/HTMLElement/Ext.Element} element The element to align to.
8655 * @param {String} [position="tl-bl?"] The position to align to (defaults to )
8656 * @param {Number[]} [offsets] Offset the positioning by [x, y]
8657 * @return {Number[]} [x, y]
8659 getAlignToXY : function(el, p, o){
8665 sourceClass: 'Ext.Element',
8666 sourceMethod: 'getAlignToXY',
8667 msg: 'Attempted to align an element that doesn\'t exist'
8673 p = (!p || p == "?" ? "tl-bl?" : (!(/-/).test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();
8681 //constrain the aligned el to viewport if necessary
8685 dw = Ext.Element.getViewWidth() -10, // 10px of margin for ie
8686 dh = Ext.Element.getViewHeight()-10, // 10px of margin for ie
8694 docElement = doc.documentElement,
8696 scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
8697 scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
8698 c = false, //constrain to viewport
8701 m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8706 sourceClass: 'Ext.Element',
8707 sourceMethod: 'getAlignToXY',
8711 msg: 'Attemmpted to align an element with an invalid position: "' + p + '"'
8720 //Subtract the aligned el's internal xy from the target's offset xy
8721 //plus custom offset to get the aligned el's new offset xy
8722 a1 = me.getAnchorXY(p1, true);
8723 a2 = el.getAnchorXY(p2, false);
8725 x = a2[0] - a1[0] + o[0];
8726 y = a2[1] - a1[1] + o[1];
8732 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8733 //perpendicular to the vp border, allow the aligned el to slide on that border,
8734 //otherwise swap the aligned el to the opposite border of the target.
8736 p1x = p1.charAt(p1.length-1);
8738 p2x = p2.charAt(p2.length-1);
8739 swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8740 swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8743 if (x + w > dw + scrollX) {
8744 x = swapX ? r.left-w : dw+scrollX-w;
8747 x = swapX ? r.right : scrollX;
8749 if (y + h > dh + scrollY) {
8750 y = swapY ? r.top-h : dh+scrollY-h;
8753 y = swapY ? r.bottom : scrollY;
8760 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8761 * document it aligns it to the viewport.
8762 * The position parameter is optional, and can be specified in any one of the following formats:
8764 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8765 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8766 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8767 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8768 * <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
8769 * element's anchor point, and the second value is used as the target's anchor point.</li>
8771 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8772 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8773 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8774 * that specified in order to enforce the viewport constraints.
8775 * Following are all of the supported anchor positions:
8778 ----- -----------------------------
8779 tl The top left corner (default)
8780 t The center of the top edge
8781 tr The top right corner
8782 l The center of the left edge
8783 c In the center of the element
8784 r The center of the right edge
8785 bl The bottom left corner
8786 b The center of the bottom edge
8787 br The bottom right corner
8791 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8792 el.alignTo("other-el");
8794 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8795 el.alignTo("other-el", "tr?");
8797 // align the bottom right corner of el with the center left edge of other-el
8798 el.alignTo("other-el", "br-l?");
8800 // align the center of el with the bottom left corner of other-el and
8801 // adjust the x position by -6 pixels (and the y position by 0)
8802 el.alignTo("other-el", "c-bl", [-6, 0]);
8804 * @param {String/HTMLElement/Ext.Element} element The element to align to.
8805 * @param {String} [position="tl-bl?"] The position to align to
8806 * @param {Number[]} [offsets] Offset the positioning by [x, y]
8807 * @param {Boolean/Object} [animate] true for the default animation or a standard Element animation config object
8808 * @return {Ext.Element} this
8810 alignTo : function(element, position, offsets, animate){
8812 return me.setXY(me.getAlignToXY(element, position, offsets),
8813 me.anim && !!animate ? me.anim(animate) : false);
8816 // private ==> used outside of core
8817 adjustForConstraints : function(xy, parent) {
8818 var vector = this.getConstrainVector(parent, xy);
8827 * <p>Returns the <code>[X, Y]</code> vector by which this element must be translated to make a best attempt
8828 * to constrain within the passed constraint. Returns <code>false</code> is this element does not need to be moved.</p>
8829 * <p>Priority is given to constraining the top and left within the constraint.</p>
8830 * <p>The constraint may either be an existing element into which this element is to be constrained, or
8831 * an {@link Ext.util.Region Region} into which this element is to be constrained.</p>
8832 * @param constrainTo {Mixed} The Element or {@link Ext.util.Region Region} into which this element is to be constrained.
8833 * @param proposedPosition {Array} A proposed <code>[X, Y]</code> position to test for validity and to produce a vector for instead
8834 * of using this Element's current position;
8835 * @returns {Number[]/Boolean} <b>If</b> this element <i>needs</i> to be translated, an <code>[X, Y]</code>
8836 * vector by which this element must be translated. Otherwise, <code>false</code>.
8838 getConstrainVector: function(constrainTo, proposedPosition) {
8839 if (!(constrainTo instanceof Ext.util.Region)) {
8840 constrainTo = Ext.get(constrainTo).getViewRegion();
8842 var thisRegion = this.getRegion(),
8844 shadowSize = this.shadow && this.shadow.offset,
8847 // Shift this region to occupy the proposed position
8848 if (proposedPosition) {
8849 thisRegion.translateBy(proposedPosition[0] - thisRegion.x, proposedPosition[1] - thisRegion.y);
8852 // Reduce the constrain region to allow for shadow
8853 // TODO: Rewrite the Shadow class. When that's done, get the extra for each side from the Shadow.
8855 constrainTo.adjust(0, -shadowSize, -shadowSize, shadowSize);
8858 // Constrain the X coordinate by however much this Element overflows
8859 if (thisRegion.right > constrainTo.right) {
8861 vector[0] = (constrainTo.right - thisRegion.right); // overflowed the right
8863 if (thisRegion.left + vector[0] < constrainTo.left) {
8865 vector[0] = (constrainTo.left - thisRegion.left); // overflowed the left
8868 // Constrain the Y coordinate by however much this Element overflows
8869 if (thisRegion.bottom > constrainTo.bottom) {
8871 vector[1] = (constrainTo.bottom - thisRegion.bottom); // overflowed the bottom
8873 if (thisRegion.top + vector[1] < constrainTo.top) {
8875 vector[1] = (constrainTo.top - thisRegion.top); // overflowed the top
8877 return overflowed ? vector : false;
8881 * Calculates the x, y to center this element on the screen
8882 * @return {Number[]} The x, y values [x, y]
8884 getCenterXY : function(){
8885 return this.getAlignToXY(document, 'c-c');
8889 * Centers the Element in either the viewport, or another Element.
8890 * @param {String/HTMLElement/Ext.Element} centerIn (optional) The element in which to center the element.
8892 center : function(centerIn){
8893 return this.alignTo(centerIn || document, 'c-c');
8898 * @class Ext.Element
8902 var ELEMENT = Ext.Element,
8907 POSITION = "position",
8909 RELATIVE = "relative",
8913 Ext.override(Ext.Element, {
8915 * 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).
8916 * @return {Number} The X position of the element
8919 return ELEMENT.getX(this.dom);
8923 * 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).
8924 * @return {Number} The Y position of the element
8927 return ELEMENT.getY(this.dom);
8931 * 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).
8932 * @return {Number[]} The XY position of the element
8935 return ELEMENT.getXY(this.dom);
8939 * 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.
8940 * @param {String/HTMLElement/Ext.Element} element The element to get the offsets from.
8941 * @return {Number[]} The XY page offsets (e.g. [100, -200])
8943 getOffsetsTo : function(el){
8944 var o = this.getXY(),
8945 e = Ext.fly(el, '_internal').getXY();
8946 return [o[0]-e[0],o[1]-e[1]];
8950 * 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).
8951 * @param {Number} The X position of the element
8952 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8953 * @return {Ext.Element} this
8955 setX : function(x, animate){
8956 return this.setXY([x, this.getY()], animate);
8960 * 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).
8961 * @param {Number} The Y position of the element
8962 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8963 * @return {Ext.Element} this
8965 setY : function(y, animate){
8966 return this.setXY([this.getX(), y], animate);
8970 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8971 * @param {String} left The left CSS property value
8972 * @return {Ext.Element} this
8974 setLeft : function(left){
8975 this.setStyle(LEFT, this.addUnits(left));
8980 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8981 * @param {String} top The top CSS property value
8982 * @return {Ext.Element} this
8984 setTop : function(top){
8985 this.setStyle(TOP, this.addUnits(top));
8990 * Sets the element's CSS right style.
8991 * @param {String} right The right CSS property value
8992 * @return {Ext.Element} this
8994 setRight : function(right){
8995 this.setStyle(RIGHT, this.addUnits(right));
9000 * Sets the element's CSS bottom style.
9001 * @param {String} bottom The bottom CSS property value
9002 * @return {Ext.Element} this
9004 setBottom : function(bottom){
9005 this.setStyle(BOTTOM, this.addUnits(bottom));
9010 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9011 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9012 * @param {Number[]} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
9013 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9014 * @return {Ext.Element} this
9016 setXY: function(pos, animate) {
9018 if (!animate || !me.anim) {
9019 ELEMENT.setXY(me.dom, pos);
9022 if (!Ext.isObject(animate)) {
9025 me.animate(Ext.applyIf({ to: { x: pos[0], y: pos[1] } }, animate));
9031 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9032 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9033 * @param {Number} x X value for new position (coordinates are page-based)
9034 * @param {Number} y Y value for new position (coordinates are page-based)
9035 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9036 * @return {Ext.Element} this
9038 setLocation : function(x, y, animate){
9039 return this.setXY([x, y], animate);
9043 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
9044 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
9045 * @param {Number} x X value for new position (coordinates are page-based)
9046 * @param {Number} y Y value for new position (coordinates are page-based)
9047 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
9048 * @return {Ext.Element} this
9050 moveTo : function(x, y, animate){
9051 return this.setXY([x, y], animate);
9055 * Gets the left X coordinate
9056 * @param {Boolean} local True to get the local css position instead of page coordinate
9059 getLeft : function(local){
9060 return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
9064 * Gets the right X coordinate of the element (element X position + element width)
9065 * @param {Boolean} local True to get the local css position instead of page coordinate
9068 getRight : function(local){
9070 return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
9074 * Gets the top Y coordinate
9075 * @param {Boolean} local True to get the local css position instead of page coordinate
9078 getTop : function(local) {
9079 return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
9083 * Gets the bottom Y coordinate of the element (element Y position + element height)
9084 * @param {Boolean} local True to get the local css position instead of page coordinate
9087 getBottom : function(local){
9089 return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
9093 * Initializes positioning on this element. If a desired position is not passed, it will make the
9094 * the element positioned relative IF it is not already positioned.
9095 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9096 * @param {Number} zIndex (optional) The zIndex to apply
9097 * @param {Number} x (optional) Set the page X position
9098 * @param {Number} y (optional) Set the page Y position
9100 position : function(pos, zIndex, x, y) {
9103 if (!pos && me.isStyle(POSITION, STATIC)){
9104 me.setStyle(POSITION, RELATIVE);
9106 me.setStyle(POSITION, pos);
9109 me.setStyle(ZINDEX, zIndex);
9112 me.setXY([x || false, y || false]);
9117 * Clear positioning back to the default when the document was loaded
9118 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9119 * @return {Ext.Element} this
9121 clearPositioning : function(value){
9122 value = value || '';
9135 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9136 * snapshot before performing an update and then restoring the element.
9139 getPositioning : function(){
9140 var l = this.getStyle(LEFT);
9141 var t = this.getStyle(TOP);
9143 "position" : this.getStyle(POSITION),
9145 "right" : l ? "" : this.getStyle(RIGHT),
9147 "bottom" : t ? "" : this.getStyle(BOTTOM),
9148 "z-index" : this.getStyle(ZINDEX)
9153 * Set positioning with an object returned by getPositioning().
9154 * @param {Object} posCfg
9155 * @return {Ext.Element} this
9157 setPositioning : function(pc){
9159 style = me.dom.style;
9163 if(pc.right == AUTO){
9166 if(pc.bottom == AUTO){
9174 * Translates the passed page coordinates into left/top css values for this element
9175 * @param {Number/Number[]} x The page x or an array containing [x, y]
9176 * @param {Number} y (optional) The page y, required if x is not an array
9177 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9179 translatePoints: function(x, y) {
9180 if (Ext.isArray(x)) {
9185 relative = me.isStyle(POSITION, RELATIVE),
9187 left = parseInt(me.getStyle(LEFT), 10),
9188 top = parseInt(me.getStyle(TOP), 10);
9190 if (!Ext.isNumber(left)) {
9191 left = relative ? 0 : me.dom.offsetLeft;
9193 if (!Ext.isNumber(top)) {
9194 top = relative ? 0 : me.dom.offsetTop;
9196 left = (Ext.isNumber(x)) ? x - o[0] + left : undefined;
9197 top = (Ext.isNumber(y)) ? y - o[1] + top : undefined;
9205 * 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.
9206 * @param {Object} box The box to fill {x, y, width, height}
9207 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9208 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9209 * @return {Ext.Element} this
9211 setBox: function(box, adjust, animate) {
9215 if ((adjust && !me.autoBoxAdjust) && !me.isBorderBox()) {
9216 w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
9217 h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
9219 me.setBounds(box.x, box.y, w, h, animate);
9224 * Return an object defining the area of this Element which can be passed to {@link #setBox} to
9225 * set another Element's size/location to match this element.
9226 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9227 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9228 * @return {Object} box An object in the format<pre><code>
9230 x: <Element's X position>,
9231 y: <Element's Y position>,
9232 width: <Element's width>,
9233 height: <Element's height>,
9234 bottom: <Element's lower bound>,
9235 right: <Element's rightmost bound>
9238 * The returned object may also be addressed as an Array where index 0 contains the X position
9239 * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
9241 getBox: function(contentBox, local) {
9246 getBorderWidth = me.getBorderWidth,
9247 getPadding = me.getPadding,
9248 l, r, t, b, w, h, bx;
9252 left = parseInt(me.getStyle("left"), 10) || 0;
9253 top = parseInt(me.getStyle("top"), 10) || 0;
9268 l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");
9269 r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");
9270 t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");
9271 b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");
9281 bx.right = bx.x + bx.width;
9282 bx.bottom = bx.y + bx.height;
9287 * Move this element relative to its current position.
9288 * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
9289 * @param {Number} distance How far to move the element in pixels
9290 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9292 move: function(direction, distance, animate) {
9297 left = [x - distance, y],
9298 right = [x + distance, y],
9299 top = [x, y - distance],
9300 bottom = [x, y + distance],
9314 direction = direction.toLowerCase();
9315 me.moveTo(hash[direction][0], hash[direction][1], animate);
9319 * Quick set left and top adding default units
9320 * @param {String} left The left CSS property value
9321 * @param {String} top The top CSS property value
9322 * @return {Ext.Element} this
9324 setLeftTop: function(left, top) {
9326 style = me.dom.style;
9327 style.left = me.addUnits(left);
9328 style.top = me.addUnits(top);
9333 * Returns the region of this element.
9334 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
9335 * @return {Ext.util.Region} A Region containing "top, left, bottom, right" member data.
9337 getRegion: function() {
9338 return this.getPageBox(true);
9342 * Returns the <b>content</b> region of this element. That is the region within the borders and padding.
9343 * @return {Ext.util.Region} A Region containing "top, left, bottom, right" member data.
9345 getViewRegion: function() {
9347 isBody = me.dom === document.body,
9348 scroll, pos, top, left, width, height;
9350 // For the body we want to do some special logic
9352 scroll = me.getScroll();
9355 width = Ext.Element.getViewportWidth();
9356 height = Ext.Element.getViewportHeight();
9360 left = pos[0] + me.getBorderWidth('l') + me.getPadding('l');
9361 top = pos[1] + me.getBorderWidth('t') + me.getPadding('t');
9362 width = me.getWidth(true);
9363 height = me.getHeight(true);
9366 return Ext.create('Ext.util.Region', top, left + width, top + height, left);
9370 * Return an object defining the area of this Element which can be passed to {@link #setBox} to
9371 * set another Element's size/location to match this element.
9372 * @param {Boolean} asRegion(optional) If true an Ext.util.Region will be returned
9373 * @return {Object} box An object in the format<pre><code>
9375 x: <Element's X position>,
9376 y: <Element's Y position>,
9377 width: <Element's width>,
9378 height: <Element's height>,
9379 bottom: <Element's lower bound>,
9380 right: <Element's rightmost bound>
9383 * The returned object may also be addressed as an Array where index 0 contains the X position
9384 * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
9386 getPageBox : function(getRegion) {
9389 isDoc = el === document.body,
9390 w = isDoc ? Ext.Element.getViewWidth() : el.offsetWidth,
9391 h = isDoc ? Ext.Element.getViewHeight() : el.offsetHeight,
9399 return Ext.create('Ext.util.Region', t, r, b, l);
9414 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9415 * @param {Number} x X value for new position (coordinates are page-based)
9416 * @param {Number} y Y value for new position (coordinates are page-based)
9417 * @param {Number/String} width The new width. This may be one of:<div class="mdetail-params"><ul>
9418 * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>
9419 * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
9421 * @param {Number/String} height The new height. This may be one of:<div class="mdetail-params"><ul>
9422 * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>
9423 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
9425 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9426 * @return {Ext.Element} this
9428 setBounds: function(x, y, width, height, animate) {
9430 if (!animate || !me.anim) {
9431 me.setSize(width, height);
9432 me.setLocation(x, y);
9434 if (!Ext.isObject(animate)) {
9437 me.animate(Ext.applyIf({
9441 width: me.adjustWidth(width),
9442 height: me.adjustHeight(height)
9450 * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.
9451 * @param {Ext.util.Region} region The region to fill
9452 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9453 * @return {Ext.Element} this
9455 setRegion: function(region, animate) {
9456 return this.setBounds(region.left, region.top, region.right - region.left, region.bottom - region.top, animate);
9462 * @class Ext.Element
9464 Ext.override(Ext.Element, {
9466 * Returns true if this element is scrollable.
9469 isScrollable : function(){
9471 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9475 * Returns the current scroll position of the element.
9476 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9478 getScroll : function() {
9482 docElement = doc.documentElement,
9487 if (d == doc || d == body) {
9488 if (Ext.isIE && Ext.isStrict) {
9489 l = docElement.scrollLeft;
9490 t = docElement.scrollTop;
9492 l = window.pageXOffset;
9493 t = window.pageYOffset;
9496 left: l || (body ? body.scrollLeft : 0),
9497 top : t || (body ? body.scrollTop : 0)
9510 * 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().
9511 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9512 * @param {Number} value The new scroll value
9513 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9514 * @return {Ext.Element} this
9516 scrollTo : function(side, value, animate) {
9517 //check if we're scrolling top or left
9518 var top = /top/i.test(side),
9523 if (!animate || !me.anim) {
9524 // just setting the value, so grab the direction
9525 prop = 'scroll' + (top ? 'Top' : 'Left');
9529 if (!Ext.isObject(animate)) {
9532 obj['scroll' + (top ? 'Top' : 'Left')] = value;
9533 me.animate(Ext.applyIf({
9541 * Scrolls this element into view within the passed container.
9542 * @param {String/HTMLElement/Ext.Element} container (optional) The container element to scroll (defaults to document.body). Should be a
9543 * string (id), dom node, or Ext.Element.
9544 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
9545 * @return {Ext.Element} this
9547 scrollIntoView : function(container, hscroll) {
9548 container = Ext.getDom(container) || Ext.getBody().dom;
9550 offsets = this.getOffsetsTo(container),
9552 left = offsets[0] + container.scrollLeft,
9553 top = offsets[1] + container.scrollTop,
9554 bottom = top + el.offsetHeight,
9555 right = left + el.offsetWidth,
9557 ctClientHeight = container.clientHeight,
9558 ctScrollTop = parseInt(container.scrollTop, 10),
9559 ctScrollLeft = parseInt(container.scrollLeft, 10),
9560 ctBottom = ctScrollTop + ctClientHeight,
9561 ctRight = ctScrollLeft + container.clientWidth;
9563 if (el.offsetHeight > ctClientHeight || top < ctScrollTop) {
9564 container.scrollTop = top;
9565 } else if (bottom > ctBottom) {
9566 container.scrollTop = bottom - ctClientHeight;
9568 // corrects IE, other browsers will ignore
9569 container.scrollTop = container.scrollTop;
9571 if (hscroll !== false) {
9572 if (el.offsetWidth > container.clientWidth || left < ctScrollLeft) {
9573 container.scrollLeft = left;
9575 else if (right > ctRight) {
9576 container.scrollLeft = right - container.clientWidth;
9578 container.scrollLeft = container.scrollLeft;
9584 scrollChildIntoView : function(child, hscroll) {
9585 Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
9589 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9590 * within this element's scrollable range.
9591 * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
9592 * @param {Number} distance How far to scroll the element in pixels
9593 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9594 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9595 * was scrolled as far as it could go.
9597 scroll : function(direction, distance, animate) {
9598 if (!this.isScrollable()) {
9602 l = el.scrollLeft, t = el.scrollTop,
9603 w = el.scrollWidth, h = el.scrollHeight,
9604 cw = el.clientWidth, ch = el.clientHeight,
9605 scrolled = false, v,
9607 l: Math.min(l + distance, w-cw),
9608 r: v = Math.max(l - distance, 0),
9609 t: Math.max(t - distance, 0),
9610 b: Math.min(t + distance, h-ch)
9615 direction = direction.substr(0, 1);
9616 if ((v = hash[direction]) > -1) {
9618 this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.anim(animate));
9624 * @class Ext.Element
9626 Ext.Element.addMethods(
9628 var VISIBILITY = "visibility",
9629 DISPLAY = "display",
9632 XMASKED = Ext.baseCSSPrefix + "masked",
9633 XMASKEDRELATIVE = Ext.baseCSSPrefix + "masked-relative",
9634 data = Ext.Element.data;
9638 * Checks whether the element is currently visible using both visibility and display properties.
9639 * @param {Boolean} [deep=false] True to walk the dom and see if parent elements are hidden
9640 * @return {Boolean} True if the element is currently visible, else false
9642 isVisible : function(deep) {
9643 var vis = !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE),
9644 p = this.dom.parentNode;
9646 if (deep !== true || !vis) {
9650 while (p && !(/^body/i.test(p.tagName))) {
9651 if (!Ext.fly(p, '_isVisible').isVisible()) {
9660 * Returns true if display is not "none"
9663 isDisplayed : function() {
9664 return !this.isStyle(DISPLAY, NONE);
9668 * Convenience method for setVisibilityMode(Element.DISPLAY)
9669 * @param {String} display (optional) What to set display to when visible
9670 * @return {Ext.Element} this
9672 enableDisplayMode : function(display) {
9673 this.setVisibilityMode(Ext.Element.DISPLAY);
9675 if (!Ext.isEmpty(display)) {
9676 data(this.dom, 'originalDisplay', display);
9683 * Puts a mask over this element to disable user interaction. Requires core.css.
9684 * This method can only be applied to elements which accept child nodes.
9685 * @param {String} msg (optional) A message to display in the mask
9686 * @param {String} msgCls (optional) A css class to apply to the msg element
9687 * @return {Ext.Element} The mask element
9689 mask : function(msg, msgCls) {
9692 setExpression = dom.style.setExpression,
9694 EXTELMASKMSG = Ext.baseCSSPrefix + "mask-msg",
9698 if (!(/^body/i.test(dom.tagName) && me.getStyle('position') == 'static')) {
9699 me.addCls(XMASKEDRELATIVE);
9701 el = data(dom, 'maskMsg');
9705 el = data(dom, 'mask');
9710 mask = dh.append(dom, {cls : Ext.baseCSSPrefix + "mask"}, true);
9711 data(dom, 'mask', mask);
9714 mask.setDisplayed(true);
9716 if (typeof msg == 'string') {
9717 var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
9718 data(dom, 'maskMsg', mm);
9719 mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
9720 mm.dom.firstChild.innerHTML = msg;
9721 mm.setDisplayed(true);
9724 // NOTE: CSS expressions are resource intensive and to be used only as a last resort
9725 // These expressions are removed as soon as they are no longer necessary - in the unmask method.
9726 // In normal use cases an element will be masked for a limited period of time.
9727 // Fix for https://sencha.jira.com/browse/EXTJSIV-19.
9728 // IE6 strict mode and IE6-9 quirks mode takes off left+right padding when calculating width!
9729 if (!Ext.supports.IncludePaddingInWidthCalculation && setExpression) {
9730 mask.dom.style.setExpression('width', 'this.parentNode.offsetWidth + "px"');
9733 // Some versions and modes of IE subtract top+bottom padding when calculating height.
9734 // Different versions from those which make the same error for width!
9735 if (!Ext.supports.IncludePaddingInHeightCalculation && setExpression) {
9736 mask.dom.style.setExpression('height', 'this.parentNode.offsetHeight + "px"');
9738 // ie will not expand full height automatically
9739 else if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto') {
9740 mask.setSize(undefined, me.getHeight());
9746 * Removes a previously applied mask.
9748 unmask : function() {
9751 mask = data(dom, 'mask'),
9752 maskMsg = data(dom, 'maskMsg');
9755 // Remove resource-intensive CSS expressions as soon as they are not required.
9756 if (mask.dom.style.clearExpression) {
9757 mask.dom.style.clearExpression('width');
9758 mask.dom.style.clearExpression('height');
9762 data(dom, 'maskMsg', undefined);
9766 data(dom, 'mask', undefined);
9767 me.removeCls([XMASKED, XMASKEDRELATIVE]);
9771 * Returns true if this element is masked. Also re-centers any displayed message within the mask.
9774 isMasked : function() {
9776 mask = data(me.dom, 'mask'),
9777 maskMsg = data(me.dom, 'maskMsg');
9779 if (mask && mask.isVisible()) {
9789 * Creates an iframe shim for this element to keep selects and other windowed objects from
9791 * @return {Ext.Element} The new shim element
9793 createShim : function() {
9794 var el = document.createElement('iframe'),
9797 el.frameBorder = '0';
9798 el.className = Ext.baseCSSPrefix + 'shim';
9799 el.src = Ext.SSL_SECURE_URL;
9800 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
9801 shim.autoBoxAdjust = false;
9808 * @class Ext.Element
9810 Ext.Element.addMethods({
9812 * Convenience method for constructing a KeyMap
9813 * @param {String/Number/Number[]/Object} 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:
9814 * <code>{key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}</code>
9815 * @param {Function} fn The function to call
9816 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed. Defaults to this Element.
9817 * @return {Ext.util.KeyMap} The KeyMap created
9819 addKeyListener : function(key, fn, scope){
9821 if(typeof key != 'object' || Ext.isArray(key)){
9837 return Ext.create('Ext.util.KeyMap', this, config);
9841 * Creates a KeyMap for this element
9842 * @param {Object} config The KeyMap config. See {@link Ext.util.KeyMap} for more details
9843 * @return {Ext.util.KeyMap} The KeyMap created
9845 addKeyMap : function(config){
9846 return Ext.create('Ext.util.KeyMap', this, config);
9850 //Import the newly-added Ext.Element functions into CompositeElementLite. We call this here because
9851 //Element.keys.js is the last extra Ext.Element include in the ext-all.js build
9852 Ext.CompositeElementLite.importElementMethods();
9855 * @class Ext.CompositeElementLite
9857 Ext.apply(Ext.CompositeElementLite.prototype, {
9858 addElements : function(els, root){
9862 if(typeof els == "string"){
9863 els = Ext.Element.selectorFunction(els, root);
9865 var yels = this.elements;
9866 Ext.each(els, function(e) {
9867 yels.push(Ext.get(e));
9873 * Returns the first Element
9874 * @return {Ext.Element}
9877 return this.item(0);
9881 * Returns the last Element
9882 * @return {Ext.Element}
9885 return this.item(this.getCount()-1);
9889 * Returns true if this composite contains the passed element
9890 * @param el {String/HTMLElement/Ext.Element/Number} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
9893 contains : function(el){
9894 return this.indexOf(el) != -1;
9898 * Removes the specified element(s).
9899 * @param {String/HTMLElement/Ext.Element/Number} el The id of an element, the Element itself, the index of the element in this composite
9900 * or an array of any of those.
9901 * @param {Boolean} removeDom (optional) True to also remove the element from the document
9902 * @return {Ext.CompositeElement} this
9904 removeElement : function(keys, removeDom){
9906 els = this.elements,
9908 Ext.each(keys, function(val){
9909 if ((el = (els[val] || els[val = me.indexOf(val)]))) {
9917 Ext.Array.erase(els, val, 1);
9925 * @class Ext.CompositeElement
9926 * @extends Ext.CompositeElementLite
9927 * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
9928 * members, or to perform collective actions upon the whole set.</p>
9929 * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
9930 * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
9931 * <p>All methods return <i>this</i> and can be chained.</p>
9934 var els = Ext.select("#some-el div.some-class", true);
9935 // or select directly from an existing element
9936 var el = Ext.get('some-el');
9937 el.select('div.some-class', true);
9939 els.setWidth(100); // all elements become 100 width
9940 els.hide(true); // all elements fade out and hide
9942 els.setWidth(100).hide(true);
9945 Ext.CompositeElement = Ext.extend(Ext.CompositeElementLite, {
9947 constructor : function(els, root){
9949 this.add(els, root);
9953 getElement : function(el){
9954 // In this case just return it, since we already have a reference to it
9959 transformElement : function(el){
9965 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
9966 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
9967 * {@link Ext.CompositeElementLite CompositeElementLite} object.
9968 * @param {String/HTMLElement[]} selector The CSS selector or an array of elements
9969 * @param {Boolean} [unique] true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
9970 * @param {HTMLElement/String} [root] The root element of the query or id of the root
9971 * @return {Ext.CompositeElementLite/Ext.CompositeElement}
9972 * @member Ext.Element
9975 Ext.Element.select = function(selector, unique, root){
9977 if(typeof selector == "string"){
9978 els = Ext.Element.selectorFunction(selector, root);
9979 }else if(selector.length !== undefined){
9984 sourceClass: "Ext.Element",
9985 sourceMethod: "select",
9989 msg: "Invalid selector specified: " + selector
9993 return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
9997 * Shorthand of {@link Ext.Element#select}.
10000 * @alias Ext.Element#select
10002 Ext.select = Ext.Element.select;