3 * Copyright(c) 2006-2010 Sencha Inc.
5 * http://www.sencha.com/license
9 var EXTUTIL = Ext.util,
14 * @class Ext.util.Observable
15 * Base class that provides a common interface for publishing events. Subclasses are expected to
16 * to have a property "events" with all the events defined, and, optionally, a property "listeners"
17 * with configured listeners defined.<br>
20 Employee = Ext.extend(Ext.util.Observable, {
21 constructor: function(config){
22 this.name = config.name;
28 // Copy configured listeners into *this* object so that the base class's
29 // constructor will add them.
30 this.listeners = config.listeners;
32 // Call our superclass constructor to complete construction process.
33 Employee.superclass.constructor.call(this, config)
37 * This could then be used like this:<pre><code>
38 var newEmployee = new Employee({
42 // By default, "this" will be the object that fired the event.
43 alert(this.name + " has quit!");
49 EXTUTIL.Observable = function(){
51 * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
52 * object during initialization. This should be a valid listeners config object as specified in the
53 * {@link #addListener} example for attaching multiple handlers at once.</p>
54 * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
55 * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
56 * is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
57 * <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
58 * events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
59 * has been rendered. A plugin can simplify this step:<pre><code>
60 // Plugin is configured with a listeners config object.
61 // The Component is appended to the argument list of all handler functions.
62 Ext.DomObserver = Ext.extend(Object, {
63 constructor: function(config) {
64 this.listeners = config.listeners ? config.listeners : config;
67 // Component passes itself into plugin's init method
69 var p, l = this.listeners;
71 if (Ext.isFunction(l[p])) {
72 l[p] = this.createHandler(l[p], c);
74 l[p].fn = this.createHandler(l[p].fn, c);
78 // Add the listeners to the Element immediately following the render call
79 c.render = c.render.{@link Function#createSequence createSequence}(function() {
87 createHandler: function(fn, c) {
94 var combo = new Ext.form.ComboBox({
96 // Collapse combo when its element is clicked on
97 plugins: [ new Ext.DomObserver({
98 click: function(evt, comp) {
109 var me = this, e = me.events;
117 EXTUTIL.Observable.prototype = {
119 filterOptRe : /^(?:scope|delay|buffer|single)$/,
122 * <p>Fires the specified event with the passed parameters (minus the event name).</p>
123 * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
124 * by calling {@link #enableBubble}.</p>
125 * @param {String} eventName The name of the event to fire.
126 * @param {Object...} args Variable number of parameters are passed to handlers.
127 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
129 fireEvent : function(){
130 var a = Array.prototype.slice.call(arguments, 0),
131 ename = a[0].toLowerCase(),
134 ce = me.events[ename],
138 if (me.eventsSuspended === TRUE) {
139 if (q = me.eventQueue) {
143 else if(typeof ce == 'object') {
145 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
148 c = me.getBubbleTarget && me.getBubbleTarget();
149 if(c && c.enableBubble) {
150 cc = c.events[ename];
151 if(!cc || typeof cc != 'object' || !cc.bubble) {
152 c.enableBubble(ename);
154 return c.fireEvent.apply(c, a);
159 ret = ce.fire.apply(ce, a);
166 * Appends an event handler to this object.
167 * @param {String} eventName The name of the event to listen for.
168 * @param {Function} handler The method the event invokes.
169 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
170 * <b>If omitted, defaults to the object which fired the event.</b>
171 * @param {Object} options (optional) An object containing handler configuration.
172 * properties. This may contain any of the following properties:<ul>
173 * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
174 * <b>If omitted, defaults to the object which fired the event.</b></div></li>
175 * <li><b>delay</b> : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
176 * <li><b>single</b> : Boolean<div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
177 * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
178 * by the specified number of milliseconds. If the event fires again within that time, the original
179 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
180 * <li><b>target</b> : Observable<div class="sub-desc">Only call the handler if the event was fired on the target Observable, <i>not</i>
181 * if the event was bubbled up from a child Observable.</div></li>
184 * <b>Combining Options</b><br>
185 * Using the options argument, it is possible to combine different types of listeners:<br>
187 * A delayed, one-time listener.
189 myDataView.on('click', this.onClick, this, {
194 * <b>Attaching multiple handlers in 1 call</b><br>
195 * The method also allows for a single argument to be passed which is a config object containing properties
196 * which specify multiple handlers.
206 fn: this.onMouseOver,
215 * Or a shorthand syntax:<br>
218 'click' : this.onClick,
219 'mouseover' : this.onMouseOver,
220 'mouseout' : this.onMouseOut,
224 addListener : function(eventName, fn, scope, o){
230 if (typeof eventName == 'object') {
234 if (!me.filterOptRe.test(e)) {
235 me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
239 eventName = eventName.toLowerCase();
240 ce = me.events[eventName] || TRUE;
241 if (typeof ce == 'boolean') {
242 me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
244 ce.addListener(fn, scope, typeof o == 'object' ? o : {});
249 * Removes an event handler.
250 * @param {String} eventName The type of event the handler was associated with.
251 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
252 * @param {Object} scope (optional) The scope originally specified for the handler.
254 removeListener : function(eventName, fn, scope){
255 var ce = this.events[eventName.toLowerCase()];
256 if (typeof ce == 'object') {
257 ce.removeListener(fn, scope);
262 * Removes all listeners for this object
264 purgeListeners : function(){
265 var events = this.events,
270 if(typeof evt == 'object'){
271 evt.clearListeners();
277 * Adds the specified events to the list of events which this Observable may fire.
278 * @param {Object|String} o Either an object with event names as properties with a value of <code>true</code>
279 * or the first event name string if multiple event names are being passed as separate parameters.
280 * @param {string} Optional. Event name if multiple event names are being passed as separate parameters.
282 this.addEvents('storeloaded', 'storecleared');
285 addEvents : function(o){
287 me.events = me.events || {};
288 if (typeof o == 'string') {
292 me.events[a[i]] = me.events[a[i]] || TRUE;
295 Ext.applyIf(me.events, o);
300 * Checks to see if this object has any listeners for a specified event
301 * @param {String} eventName The name of the event to check for
302 * @return {Boolean} True if the event is being listened for, else false
304 hasListener : function(eventName){
305 var e = this.events[eventName.toLowerCase()];
306 return typeof e == 'object' && e.listeners.length > 0;
310 * Suspend the firing of all events. (see {@link #resumeEvents})
311 * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
312 * after the {@link #resumeEvents} call instead of discarding all suspended events;
314 suspendEvents : function(queueSuspended){
315 this.eventsSuspended = TRUE;
316 if(queueSuspended && !this.eventQueue){
317 this.eventQueue = [];
322 * Resume firing events. (see {@link #suspendEvents})
323 * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
324 * events fired during event suspension will be sent to any listeners now.
326 resumeEvents : function(){
328 queued = me.eventQueue || [];
329 me.eventsSuspended = FALSE;
330 delete me.eventQueue;
331 EACH(queued, function(e) {
332 me.fireEvent.apply(me, e);
337 var OBSERVABLE = EXTUTIL.Observable.prototype;
339 * Appends an event handler to this object (shorthand for {@link #addListener}.)
340 * @param {String} eventName The type of event to listen for
341 * @param {Function} handler The method the event invokes
342 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
343 * <b>If omitted, defaults to the object which fired the event.</b>
344 * @param {Object} options (optional) An object containing handler configuration.
347 OBSERVABLE.on = OBSERVABLE.addListener;
349 * Removes an event handler (shorthand for {@link #removeListener}.)
350 * @param {String} eventName The type of event the handler was associated with.
351 * @param {Function} handler The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
352 * @param {Object} scope (optional) The scope originally specified for the handler.
355 OBSERVABLE.un = OBSERVABLE.removeListener;
358 * Removes <b>all</b> added captures from the Observable.
359 * @param {Observable} o The Observable to release
362 EXTUTIL.Observable.releaseCapture = function(o){
363 o.fireEvent = OBSERVABLE.fireEvent;
366 function createTargeted(h, o, scope){
368 if(o.target == arguments[0]){
369 h.apply(scope, Array.prototype.slice.call(arguments, 0));
374 function createBuffered(h, o, l, scope){
375 l.task = new EXTUTIL.DelayedTask();
377 l.task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
381 function createSingle(h, e, fn, scope){
383 e.removeListener(fn, scope);
384 return h.apply(scope, arguments);
388 function createDelayed(h, o, l, scope){
390 var task = new EXTUTIL.DelayedTask(),
391 args = Array.prototype.slice.call(arguments, 0);
396 task.delay(o.delay || 10, function(){
397 l.tasks.remove(task);
398 h.apply(scope, args);
403 EXTUTIL.Event = function(obj, name){
409 EXTUTIL.Event.prototype = {
410 addListener : function(fn, scope, options){
413 scope = scope || me.obj;
414 if(!me.isListening(fn, scope)){
415 l = me.createListener(fn, scope, options);
416 if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
417 me.listeners = me.listeners.slice(0);
419 me.listeners.push(l);
423 createListener: function(fn, scope, o){
425 scope = scope || this.obj;
432 h = createTargeted(h, o, scope);
435 h = createDelayed(h, o, l, scope);
438 h = createSingle(h, this, fn, scope);
441 h = createBuffered(h, o, l, scope);
447 findListener : function(fn, scope){
448 var list = this.listeners,
452 scope = scope || this.obj;
456 if(l.fn == fn && l.scope == scope){
464 isListening : function(fn, scope){
465 return this.findListener(fn, scope) != -1;
468 removeListener : function(fn, scope){
474 if((index = me.findListener(fn, scope)) != -1){
476 me.listeners = me.listeners.slice(0);
478 l = me.listeners[index];
483 k = l.tasks && l.tasks.length;
490 me.listeners.splice(index, 1);
496 // Iterate to stop any buffered/delayed events
497 clearListeners : function(){
502 me.removeListener(l[i].fn, l[i].scope);
508 listeners = me.listeners,
509 len = listeners.length,
515 var args = Array.prototype.slice.call(arguments, 0);
516 for (; i < len; i++) {
518 if(l && l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
519 return (me.firing = FALSE);
530 * @class Ext.DomHelper
531 * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
532 * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
533 * from your DOM building code.</p>
535 * <p><b><u>DomHelper element specification object</u></b></p>
536 * <p>A specification object is used when creating elements. Attributes of this object
537 * are assumed to be element attributes, except for 4 special attributes:
538 * <div class="mdetail-params"><ul>
539 * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
540 * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
541 * same kind of element definition objects to be created and appended. These can be nested
542 * as deep as you want.</div></li>
543 * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
544 * This will end up being either the "class" attribute on a HTML fragment or className
545 * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
546 * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
549 * <p><b><u>Insertion methods</u></b></p>
550 * <p>Commonly used insertion methods:
551 * <div class="mdetail-params"><ul>
552 * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>
553 * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>
554 * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>
555 * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>
556 * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>
557 * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>
560 * <p><b><u>Example</u></b></p>
561 * <p>This is an example, where an unordered list with 3 children items is appended to an existing
562 * element with id <tt>'my-div'</tt>:<br>
564 var dh = Ext.DomHelper; // create shorthand alias
565 // specification object
570 // append children after creating
571 children: [ // may also specify 'cn' instead of 'children'
572 {tag: 'li', id: 'item0', html: 'List Item 0'},
573 {tag: 'li', id: 'item1', html: 'List Item 1'},
574 {tag: 'li', id: 'item2', html: 'List Item 2'}
577 var list = dh.append(
578 'my-div', // the context element 'my-div' can either be the id or the actual node
579 spec // the specification object
582 * <p>Element creation specification parameters in this class may also be passed as an Array of
583 * specification objects. This can be used to insert multiple sibling nodes into an existing
584 * container very efficiently. For example, to add more list items to the example above:<pre><code>
586 {tag: 'li', id: 'item3', html: 'List Item 3'},
587 {tag: 'li', id: 'item4', html: 'List Item 4'}
591 * <p><b><u>Templating</u></b></p>
592 * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
593 * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
594 * insert new elements. Revisiting the example above, we could utilize templating this time:
597 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
599 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
601 for(var i = 0; i < 5, i++){
602 tpl.append(list, [i]); // use template to append to the actual node
605 * <p>An example using a template:<pre><code>
606 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
608 var tpl = new Ext.DomHelper.createTemplate(html);
609 tpl.append('blog-roll', ['link1', 'http://www.jackslocum.com/', "Jack's Site"]);
610 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin's Site"]);
613 * <p>The same example using named parameters:<pre><code>
614 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
616 var tpl = new Ext.DomHelper.createTemplate(html);
617 tpl.append('blog-roll', {
619 url: 'http://www.jackslocum.com/',
620 text: "Jack's Site"
622 tpl.append('blog-roll', {
624 url: 'http://www.dustindiaz.com/',
625 text: "Dustin's Site"
629 * <p><b><u>Compiling Templates</u></b></p>
630 * <p>Templates are applied using regular expressions. The performance is great, but if
631 * you are adding a bunch of DOM elements using the same template, you can increase
632 * performance even further by {@link Ext.Template#compile "compiling"} the template.
633 * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
634 * broken up at the different variable points and a dynamic function is created and eval'ed.
635 * The generated function performs string concatenation of these parts and the passed
636 * variables instead of using regular expressions.
638 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
640 var tpl = new Ext.DomHelper.createTemplate(html);
643 //... use template like normal
646 * <p><b><u>Performance Boost</u></b></p>
647 * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
648 * of DOM can significantly boost performance.</p>
649 * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
650 * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
651 * results in the creation of a text node. Usage:</p>
653 Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
657 Ext.DomHelper = function(){
658 var tempTableEl = null,
659 emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
660 tableRe = /^table|tbody|tr|td$/i,
661 confRe = /tag|children|cn|html$/i,
662 tableElRe = /td|tr|tbody/i,
663 cssRe = /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
666 // kill repeat to save bytes
667 afterbegin = 'afterbegin',
668 afterend = 'afterend',
669 beforebegin = 'beforebegin',
670 beforeend = 'beforeend',
679 function doInsert(el, o, returnElement, pos, sibling, append){
680 var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));
681 return returnElement ? Ext.get(newNode, true) : newNode;
684 // build as innerHTML where available
685 function createHtml(o){
692 if(typeof o == "string"){
694 } else if (Ext.isArray(o)) {
695 for (var i=0; i < o.length; i++) {
697 b += createHtml(o[i]);
701 b += '<' + (o.tag = o.tag || 'div');
704 if(!confRe.test(attr)){
705 if (typeof val == "object") {
706 b += ' ' + attr + '="';
708 b += key + ':' + val[key] + ';';
712 b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
716 // Now either just close the tag or try to add children and close the tag.
717 if (emptyTags.test(o.tag)) {
721 if ((cn = o.children || o.cn)) {
726 b += '</' + o.tag + '>';
732 function ieTable(depth, s, h, e){
733 tempTableEl.innerHTML = [s, h, e].join('');
740 // If the result is multiple siblings, then encapsulate them into one fragment.
741 if(ns = el.nextSibling){
742 var df = document.createDocumentFragment();
755 * Nasty code for IE's broken table implementation
757 function insertIntoTable(tag, where, el, html) {
761 tempTableEl = tempTableEl || document.createElement('div');
763 if(tag == 'td' && (where == afterbegin || where == beforeend) ||
764 !tableElRe.test(tag) && (where == beforebegin || where == afterend)) {
767 before = where == beforebegin ? el :
768 where == afterend ? el.nextSibling :
769 where == afterbegin ? el.firstChild : null;
771 if (where == beforebegin || where == afterend) {
775 if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
776 node = ieTable(4, trs, html, tre);
777 } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
778 (tag == 'tr' && (where == beforebegin || where == afterend))) {
779 node = ieTable(3, tbs, html, tbe);
781 node = ieTable(2, ts, html, te);
783 el.insertBefore(node, before);
790 * Returns the markup for the passed Element(s) config.
791 * @param {Object} o The DOM object spec (and children)
794 markup : function(o){
795 return createHtml(o);
799 * Applies a style specification to an element.
800 * @param {String/HTMLElement} el The element to apply styles to
801 * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
802 * a function which returns such a specification.
804 applyStyles : function(el, styles){
809 if (typeof styles == "function") {
810 styles = styles.call();
812 if (typeof styles == "string") {
814 * Since we're using the g flag on the regex, we need to set the lastIndex.
815 * This automatically happens on some implementations, but not others, see:
816 * http://stackoverflow.com/questions/2645273/javascript-regular-expression-literal-persists-between-function-calls
817 * http://blog.stevenlevithan.com/archives/fixing-javascript-regexp
820 while ((matches = cssRe.exec(styles))) {
821 el.setStyle(matches[1], matches[2]);
823 } else if (typeof styles == "object") {
830 * Inserts an HTML fragment into the DOM.
831 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
832 * @param {HTMLElement} el The context element
833 * @param {String} html The HTML fragment
834 * @return {HTMLElement} The new node
836 insertHtml : function(where, el, html){
845 where = where.toLowerCase();
846 // add these here because they are used in both branches of the condition.
847 hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
848 hash[afterend] = ['AfterEnd', 'nextSibling'];
850 if (el.insertAdjacentHTML) {
851 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
854 // add these two to the hash.
855 hash[afterbegin] = ['AfterBegin', 'firstChild'];
856 hash[beforeend] = ['BeforeEnd', 'lastChild'];
857 if ((hashVal = hash[where])) {
858 el.insertAdjacentHTML(hashVal[0], html);
859 return el[hashVal[1]];
862 range = el.ownerDocument.createRange();
863 setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
866 frag = range.createContextualFragment(html);
867 el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
868 return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
870 rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
872 range[setStart](el[rangeEl]);
873 frag = range.createContextualFragment(html);
874 if(where == afterbegin){
875 el.insertBefore(frag, el.firstChild);
877 el.appendChild(frag);
885 throw 'Illegal insertion point -> "' + where + '"';
889 * Creates new DOM element(s) and inserts them before el.
890 * @param {Mixed} el The context element
891 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
892 * @param {Boolean} returnElement (optional) true to return a Ext.Element
893 * @return {HTMLElement/Ext.Element} The new node
895 insertBefore : function(el, o, returnElement){
896 return doInsert(el, o, returnElement, beforebegin);
900 * Creates new DOM element(s) and inserts them after el.
901 * @param {Mixed} el The context element
902 * @param {Object} o The DOM object spec (and children)
903 * @param {Boolean} returnElement (optional) true to return a Ext.Element
904 * @return {HTMLElement/Ext.Element} The new node
906 insertAfter : function(el, o, returnElement){
907 return doInsert(el, o, returnElement, afterend, 'nextSibling');
911 * Creates new DOM element(s) and inserts them as the first child of el.
912 * @param {Mixed} el The context element
913 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
914 * @param {Boolean} returnElement (optional) true to return a Ext.Element
915 * @return {HTMLElement/Ext.Element} The new node
917 insertFirst : function(el, o, returnElement){
918 return doInsert(el, o, returnElement, afterbegin, 'firstChild');
922 * Creates new DOM element(s) and appends them to el.
923 * @param {Mixed} el The context element
924 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
925 * @param {Boolean} returnElement (optional) true to return a Ext.Element
926 * @return {HTMLElement/Ext.Element} The new node
928 append : function(el, o, returnElement){
929 return doInsert(el, o, returnElement, beforeend, '', true);
933 * Creates new DOM element(s) and overwrites the contents of el with them.
934 * @param {Mixed} el The context element
935 * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
936 * @param {Boolean} returnElement (optional) true to return a Ext.Element
937 * @return {HTMLElement/Ext.Element} The new node
939 overwrite : function(el, o, returnElement){
941 el.innerHTML = createHtml(o);
942 return returnElement ? Ext.get(el.firstChild) : el.firstChild;
945 createHtml : createHtml
950 * @class Ext.Template
951 * <p>Represents an HTML fragment template. Templates may be {@link #compile precompiled}
952 * for greater performance.</p>
953 * <p>For example usage {@link #Template see the constructor}.</p>
956 * An instance of this class may be created by passing to the constructor either
957 * a single argument, or multiple arguments:
958 * <div class="mdetail-params"><ul>
959 * <li><b>single argument</b> : String/Array
960 * <div class="sub-desc">
961 * The single argument may be either a String or an Array:<ul>
962 * <li><tt>String</tt> : </li><pre><code>
963 var t = new Ext.Template("<div>Hello {0}.</div>");
964 t.{@link #append}('some-element', ['foo']);
966 * <li><tt>Array</tt> : </li>
967 * An Array will be combined with <code>join('')</code>.
969 var t = new Ext.Template([
970 '<div name="{id}">',
971 '<span class="{cls}">{name:trim} {value:ellipsis(10)}</span>',
974 t.{@link #compile}();
975 t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
978 * <li><b>multiple arguments</b> : String, Object, Array, ...
979 * <div class="sub-desc">
980 * Multiple arguments will be combined with <code>join('')</code>.
982 var t = new Ext.Template(
983 '<div name="{id}">',
984 '<span class="{cls}">{name} {value}</span>',
986 // a configuration object:
988 compiled: true, // {@link #compile} immediately
989 disableFormats: true // See Notes below.
993 * <p><b>Notes</b>:</p>
994 * <div class="mdetail-params"><ul>
995 * <li>Formatting and <code>disableFormats</code> are not applicable for Ext Core.</li>
996 * <li>For a list of available format functions, see {@link Ext.util.Format}.</li>
997 * <li><code>disableFormats</code> reduces <code>{@link #apply}</code> time
998 * when no formatting is required.</li>
1002 * @param {Mixed} config
1004 Ext.Template = function(html){
1010 if (Ext.isArray(html)) {
1011 html = html.join("");
1012 } else if (a.length > 1) {
1013 for(var i = 0, len = a.length; i < len; i++){
1015 if(typeof v == 'object'){
1021 html = buf.join('');
1027 * @cfg {Boolean} compiled Specify <tt>true</tt> to compile the template
1028 * immediately (see <code>{@link #compile}</code>).
1029 * Defaults to <tt>false</tt>.
1035 Ext.Template.prototype = {
1037 * @cfg {RegExp} re The regular expression used to match template variables.
1038 * Defaults to:<pre><code>
1039 * re : /\{([\w-]+)\}/g // for Ext Core
1040 * re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g // for Ext JS
1043 re : /\{([\w-]+)\}/g,
1045 * See <code>{@link #re}</code>.
1051 * Returns an HTML fragment of this template with the specified <code>values</code> applied.
1052 * @param {Object/Array} values
1053 * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
1054 * or an object (i.e. <code>{foo: 'bar'}</code>).
1055 * @return {String} The HTML fragment
1057 applyTemplate : function(values){
1060 return me.compiled ?
1061 me.compiled(values) :
1062 me.html.replace(me.re, function(m, name){
1063 return values[name] !== undefined ? values[name] : "";
1068 * Sets the HTML used as the template and optionally compiles it.
1069 * @param {String} html
1070 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
1071 * @return {Ext.Template} this
1073 set : function(html, compile){
1077 return compile ? me.compile() : me;
1081 * Compiles the template into an internal function, eliminating the RegEx overhead.
1082 * @return {Ext.Template} this
1084 compile : function(){
1086 sep = Ext.isGecko ? "+" : ",";
1088 function fn(m, name){
1089 name = "values['" + name + "']";
1090 return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";
1093 eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +
1094 me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
1095 (Ext.isGecko ? "';};" : "'].join('');};"));
1100 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
1101 * @param {Mixed} el The context element
1102 * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
1103 * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
1104 * @return {HTMLElement/Ext.Element} The new node or Element
1106 insertFirst: function(el, values, returnElement){
1107 return this.doInsert('afterBegin', el, values, returnElement);
1111 * Applies the supplied values to the template and inserts the new node(s) before el.
1112 * @param {Mixed} el The context element
1113 * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
1114 * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
1115 * @return {HTMLElement/Ext.Element} The new node or Element
1117 insertBefore: function(el, values, returnElement){
1118 return this.doInsert('beforeBegin', el, values, returnElement);
1122 * Applies the supplied values to the template and inserts the new node(s) after el.
1123 * @param {Mixed} el The context element
1124 * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
1125 * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
1126 * @return {HTMLElement/Ext.Element} The new node or Element
1128 insertAfter : function(el, values, returnElement){
1129 return this.doInsert('afterEnd', el, values, returnElement);
1133 * Applies the supplied <code>values</code> to the template and appends
1134 * the new node(s) to the specified <code>el</code>.
1135 * <p>For example usage {@link #Template see the constructor}.</p>
1136 * @param {Mixed} el The context element
1137 * @param {Object/Array} values
1138 * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
1139 * or an object (i.e. <code>{foo: 'bar'}</code>).
1140 * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined)
1141 * @return {HTMLElement/Ext.Element} The new node or Element
1143 append : function(el, values, returnElement){
1144 return this.doInsert('beforeEnd', el, values, returnElement);
1147 doInsert : function(where, el, values, returnEl){
1148 el = Ext.getDom(el);
1149 var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
1150 return returnEl ? Ext.get(newNode, true) : newNode;
1154 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
1155 * @param {Mixed} el The context element
1156 * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
1157 * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
1158 * @return {HTMLElement/Ext.Element} The new node or Element
1160 overwrite : function(el, values, returnElement){
1161 el = Ext.getDom(el);
1162 el.innerHTML = this.applyTemplate(values);
1163 return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
1167 * Alias for {@link #applyTemplate}
1168 * Returns an HTML fragment of this template with the specified <code>values</code> applied.
1169 * @param {Object/Array} values
1170 * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
1171 * or an object (i.e. <code>{foo: 'bar'}</code>).
1172 * @return {String} The HTML fragment
1173 * @member Ext.Template
1176 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
1179 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
1180 * @param {String/HTMLElement} el A DOM element or its id
1181 * @param {Object} config A configuration object
1182 * @return {Ext.Template} The created template
1185 Ext.Template.from = function(el, config){
1186 el = Ext.getDom(el);
1187 return new Ext.Template(el.value || el.innerHTML, config || '');
1190 * This is code is also distributed under MIT license for use
1191 * with jQuery and prototype JavaScript libraries.
1194 * @class Ext.DomQuery
1195 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).
1197 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>
1200 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.
1202 <h4>Element Selectors:</h4>
1204 <li> <b>*</b> any element</li>
1205 <li> <b>E</b> an element with the tag E</li>
1206 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
1207 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
1208 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
1209 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
1211 <h4>Attribute Selectors:</h4>
1212 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
1214 <li> <b>E[foo]</b> has an attribute "foo"</li>
1215 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
1216 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
1217 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
1218 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
1219 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
1220 <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li>
1222 <h4>Pseudo Classes:</h4>
1224 <li> <b>E:first-child</b> E is the first child of its parent</li>
1225 <li> <b>E:last-child</b> E is the last child of its parent</li>
1226 <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>
1227 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
1228 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
1229 <li> <b>E:only-child</b> E is the only child of its parent</li>
1230 <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>
1231 <li> <b>E:first</b> the first E in the resultset</li>
1232 <li> <b>E:last</b> the last E in the resultset</li>
1233 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
1234 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
1235 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
1236 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
1237 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
1238 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
1239 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
1240 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
1241 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
1242 <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
1244 <h4>CSS Value Selectors:</h4>
1246 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
1247 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
1248 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
1249 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
1250 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
1251 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
1255 Ext.DomQuery = function(){
1260 trimRe = /^\s+|\s+$/g,
1261 tplRe = /\{(\d+)\}/g,
1262 modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
1263 tagTokenRe = /^(#)?([\w-\*]+)/,
1264 nthRe = /(\d*)n\+?(\d*)/,
1266 // This is for IE MSXML which does not support expandos.
1267 // IE runs the same speed using setAttribute, however FF slows way down
1268 // and Safari completely fails so they need to continue to use expandos.
1269 isIE = window.ActiveXObject ? true : false,
1272 // this eval is stop the compressor from
1273 // renaming the variable to something shorter
1274 eval("var batch = 30803;");
1276 // Retrieve the child node from a particular
1277 // parent at the specified index.
1278 function child(parent, index){
1280 n = parent.firstChild;
1282 if(n.nodeType == 1){
1292 // retrieve the next element node
1294 while((n = n.nextSibling) && n.nodeType != 1);
1298 // retrieve the previous element node
1300 while((n = n.previousSibling) && n.nodeType != 1);
1304 // Mark each child node with a nodeIndex skipping and
1305 // removing empty text nodes.
1306 function children(parent){
1307 var n = parent.firstChild,
1311 nextNode = n.nextSibling;
1312 // clean worthless empty nodes.
1313 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
1314 parent.removeChild(n);
1316 // add an expando nodeIndex
1317 n.nodeIndex = ++nodeIndex;
1325 // nodeSet - array of nodes
1327 function byClassName(nodeSet, cls){
1331 var result = [], ri = -1;
1332 for(var i = 0, ci; ci = nodeSet[i]; i++){
1333 if((' '+ci.className+' ').indexOf(cls) != -1){
1340 function attrValue(n, attr){
1341 // if its an array, use the first node.
1342 if(!n.tagName && typeof n.length != "undefined"){
1352 if(attr == "class" || attr == "className"){
1355 return n.getAttribute(attr) || n[attr];
1361 // mode - false, /, >, +, ~
1362 // tagName - defaults to "*"
1363 function getNodes(ns, mode, tagName){
1364 var result = [], ri = -1, cs;
1368 tagName = tagName || "*";
1370 if(typeof ns.getElementsByTagName != "undefined"){
1374 // no mode specified, grab all elements by tagName
1377 for(var i = 0, ni; ni = ns[i]; i++){
1378 cs = ni.getElementsByTagName(tagName);
1379 for(var j = 0, ci; ci = cs[j]; j++){
1383 // Direct Child mode (/ or >)
1384 // E > F or E/F all direct children elements of E that have the tag
1385 } else if(mode == "/" || mode == ">"){
1386 var utag = tagName.toUpperCase();
1387 for(var i = 0, ni, cn; ni = ns[i]; i++){
1389 for(var j = 0, cj; cj = cn[j]; j++){
1390 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
1395 // Immediately Preceding mode (+)
1396 // E + F all elements with the tag F that are immediately preceded by an element with the tag E
1397 }else if(mode == "+"){
1398 var utag = tagName.toUpperCase();
1399 for(var i = 0, n; n = ns[i]; i++){
1400 while((n = n.nextSibling) && n.nodeType != 1);
1401 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
1406 // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
1407 }else if(mode == "~"){
1408 var utag = tagName.toUpperCase();
1409 for(var i = 0, n; n = ns[i]; i++){
1410 while((n = n.nextSibling)){
1411 if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
1420 function concat(a, b){
1424 for(var i = 0, l = b.length; i < l; i++){
1430 function byTag(cs, tagName){
1431 if(cs.tagName || cs == document){
1437 var result = [], ri = -1;
1438 tagName = tagName.toLowerCase();
1439 for(var i = 0, ci; ci = cs[i]; i++){
1440 if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
1447 function byId(cs, id){
1448 if(cs.tagName || cs == document){
1454 var result = [], ri = -1;
1455 for(var i = 0, ci; ci = cs[i]; i++){
1456 if(ci && ci.id == id){
1464 // operators are =, !=, ^=, $=, *=, %=, |= and ~=
1465 // custom can be "{"
1466 function byAttribute(cs, attr, value, op, custom){
1469 useGetStyle = custom == "{",
1470 fn = Ext.DomQuery.operators[op],
1475 for(var i = 0, ci; ci = cs[i]; i++){
1476 // skip non-element nodes.
1477 if(ci.nodeType != 1){
1480 // only need to do this for the first node
1482 xml = Ext.DomQuery.isXml(ci);
1486 // we only need to change the property names if we're dealing with html nodes, not XML
1489 a = Ext.DomQuery.getStyle(ci, attr);
1490 } else if (attr == "class" || attr == "className"){
1492 } else if (attr == "for"){
1494 } else if (attr == "href"){
1495 // getAttribute href bug
1496 // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
1497 a = ci.getAttribute("href", 2);
1499 a = ci.getAttribute(attr);
1502 a = ci.getAttribute(attr);
1504 if((fn && fn(a, value)) || (!fn && a)){
1511 function byPseudo(cs, name, value){
1512 return Ext.DomQuery.pseudos[name](cs, value);
1515 function nodupIEXml(cs){
1518 cs[0].setAttribute("_nodup", d);
1520 for(var i = 1, len = cs.length; i < len; i++){
1522 if(!c.getAttribute("_nodup") != d){
1523 c.setAttribute("_nodup", d);
1527 for(var i = 0, len = cs.length; i < len; i++){
1528 cs[i].removeAttribute("_nodup");
1537 var len = cs.length, c, i, r = cs, cj, ri = -1;
1538 if(!len || typeof cs.nodeType != "undefined" || len == 1){
1541 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
1542 return nodupIEXml(cs);
1546 for(i = 1; c = cs[i]; i++){
1551 for(var j = 0; j < i; j++){
1554 for(j = i+1; cj = cs[j]; j++){
1566 function quickDiffIEXml(c1, c2){
1569 for(var i = 0, len = c1.length; i < len; i++){
1570 c1[i].setAttribute("_qdiff", d);
1572 for(var i = 0, len = c2.length; i < len; i++){
1573 if(c2[i].getAttribute("_qdiff") != d){
1574 r[r.length] = c2[i];
1577 for(var i = 0, len = c1.length; i < len; i++){
1578 c1[i].removeAttribute("_qdiff");
1583 function quickDiff(c1, c2){
1584 var len1 = c1.length,
1590 if(isIE && typeof c1[0].selectSingleNode != "undefined"){
1591 return quickDiffIEXml(c1, c2);
1593 for(var i = 0; i < len1; i++){
1596 for(var i = 0, len = c2.length; i < len; i++){
1597 if(c2[i]._qdiff != d){
1598 r[r.length] = c2[i];
1604 function quickId(ns, mode, root, id){
1606 var d = root.ownerDocument || root;
1607 return d.getElementById(id);
1609 ns = getNodes(ns, mode, "*");
1610 return byId(ns, id);
1614 getStyle : function(el, name){
1615 return Ext.fly(el).getStyle(name);
1618 * Compiles a selector/xpath query into a reusable function. The returned function
1619 * takes one parameter "root" (optional), which is the context node from where the query should start.
1620 * @param {String} selector The selector/xpath query
1621 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
1622 * @return {Function}
1624 compile : function(path, type){
1625 type = type || "select";
1627 // setup fn preamble
1628 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
1631 matchers = Ext.DomQuery.matchers,
1632 matchersLn = matchers.length,
1634 // accept leading mode switch
1635 lmode = path.match(modeRe);
1637 if(lmode && lmode[1]){
1638 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
1639 path = path.replace(lmode[1], "");
1642 // strip leading slashes
1643 while(path.substr(0, 1)=="/"){
1644 path = path.substr(1);
1647 while(path && lastPath != path){
1649 var tokenMatch = path.match(tagTokenRe);
1650 if(type == "select"){
1653 if(tokenMatch[1] == "#"){
1654 fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';
1656 fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
1658 path = path.replace(tokenMatch[0], "");
1659 }else if(path.substr(0, 1) != '@'){
1660 fn[fn.length] = 'n = getNodes(n, mode, "*");';
1665 if(tokenMatch[1] == "#"){
1666 fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
1668 fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
1670 path = path.replace(tokenMatch[0], "");
1673 while(!(modeMatch = path.match(modeRe))){
1674 var matched = false;
1675 for(var j = 0; j < matchersLn; j++){
1676 var t = matchers[j];
1677 var m = path.match(t.re);
1679 fn[fn.length] = t.select.replace(tplRe, function(x, i){
1682 path = path.replace(m[0], "");
1687 // prevent infinite loop on bad selector
1689 throw 'Error parsing selector, parsing failed at "' + path + '"';
1693 fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
1694 path = path.replace(modeMatch[1], "");
1698 fn[fn.length] = "return nodup(n);\n}";
1700 // eval fn and return it
1706 * Selects a group of elements.
1707 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
1708 * @param {Node/String} root (optional) The start of the query (defaults to document).
1709 * @return {Array} An Array of DOM elements which match the selector. If there are
1710 * no matches, and empty Array is returned.
1712 jsSelect: function(path, root, type){
1713 // set root to doc if not specified.
1714 root = root || document;
1716 if(typeof root == "string"){
1717 root = document.getElementById(root);
1719 var paths = path.split(","),
1722 // loop over each selector
1723 for(var i = 0, len = paths.length; i < len; i++){
1724 var subPath = paths[i].replace(trimRe, "");
1725 // compile and place in cache
1726 if(!cache[subPath]){
1727 cache[subPath] = Ext.DomQuery.compile(subPath);
1728 if(!cache[subPath]){
1729 throw subPath + " is not a valid selector";
1732 var result = cache[subPath](root);
1733 if(result && result != document){
1734 results = results.concat(result);
1738 // if there were multiple selectors, make sure dups
1740 if(paths.length > 1){
1741 return nodup(results);
1745 isXml: function(el) {
1746 var docEl = (el ? el.ownerDocument || el : 0).documentElement;
1747 return docEl ? docEl.nodeName !== "HTML" : false;
1749 select : document.querySelectorAll ? function(path, root, type) {
1750 root = root || document;
1751 if (!Ext.DomQuery.isXml(root)) {
1753 var cs = root.querySelectorAll(path);
1754 return Ext.toArray(cs);
1758 return Ext.DomQuery.jsSelect.call(this, path, root, type);
1759 } : function(path, root, type) {
1760 return Ext.DomQuery.jsSelect.call(this, path, root, type);
1764 * Selects a single element.
1765 * @param {String} selector The selector/xpath query
1766 * @param {Node} root (optional) The start of the query (defaults to document).
1767 * @return {Element} The DOM element which matched the selector.
1769 selectNode : function(path, root){
1770 return Ext.DomQuery.select(path, root)[0];
1774 * Selects the value of a node, optionally replacing null with the defaultValue.
1775 * @param {String} selector The selector/xpath query
1776 * @param {Node} root (optional) The start of the query (defaults to document).
1777 * @param {String} defaultValue
1780 selectValue : function(path, root, defaultValue){
1781 path = path.replace(trimRe, "");
1782 if(!valueCache[path]){
1783 valueCache[path] = Ext.DomQuery.compile(path, "select");
1785 var n = valueCache[path](root), v;
1786 n = n[0] ? n[0] : n;
1788 // overcome a limitation of maximum textnode size
1789 // Rumored to potentially crash IE6 but has not been confirmed.
1790 // http://reference.sitepoint.com/javascript/Node/normalize
1791 // https://developer.mozilla.org/En/DOM/Node.normalize
1792 if (typeof n.normalize == 'function') n.normalize();
1794 v = (n && n.firstChild ? n.firstChild.nodeValue : null);
1795 return ((v === null||v === undefined||v==='') ? defaultValue : v);
1799 * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
1800 * @param {String} selector The selector/xpath query
1801 * @param {Node} root (optional) The start of the query (defaults to document).
1802 * @param {Number} defaultValue
1805 selectNumber : function(path, root, defaultValue){
1806 var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
1807 return parseFloat(v);
1811 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
1812 * @param {String/HTMLElement/Array} el An element id, element or array of elements
1813 * @param {String} selector The simple selector to test
1816 is : function(el, ss){
1817 if(typeof el == "string"){
1818 el = document.getElementById(el);
1820 var isArray = Ext.isArray(el),
1821 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
1822 return isArray ? (result.length == el.length) : (result.length > 0);
1826 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
1827 * @param {Array} el An array of elements to filter
1828 * @param {String} selector The simple selector to test
1829 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
1830 * the selector instead of the ones that match
1831 * @return {Array} An Array of DOM elements which match the selector. If there are
1832 * no matches, and empty Array is returned.
1834 filter : function(els, ss, nonMatches){
1835 ss = ss.replace(trimRe, "");
1836 if(!simpleCache[ss]){
1837 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
1839 var result = simpleCache[ss](els);
1840 return nonMatches ? quickDiff(result, els) : result;
1844 * Collection of matching regular expressions and code snippets.
1845 * Each capture group within () will be replace the {} in the select
1846 * statement as specified by their index.
1850 select: 'n = byClassName(n, " {1} ");'
1852 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
1853 select: 'n = byPseudo(n, "{1}", "{2}");'
1855 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
1856 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
1859 select: 'n = byId(n, "{1}");'
1862 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
1867 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
1868 * 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, > <.
1871 "=" : function(a, v){
1874 "!=" : function(a, v){
1877 "^=" : function(a, v){
1878 return a && a.substr(0, v.length) == v;
1880 "$=" : function(a, v){
1881 return a && a.substr(a.length-v.length) == v;
1883 "*=" : function(a, v){
1884 return a && a.indexOf(v) !== -1;
1886 "%=" : function(a, v){
1887 return (a % v) == 0;
1889 "|=" : function(a, v){
1890 return a && (a == v || a.substr(0, v.length+1) == v+'-');
1892 "~=" : function(a, v){
1893 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
1898 * <p>Object hash of "pseudo class" filter functions which are used when filtering selections. Each function is passed
1899 * two parameters:</p><div class="mdetail-params"><ul>
1900 * <li><b>c</b> : Array<div class="sub-desc">An Array of DOM elements to filter.</div></li>
1901 * <li><b>v</b> : String<div class="sub-desc">The argument (if any) supplied in the selector.</div></li>
1903 * <p>A filter function returns an Array of DOM elements which conform to the pseudo class.</p>
1904 * <p>In addition to the provided pseudo classes listed above such as <code>first-child</code> and <code>nth-child</code>,
1905 * developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.</p>
1906 * <p>For example, to filter <code><a></code> elements to only return links to <i>external</i> resources:</p>
1908 Ext.DomQuery.pseudos.external = function(c, v){
1909 var r = [], ri = -1;
1910 for(var i = 0, ci; ci = c[i]; i++){
1911 // Include in result set only if it's a link to an external resource
1912 if(ci.hostname != location.hostname){
1918 * Then external links could be gathered with the following statement:<code><pre>
1919 var externalLinks = Ext.select("a:external");
1923 "first-child" : function(c){
1924 var r = [], ri = -1, n;
1925 for(var i = 0, ci; ci = n = c[i]; i++){
1926 while((n = n.previousSibling) && n.nodeType != 1);
1934 "last-child" : function(c){
1935 var r = [], ri = -1, n;
1936 for(var i = 0, ci; ci = n = c[i]; i++){
1937 while((n = n.nextSibling) && n.nodeType != 1);
1945 "nth-child" : function(c, a) {
1946 var r = [], ri = -1,
1947 m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
1948 f = (m[1] || 1) - 0, l = m[2] - 0;
1949 for(var i = 0, n; n = c[i]; i++){
1950 var pn = n.parentNode;
1951 if (batch != pn._batch) {
1953 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
1954 if(cn.nodeType == 1){
1961 if (l == 0 || n.nodeIndex == l){
1964 } else if ((n.nodeIndex + l) % f == 0){
1972 "only-child" : function(c){
1973 var r = [], ri = -1;;
1974 for(var i = 0, ci; ci = c[i]; i++){
1975 if(!prev(ci) && !next(ci)){
1982 "empty" : function(c){
1983 var r = [], ri = -1;
1984 for(var i = 0, ci; ci = c[i]; i++){
1985 var cns = ci.childNodes, j = 0, cn, empty = true;
1988 if(cn.nodeType == 1 || cn.nodeType == 3){
2000 "contains" : function(c, v){
2001 var r = [], ri = -1;
2002 for(var i = 0, ci; ci = c[i]; i++){
2003 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
2010 "nodeValue" : function(c, v){
2011 var r = [], ri = -1;
2012 for(var i = 0, ci; ci = c[i]; i++){
2013 if(ci.firstChild && ci.firstChild.nodeValue == v){
2020 "checked" : function(c){
2021 var r = [], ri = -1;
2022 for(var i = 0, ci; ci = c[i]; i++){
2023 if(ci.checked == true){
2030 "not" : function(c, ss){
2031 return Ext.DomQuery.filter(c, ss, true);
2034 "any" : function(c, selectors){
2035 var ss = selectors.split('|'),
2037 for(var i = 0, ci; ci = c[i]; i++){
2038 for(var j = 0; s = ss[j]; j++){
2039 if(Ext.DomQuery.is(ci, s)){
2048 "odd" : function(c){
2049 return this["nth-child"](c, "odd");
2052 "even" : function(c){
2053 return this["nth-child"](c, "even");
2056 "nth" : function(c, a){
2057 return c[a-1] || [];
2060 "first" : function(c){
2064 "last" : function(c){
2065 return c[c.length-1] || [];
2068 "has" : function(c, ss){
2069 var s = Ext.DomQuery.select,
2071 for(var i = 0, ci; ci = c[i]; i++){
2072 if(s(ss, ci).length > 0){
2079 "next" : function(c, ss){
2080 var is = Ext.DomQuery.is,
2082 for(var i = 0, ci; ci = c[i]; i++){
2091 "prev" : function(c, ss){
2092 var is = Ext.DomQuery.is,
2094 for(var i = 0, ci; ci = c[i]; i++){
2107 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
2108 * @param {String} path The selector/xpath query
2109 * @param {Node} root (optional) The start of the query (defaults to document).
2114 Ext.query = Ext.DomQuery.select;
2116 * @class Ext.util.DelayedTask
2117 * <p> The DelayedTask class provides a convenient way to "buffer" the execution of a method,
2118 * performing setTimeout where a new timeout cancels the old timeout. When called, the
2119 * task will wait the specified time period before executing. If durng that time period,
2120 * the task is called again, the original call will be cancelled. This continues so that
2121 * the function is only called a single time for each iteration.</p>
2122 * <p>This method is especially useful for things like detecting whether a user has finished
2123 * typing in a text field. An example would be performing validation on a keypress. You can
2124 * use this class to buffer the keypress events for a certain number of milliseconds, and
2125 * perform only if they stop for that amount of time. Usage:</p><pre><code>
2126 var task = new Ext.util.DelayedTask(function(){
2127 alert(Ext.getDom('myInputField').value.length);
2129 // Wait 500ms before calling our function. If the user presses another key
2130 // during that 500ms, it will be cancelled and we'll wait another 500ms.
2131 Ext.get('myInputField').on('keypress', function(){
2132 task.{@link #delay}(500);
2135 * <p>Note that we are using a DelayedTask here to illustrate a point. The configuration
2136 * option <tt>buffer</tt> for {@link Ext.util.Observable#addListener addListener/on} will
2137 * also setup a delayed task for you to buffer events.</p>
2138 * @constructor The parameters to this constructor serve as defaults and are not required.
2139 * @param {Function} fn (optional) The default function to call.
2140 * @param {Object} scope The default scope (The <code><b>this</b></code> reference) in which the
2141 * function is called. If not specified, <code>this</code> will refer to the browser window.
2142 * @param {Array} args (optional) The default Array of arguments.
2144 Ext.util.DelayedTask = function(fn, scope, args){
2150 fn.apply(scope, args || []);
2154 * Cancels any pending timeout and queues a new one
2155 * @param {Number} delay The milliseconds to delay
2156 * @param {Function} newFn (optional) Overrides function passed to constructor
2157 * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
2158 * is specified, <code>this</code> will refer to the browser window.
2159 * @param {Array} newArgs (optional) Overrides args passed to constructor
2161 me.delay = function(delay, newFn, newScope, newArgs){
2164 scope = newScope || scope;
2165 args = newArgs || args;
2166 id = setInterval(call, delay);
2170 * Cancel the last queued timeout
2172 me.cancel = function(){
2179 * @class Ext.Element
2180 * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>
2181 * <p>All instances of this class inherit the methods of {@link Ext.Fx} making visual effects easily available to all DOM elements.</p>
2182 * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To
2183 * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older
2184 * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>
2188 var el = Ext.get("my-div");
2190 // by DOM element reference
2191 var el = Ext.get(myDivElement);
2193 * <b>Animations</b><br />
2194 * <p>When an element is manipulated, by default there is no animation.</p>
2196 var el = Ext.get("my-div");
2201 * <p>Many of the functions for manipulating an element have an optional "animate" parameter. This
2202 * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>
2204 // default animation
2205 el.setWidth(100, true);
2208 * <p>To configure the effects, an object literal with animation options to use as the Element animation
2209 * configuration object can also be specified. Note that the supported Element animation configuration
2210 * options are a subset of the {@link Ext.Fx} animation options specific to Fx effects. The supported
2211 * Element animation configuration options are:</p>
2213 Option Default Description
2214 --------- -------- ---------------------------------------------
2215 {@link Ext.Fx#duration duration} .35 The duration of the animation in seconds
2216 {@link Ext.Fx#easing easing} easeOut The easing method
2217 {@link Ext.Fx#callback callback} none A function to execute when the anim completes
2218 {@link Ext.Fx#scope scope} this The scope (this) of the callback function
2222 // Element animation options object
2224 {@link Ext.Fx#duration duration}: 1,
2225 {@link Ext.Fx#easing easing}: 'elasticIn',
2226 {@link Ext.Fx#callback callback}: this.foo,
2227 {@link Ext.Fx#scope scope}: this
2229 // animation with some options set
2230 el.setWidth(100, opt);
2232 * <p>The Element animation object being used for the animation will be set on the options
2233 * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>
2235 // using the "anim" property to get the Anim object
2236 if(opt.anim.isAnimated()){
2240 * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>
2241 * <p><b> Composite (Collections of) Elements</b></p>
2242 * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>
2243 * @constructor Create a new Element directly.
2244 * @param {String/HTMLElement} element
2245 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
2250 Ext.Element = function(element, forceNew){
2251 var dom = typeof element == "string" ?
2252 DOC.getElementById(element) : element,
2255 if(!dom) return null;
2259 if(!forceNew && id && Ext.elCache[id]){ // element object already exists
2260 return Ext.elCache[id].el;
2270 * The DOM element ID
2273 this.id = id || Ext.id(dom);
2276 var DH = Ext.DomHelper,
2282 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2283 * @param {Object} o The object with the attributes
2284 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2285 * @return {Ext.Element} this
2287 set : function(o, useSet){
2291 useSet = (useSet !== false) && !!el.setAttribute;
2294 if (o.hasOwnProperty(attr)) {
2296 if (attr == 'style') {
2297 DH.applyStyles(el, val);
2298 } else if (attr == 'cls') {
2300 } else if (useSet) {
2301 el.setAttribute(attr, val);
2313 * Fires when a mouse click is detected within the element.
2314 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2315 * @param {HtmlElement} t The target of the event.
2316 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2319 * @event contextmenu
2320 * Fires when a right click is detected within the element.
2321 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2322 * @param {HtmlElement} t The target of the event.
2323 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2327 * Fires when a mouse double click is detected within the element.
2328 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2329 * @param {HtmlElement} t The target of the event.
2330 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2334 * Fires when a mousedown is detected within the element.
2335 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2336 * @param {HtmlElement} t The target of the event.
2337 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2341 * Fires when a mouseup is detected within the element.
2342 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2343 * @param {HtmlElement} t The target of the event.
2344 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2348 * Fires when a mouseover is detected within the element.
2349 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2350 * @param {HtmlElement} t The target of the event.
2351 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2355 * Fires when a mousemove is detected with the element.
2356 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2357 * @param {HtmlElement} t The target of the event.
2358 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2362 * Fires when a mouseout is detected with the element.
2363 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2364 * @param {HtmlElement} t The target of the event.
2365 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2369 * Fires when the mouse enters the element.
2370 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2371 * @param {HtmlElement} t The target of the event.
2372 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2376 * Fires when the mouse leaves the element.
2377 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2378 * @param {HtmlElement} t The target of the event.
2379 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2385 * Fires when a keypress is detected within the element.
2386 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2387 * @param {HtmlElement} t The target of the event.
2388 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2392 * Fires when a keydown is detected within the element.
2393 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2394 * @param {HtmlElement} t The target of the event.
2395 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2399 * Fires when a keyup is detected within the element.
2400 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2401 * @param {HtmlElement} t The target of the event.
2402 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2406 // HTML frame/object events
2409 * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.
2410 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2411 * @param {HtmlElement} t The target of the event.
2412 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2416 * Fires when the user agent removes all content from a window or frame. For elements, it fires when the target element or any of its content has been removed.
2417 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2418 * @param {HtmlElement} t The target of the event.
2419 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2423 * Fires when an object/image is stopped from loading before completely loaded.
2424 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2425 * @param {HtmlElement} t The target of the event.
2426 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2430 * Fires when an object/image/frame cannot be loaded properly.
2431 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2432 * @param {HtmlElement} t The target of the event.
2433 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2437 * Fires when a document view is resized.
2438 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2439 * @param {HtmlElement} t The target of the event.
2440 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2444 * Fires when a document view is scrolled.
2445 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2446 * @param {HtmlElement} t The target of the event.
2447 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2453 * Fires when a user selects some text in a text field, including input and textarea.
2454 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2455 * @param {HtmlElement} t The target of the event.
2456 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2460 * Fires when a control loses the input focus and its value has been modified since gaining focus.
2461 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2462 * @param {HtmlElement} t The target of the event.
2463 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2467 * Fires when a form is submitted.
2468 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2469 * @param {HtmlElement} t The target of the event.
2470 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2474 * Fires when a form is reset.
2475 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2476 * @param {HtmlElement} t The target of the event.
2477 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2481 * Fires when an element receives focus either via the pointing device or by tab navigation.
2482 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2483 * @param {HtmlElement} t The target of the event.
2484 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2488 * Fires when an element loses focus either via the pointing device or by tabbing navigation.
2489 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2490 * @param {HtmlElement} t The target of the event.
2491 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2494 // User Interface events
2497 * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
2498 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2499 * @param {HtmlElement} t The target of the event.
2500 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2503 * @event DOMFocusOut
2504 * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
2505 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2506 * @param {HtmlElement} t The target of the event.
2507 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2510 * @event DOMActivate
2511 * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
2512 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2513 * @param {HtmlElement} t The target of the event.
2514 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2517 // DOM Mutation events
2519 * @event DOMSubtreeModified
2520 * Where supported. Fires when the subtree is modified.
2521 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2522 * @param {HtmlElement} t The target of the event.
2523 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2526 * @event DOMNodeInserted
2527 * Where supported. Fires when a node has been added as a child of another node.
2528 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2529 * @param {HtmlElement} t The target of the event.
2530 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2533 * @event DOMNodeRemoved
2534 * Where supported. Fires when a descendant node of the element is removed.
2535 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2536 * @param {HtmlElement} t The target of the event.
2537 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2540 * @event DOMNodeRemovedFromDocument
2541 * Where supported. Fires when a node is being removed from a document.
2542 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2543 * @param {HtmlElement} t The target of the event.
2544 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2547 * @event DOMNodeInsertedIntoDocument
2548 * Where supported. Fires when a node is being inserted into a document.
2549 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2550 * @param {HtmlElement} t The target of the event.
2551 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2554 * @event DOMAttrModified
2555 * Where supported. Fires when an attribute has been modified.
2556 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2557 * @param {HtmlElement} t The target of the event.
2558 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2561 * @event DOMCharacterDataModified
2562 * Where supported. Fires when the character data has been modified.
2563 * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2564 * @param {HtmlElement} t The target of the event.
2565 * @param {Object} o The options configuration passed to the {@link #addListener} call.
2569 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
2575 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
2576 * @param {String} selector The simple selector to test
2577 * @return {Boolean} True if this element matches the selector, else false
2579 is : function(simpleSelector){
2580 return Ext.DomQuery.is(this.dom, simpleSelector);
2584 * Tries to focus the element. Any exceptions are caught and ignored.
2585 * @param {Number} defer (optional) Milliseconds to defer the focus
2586 * @return {Ext.Element} this
2588 focus : function(defer, /* private */ dom) {
2590 dom = dom || me.dom;
2593 me.focus.defer(defer, null, [null, dom]);
2602 * Tries to blur the element. Any exceptions are caught and ignored.
2603 * @return {Ext.Element} this
2613 * Returns the value of the "value" attribute
2614 * @param {Boolean} asNumber true to parse the value as a number
2615 * @return {String/Number}
2617 getValue : function(asNumber){
2618 var val = this.dom.value;
2619 return asNumber ? parseInt(val, 10) : val;
2623 * Appends an event handler to this element. The shorthand version {@link #on} is equivalent.
2624 * @param {String} eventName The name of event to handle.
2625 * @param {Function} fn The handler function the event invokes. This function is passed
2626 * the following parameters:<ul>
2627 * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
2628 * <li><b>el</b> : HtmlElement<div class="sub-desc">The DOM element which was the target of the event.
2629 * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
2630 * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>
2632 * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2633 * <b>If omitted, defaults to this Element.</b>.
2634 * @param {Object} options (optional) An object containing handler configuration properties.
2635 * This may contain any of the following properties:<ul>
2636 * <li><b>scope</b> Object : <div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2637 * <b>If omitted, defaults to this Element.</b></div></li>
2638 * <li><b>delegate</b> String: <div class="sub-desc">A simple selector to filter the target or look for a descendant of the target. See below for additional details.</div></li>
2639 * <li><b>stopEvent</b> Boolean: <div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
2640 * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>
2641 * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>
2642 * <li><b>normalized</b> Boolean: <div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
2643 * <li><b>target</b> Ext.Element: <div class="sub-desc">Only call the handler if the event was fired on the target Element, <i>not</i> if the event was bubbled up from a child node.</div></li>
2644 * <li><b>delay</b> Number: <div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
2645 * <li><b>single</b> Boolean: <div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
2646 * <li><b>buffer</b> Number: <div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
2647 * by the specified number of milliseconds. If the event fires again within that time, the original
2648 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
2651 * <b>Combining Options</b><br>
2652 * In the following examples, the shorthand form {@link #on} is used rather than the more verbose
2653 * addListener. The two are equivalent. Using the options argument, it is possible to combine different
2654 * types of listeners:<br>
2656 * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the
2657 * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">
2659 el.on('click', this.onClick, this, {
2664 });</code></pre></p>
2666 * <b>Attaching multiple handlers in 1 call</b><br>
2667 * The method also allows for a single argument to be passed which is a config object containing properties
2668 * which specify multiple handlers.</p>
2678 fn: this.onMouseOver,
2682 fn: this.onMouseOut,
2687 * Or a shorthand syntax:<br>
2688 * Code:<pre><code></p>
2690 'click' : this.onClick,
2691 'mouseover' : this.onMouseOver,
2692 'mouseout' : this.onMouseOut,
2696 * <p><b>delegate</b></p>
2697 * <p>This is a configuration option that you can pass along when registering a handler for
2698 * an event to assist with event delegation. Event delegation is a technique that is used to
2699 * reduce memory consumption and prevent exposure to memory-leaks. By registering an event
2700 * for a container element as opposed to each element within a container. By setting this
2701 * configuration option to a simple selector, the target element will be filtered to look for
2702 * a descendant of the target.
2703 * For example:<pre><code>
2704 // using this markup:
2706 <p id='p1'>paragraph one</p>
2707 <p id='p2' class='clickable'>paragraph two</p>
2708 <p id='p3'>paragraph three</p>
2710 // utilize event delegation to registering just one handler on the container element:
2711 el = Ext.get('elId');
2716 console.info(t.id); // 'p2'
2720 // filter the target element to be a descendant with the class 'clickable'
2721 delegate: '.clickable'
2725 * @return {Ext.Element} this
2727 addListener : function(eventName, fn, scope, options){
2728 Ext.EventManager.on(this.dom, eventName, fn, scope || this, options);
2733 * Removes an event handler from this element. The shorthand version {@link #un} is equivalent.
2734 * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the
2735 * listener, the same scope must be specified here.
2738 el.removeListener('click', this.handlerFn);
2740 el.un('click', this.handlerFn);
2742 * @param {String} eventName The name of the event from which to remove the handler.
2743 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2744 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
2745 * then this must refer to the same object.
2746 * @return {Ext.Element} this
2748 removeListener : function(eventName, fn, scope){
2749 Ext.EventManager.removeListener(this.dom, eventName, fn, scope || this);
2754 * Removes all previous added listeners from this element
2755 * @return {Ext.Element} this
2757 removeAllListeners : function(){
2758 Ext.EventManager.removeAll(this.dom);
2763 * Recursively removes all previous added listeners from this element and its children
2764 * @return {Ext.Element} this
2766 purgeAllListeners : function() {
2767 Ext.EventManager.purgeElement(this, true);
2771 * @private Test if size has a unit, otherwise appends the default
2773 addUnits : function(size){
2774 if(size === "" || size == "auto" || size === undefined){
2776 } else if(!isNaN(size) || !unitPattern.test(size)){
2777 size = size + (this.defaultUnit || 'px');
2783 * <p>Updates the <a href="http://developer.mozilla.org/en/DOM/element.innerHTML">innerHTML</a> of this Element
2784 * from a specified URL. Note that this is subject to the <a href="http://en.wikipedia.org/wiki/Same_origin_policy">Same Origin Policy</a></p>
2785 * <p>Updating innerHTML of an element will <b>not</b> execute embedded <tt><script></tt> elements. This is a browser restriction.</p>
2786 * @param {Mixed} options. Either a sring containing the URL from which to load the HTML, or an {@link Ext.Ajax#request} options object specifying
2787 * exactly how to request the HTML.
2788 * @return {Ext.Element} this
2790 load : function(url, params, cb){
2791 Ext.Ajax.request(Ext.apply({
2793 url: url.url || url,
2796 indicatorText: url.indicatorText || ''
2797 }, Ext.isObject(url) ? url : {}));
2802 * Tests various css rules/browsers to determine if this element uses a border box
2805 isBorderBox : function(){
2806 return Ext.isBorderBox || Ext.isForcedBorderBox || noBoxAdjust[(this.dom.tagName || "").toLowerCase()];
2810 * <p>Removes this element's dom reference. Note that event and cache removal is handled at {@link Ext#removeNode}</p>
2812 remove : function(){
2818 Ext.removeNode(dom);
2823 * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
2824 * @param {Function} overFn The function to call when the mouse enters the Element.
2825 * @param {Function} outFn The function to call when the mouse leaves the Element.
2826 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the functions are executed. Defaults to the Element's DOM element.
2827 * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.
2828 * @return {Ext.Element} this
2830 hover : function(overFn, outFn, scope, options){
2832 me.on('mouseenter', overFn, scope || me.dom, options);
2833 me.on('mouseleave', outFn, scope || me.dom, options);
2838 * Returns true if this element is an ancestor of the passed element
2839 * @param {HTMLElement/String} el The element to check
2840 * @return {Boolean} True if this element is an ancestor of el, else false
2842 contains : function(el){
2843 return !el ? false : Ext.lib.Dom.isAncestor(this.dom, el.dom ? el.dom : el);
2847 * Returns the value of a namespaced attribute from the element's underlying DOM node.
2848 * @param {String} namespace The namespace in which to look for the attribute
2849 * @param {String} name The attribute name
2850 * @return {String} The attribute value
2853 getAttributeNS : function(ns, name){
2854 return this.getAttribute(name, ns);
2858 * Returns the value of an attribute from the element's underlying DOM node.
2859 * @param {String} name The attribute name
2860 * @param {String} namespace (optional) The namespace in which to look for the attribute
2861 * @return {String} The attribute value
2863 getAttribute : Ext.isIE ? function(name, ns){
2865 type = typeof d[ns + ":" + name];
2867 if(['undefined', 'unknown'].indexOf(type) == -1){
2868 return d[ns + ":" + name];
2871 } : function(name, ns){
2873 return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name) || d.getAttribute(name) || d[name];
2877 * Update the innerHTML of this element
2878 * @param {String} html The new HTML
2879 * @return {Ext.Element} this
2881 update : function(html) {
2883 this.dom.innerHTML = html;
2889 var ep = El.prototype;
2891 El.addMethods = function(o){
2896 * Appends an event handler (shorthand for {@link #addListener}).
2897 * @param {String} eventName The name of event to handle.
2898 * @param {Function} fn The handler function the event invokes.
2899 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
2900 * @param {Object} options (optional) An object containing standard {@link #addListener} options
2901 * @member Ext.Element
2904 ep.on = ep.addListener;
2907 * Removes an event handler from this element (see {@link #removeListener} for additional notes).
2908 * @param {String} eventName The name of the event from which to remove the handler.
2909 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2910 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
2911 * then this must refer to the same object.
2912 * @return {Ext.Element} this
2913 * @member Ext.Element
2916 ep.un = ep.removeListener;
2919 * true to automatically adjust width and height settings for box-model issues (default to true)
2921 ep.autoBoxAdjust = true;
2924 var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
2932 * Retrieves Ext.Element objects.
2933 * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
2934 * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by
2935 * its ID, use {@link Ext.ComponentMgr#get}.</p>
2936 * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
2937 * object was recreated with the same id via AJAX or DOM.</p>
2938 * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
2939 * @return {Element} The Element object (or null if no matching element was found)
2941 * @member Ext.Element
2944 El.get = function(el){
2948 if(!el){ return null; }
2949 if (typeof el == "string") { // element id
2950 if (!(elm = DOC.getElementById(el))) {
2953 if (EC[el] && EC[el].el) {
2957 ex = El.addToCache(new El(elm));
2960 } else if (el.tagName) { // dom element
2964 if (EC[id] && EC[id].el) {
2968 ex = El.addToCache(new El(el));
2971 } else if (el instanceof El) {
2973 // refresh dom element in case no longer valid,
2974 // catch case where it hasn't been appended
2976 // If an el instance is passed, don't pass to getElementById without some kind of id
2977 if (Ext.isIE && (el.id == undefined || el.id == '')) {
2980 el.dom = DOC.getElementById(el.id) || el.dom;
2984 } else if(el.isComposite) {
2986 } else if(Ext.isArray(el)) {
2987 return El.select(el);
2988 } else if(el == DOC) {
2989 // create a bogus element object representing the document object
2991 var f = function(){};
2992 f.prototype = El.prototype;
3001 El.addToCache = function(el, id){
3011 // private method for getting and setting element data
3012 El.data = function(el, key, value){
3017 var c = EC[el.id].data;
3018 if(arguments.length == 2){
3021 return (c[key] = value);
3026 // Garbage collection - uncache elements/purge listeners on orphaned elements
3027 // so we don't hold a reference and cause the browser to retain them
3028 function garbageCollect(){
3029 if(!Ext.enableGarbageCollector){
3030 clearInterval(El.collectorThreadId);
3044 // -------------------------------------------------------
3045 // Determining what is garbage:
3046 // -------------------------------------------------------
3048 // dom node is null, definitely garbage
3049 // -------------------------------------------------------
3051 // no parentNode == direct orphan, definitely garbage
3052 // -------------------------------------------------------
3053 // !d.offsetParent && !document.getElementById(eid)
3054 // display none elements have no offsetParent so we will
3055 // also try to look it up by it's id. However, check
3056 // offsetParent first so we don't do unneeded lookups.
3057 // This enables collection of elements that are not orphans
3058 // directly, but somewhere up the line they have an orphan
3060 // -------------------------------------------------------
3061 if(!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))){
3062 if(Ext.enableListenerCollection){
3063 Ext.EventManager.removeAll(d);
3068 // Cleanup IE Object leaks
3074 EC = Ext.elCache = t;
3078 El.collectorThreadId = setInterval(garbageCollect, 30000);
3080 var flyFn = function(){};
3081 flyFn.prototype = El.prototype;
3084 El.Flyweight = function(dom){
3088 El.Flyweight.prototype = new flyFn();
3089 El.Flyweight.prototype.isFlyweight = true;
3090 El._flyweights = {};
3093 * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3094 * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>
3095 * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
3096 * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}
3097 * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>
3098 * @param {String/HTMLElement} el The dom node or id
3099 * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
3100 * (e.g. internally Ext uses "_global")
3101 * @return {Element} The shared Element object (or null if no matching element was found)
3102 * @member Ext.Element
3105 El.fly = function(el, named){
3107 named = named || '_global';
3109 if (el = Ext.getDom(el)) {
3110 (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
3111 ret = El._flyweights[named];
3117 * Retrieves Ext.Element objects.
3118 * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
3119 * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by
3120 * its ID, use {@link Ext.ComponentMgr#get}.</p>
3121 * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
3122 * object was recreated with the same id via AJAX or DOM.</p>
3123 * Shorthand of {@link Ext.Element#get}
3124 * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
3125 * @return {Element} The Element object (or null if no matching element was found)
3132 * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3133 * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>
3134 * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
3135 * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}
3136 * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>
3137 * @param {String/HTMLElement} el The dom node or id
3138 * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
3139 * (e.g. internally Ext uses "_global")
3140 * @return {Element} The shared Element object (or null if no matching element was found)
3146 // speedy lookup for elements never to box adjust
3147 var noBoxAdjust = Ext.isStrict ? {
3150 input:1, select:1, textarea:1
3152 if(Ext.isIE || Ext.isGecko){
3153 noBoxAdjust['button'] = 1;
3158 * @class Ext.Element
3160 Ext.Element.addMethods(function(){
3161 var PARENTNODE = 'parentNode',
3162 NEXTSIBLING = 'nextSibling',
3163 PREVIOUSSIBLING = 'previousSibling',
3169 * 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)
3170 * @param {String} selector The simple selector to test
3171 * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
3172 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
3173 * @return {HTMLElement} The matching DOM node (or null if no match was found)
3175 findParent : function(simpleSelector, maxDepth, returnEl){
3180 if(Ext.isGecko && Object.prototype.toString.call(p) == '[object XULElement]') {
3183 maxDepth = maxDepth || 50;
3184 if (isNaN(maxDepth)) {
3185 stopEl = Ext.getDom(maxDepth);
3186 maxDepth = Number.MAX_VALUE;
3188 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
3189 if(DQ.is(p, simpleSelector)){
3190 return returnEl ? GET(p) : p;
3199 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
3200 * @param {String} selector The simple selector to test
3201 * @param {Number/Mixed} maxDepth (optional) The max depth to
3202 search as a number or element (defaults to 10 || document.body)
3203 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
3204 * @return {HTMLElement} The matching DOM node (or null if no match was found)
3206 findParentNode : function(simpleSelector, maxDepth, returnEl){
3207 var p = Ext.fly(this.dom.parentNode, '_internal');
3208 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
3212 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
3213 * This is a shortcut for findParentNode() that always returns an Ext.Element.
3214 * @param {String} selector The simple selector to test
3215 * @param {Number/Mixed} maxDepth (optional) The max depth to
3216 search as a number or element (defaults to 10 || document.body)
3217 * @return {Ext.Element} The matching DOM node (or null if no match was found)
3219 up : function(simpleSelector, maxDepth){
3220 return this.findParentNode(simpleSelector, maxDepth, true);
3224 * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
3225 * @param {String} selector The CSS selector
3226 * @return {CompositeElement/CompositeElementLite} The composite element
3228 select : function(selector){
3229 return Ext.Element.select(selector, this.dom);
3233 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
3234 * @param {String} selector The CSS selector
3235 * @return {Array} An array of the matched nodes
3237 query : function(selector){
3238 return DQ.select(selector, this.dom);
3242 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
3243 * @param {String} selector The CSS selector
3244 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
3245 * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
3247 child : function(selector, returnDom){
3248 var n = DQ.selectNode(selector, this.dom);
3249 return returnDom ? n : GET(n);
3253 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
3254 * @param {String} selector The CSS selector
3255 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
3256 * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
3258 down : function(selector, returnDom){
3259 var n = DQ.selectNode(" > " + selector, this.dom);
3260 return returnDom ? n : GET(n);
3264 * Gets the parent node for this element, optionally chaining up trying to match a selector
3265 * @param {String} selector (optional) Find a parent node that matches the passed simple selector
3266 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3267 * @return {Ext.Element/HTMLElement} The parent node or null
3269 parent : function(selector, returnDom){
3270 return this.matchNode(PARENTNODE, PARENTNODE, selector, returnDom);
3274 * Gets the next sibling, skipping text nodes
3275 * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
3276 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3277 * @return {Ext.Element/HTMLElement} The next sibling or null
3279 next : function(selector, returnDom){
3280 return this.matchNode(NEXTSIBLING, NEXTSIBLING, selector, returnDom);
3284 * Gets the previous sibling, skipping text nodes
3285 * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
3286 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3287 * @return {Ext.Element/HTMLElement} The previous sibling or null
3289 prev : function(selector, returnDom){
3290 return this.matchNode(PREVIOUSSIBLING, PREVIOUSSIBLING, selector, returnDom);
3295 * Gets the first child, skipping text nodes
3296 * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
3297 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3298 * @return {Ext.Element/HTMLElement} The first child or null
3300 first : function(selector, returnDom){
3301 return this.matchNode(NEXTSIBLING, 'firstChild', selector, returnDom);
3305 * Gets the last child, skipping text nodes
3306 * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
3307 * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3308 * @return {Ext.Element/HTMLElement} The last child or null
3310 last : function(selector, returnDom){
3311 return this.matchNode(PREVIOUSSIBLING, 'lastChild', selector, returnDom);
3314 matchNode : function(dir, start, selector, returnDom){
3315 var n = this.dom[start];
3317 if(n.nodeType == 1 && (!selector || DQ.is(n, selector))){
3318 return !returnDom ? GET(n) : n;
3326 * @class Ext.Element
3328 Ext.Element.addMethods(
3330 var GETDOM = Ext.getDom,
3336 * Appends the passed element(s) to this element
3337 * @param {String/HTMLElement/Array/Element/CompositeElement} el
3338 * @return {Ext.Element} this
3340 appendChild: function(el){
3341 return GET(el).appendTo(this);
3345 * Appends this element to the passed element
3346 * @param {Mixed} el The new parent element
3347 * @return {Ext.Element} this
3349 appendTo: function(el){
3350 GETDOM(el).appendChild(this.dom);
3355 * Inserts this element before the passed element in the DOM
3356 * @param {Mixed} el The element before which this element will be inserted
3357 * @return {Ext.Element} this
3359 insertBefore: function(el){
3360 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el);
3365 * Inserts this element after the passed element in the DOM
3366 * @param {Mixed} el The element to insert after
3367 * @return {Ext.Element} this
3369 insertAfter: function(el){
3370 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el.nextSibling);
3375 * Inserts (or creates) an element (or DomHelper config) as the first child of this element
3376 * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
3377 * @return {Ext.Element} The new child
3379 insertFirst: function(el, returnDom){
3381 if(el.nodeType || el.dom || typeof el == 'string'){ // element
3383 this.dom.insertBefore(el, this.dom.firstChild);
3384 return !returnDom ? GET(el) : el;
3386 return this.createChild(el, this.dom.firstChild, returnDom);
3391 * Replaces the passed element with this element
3392 * @param {Mixed} el The element to replace
3393 * @return {Ext.Element} this
3395 replace: function(el){
3397 this.insertBefore(el);
3403 * Replaces this element with the passed element
3404 * @param {Mixed/Object} el The new element or a DomHelper config of an element to create
3405 * @return {Ext.Element} this
3407 replaceWith: function(el){
3410 if(el.nodeType || el.dom || typeof el == 'string'){
3412 me.dom.parentNode.insertBefore(el, me.dom);
3414 el = DH.insertBefore(me.dom, el);
3417 delete Ext.elCache[me.id];
3418 Ext.removeNode(me.dom);
3419 me.id = Ext.id(me.dom = el);
3420 Ext.Element.addToCache(me.isFlyweight ? new Ext.Element(me.dom) : me);
3425 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
3426 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
3427 * automatically generated with the specified attributes.
3428 * @param {HTMLElement} insertBefore (optional) a child element of this element
3429 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
3430 * @return {Ext.Element} The new child element
3432 createChild: function(config, insertBefore, returnDom){
3433 config = config || {tag:'div'};
3434 return insertBefore ?
3435 DH.insertBefore(insertBefore, config, returnDom !== true) :
3436 DH[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
3440 * Creates and wraps this element with another element
3441 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
3442 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
3443 * @return {HTMLElement/Element} The newly created wrapper element
3445 wrap: function(config, returnDom){
3446 var newEl = DH.insertBefore(this.dom, config || {tag: "div"}, !returnDom);
3447 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
3452 * Inserts an html fragment into this element
3453 * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
3454 * @param {String} html The HTML fragment
3455 * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)
3456 * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)
3458 insertHtml : function(where, html, returnEl){
3459 var el = DH.insertHtml(where, this.dom, html);
3460 return returnEl ? Ext.get(el) : el;
3464 * @class Ext.Element
3466 Ext.Element.addMethods(function(){
3467 // local style camelizing for speed
3468 var supports = Ext.supports,
3470 camelRe = /(-[a-z])/gi,
3471 view = document.defaultView,
3472 opacityRe = /alpha\(opacity=(.*)\)/i,
3473 trimRe = /^\s+|\s+$/g,
3477 PADDING = "padding",
3487 ISCLIPPED = 'isClipped',
3488 OVERFLOW = 'overflow',
3489 OVERFLOWX = 'overflow-x',
3490 OVERFLOWY = 'overflow-y',
3491 ORIGINALCLIP = 'originalClip',
3492 // special markup used throughout Ext when box wrapping elements
3493 borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
3494 paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
3495 margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
3496 data = Ext.Element.data;
3500 function camelFn(m, a) {
3501 return a.charAt(1).toUpperCase();
3504 function chkCache(prop) {
3505 return propCache[prop] || (propCache[prop] = prop == 'float' ? (supports.cssFloat ? 'cssFloat' : 'styleFloat') : prop.replace(camelRe, camelFn));
3509 // private ==> used by Fx
3510 adjustWidth : function(width) {
3512 var isNum = (typeof width == "number");
3513 if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
3514 width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
3516 return (isNum && width < 0) ? 0 : width;
3519 // private ==> used by Fx
3520 adjustHeight : function(height) {
3522 var isNum = (typeof height == "number");
3523 if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
3524 height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
3526 return (isNum && height < 0) ? 0 : height;
3531 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
3532 * @param {String/Array} className The CSS class to add, or an array of classes
3533 * @return {Ext.Element} this
3535 addClass : function(className){
3541 // Separate case is for speed
3542 if (!Ext.isArray(className)) {
3543 if (typeof className == 'string' && !this.hasClass(className)) {
3544 me.dom.className += " " + className;
3548 for (i = 0, len = className.length; i < len; i++) {
3550 if (typeof v == 'string' && (' ' + me.dom.className + ' ').indexOf(' ' + v + ' ') == -1) {
3555 me.dom.className += " " + cls.join(" ");
3562 * Removes one or more CSS classes from the element.
3563 * @param {String/Array} className The CSS class to remove, or an array of classes
3564 * @return {Ext.Element} this
3566 removeClass : function(className){
3573 if (!Ext.isArray(className)){
3574 className = [className];
3576 if (me.dom && me.dom.className) {
3577 elClasses = me.dom.className.replace(trimRe, '').split(spacesRe);
3578 for (i = 0, len = className.length; i < len; i++) {
3580 if (typeof cls == 'string') {
3581 cls = cls.replace(trimRe, '');
3582 idx = elClasses.indexOf(cls);
3584 elClasses.splice(idx, 1);
3588 me.dom.className = elClasses.join(" ");
3594 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
3595 * @param {String/Array} className The CSS class to add, or an array of classes
3596 * @return {Ext.Element} this
3598 radioClass : function(className){
3599 var cn = this.dom.parentNode.childNodes,
3603 className = Ext.isArray(className) ? className : [className];
3604 for (i = 0, len = cn.length; i < len; i++) {
3606 if (v && v.nodeType == 1) {
3607 Ext.fly(v, '_internal').removeClass(className);
3610 return this.addClass(className);
3614 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
3615 * @param {String} className The CSS class to toggle
3616 * @return {Ext.Element} this
3618 toggleClass : function(className){
3619 return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
3623 * Checks if the specified CSS class exists on this element's DOM node.
3624 * @param {String} className The CSS class to check for
3625 * @return {Boolean} True if the class exists, else false
3627 hasClass : function(className){
3628 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
3632 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
3633 * @param {String} oldClassName The CSS class to replace
3634 * @param {String} newClassName The replacement CSS class
3635 * @return {Ext.Element} this
3637 replaceClass : function(oldClassName, newClassName){
3638 return this.removeClass(oldClassName).addClass(newClassName);
3641 isStyle : function(style, val) {
3642 return this.getStyle(style) == val;
3646 * Normalizes currentStyle and computedStyle.
3647 * @param {String} property The style property whose value is returned.
3648 * @return {String} The current value of the style property for this element.
3650 getStyle : function(){
3651 return view && view.getComputedStyle ?
3662 prop = chkCache(prop);
3663 out = (v = el.style[prop]) ? v :
3664 (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
3666 // Ignore cases when the margin is correctly reported as 0, the bug only shows
3668 if(prop == 'marginRight' && out != '0px' && !supports.correctRightMargin){
3669 display = el.style.display;
3670 el.style.display = 'inline-block';
3671 out = view.getComputedStyle(el, '').marginRight;
3672 el.style.display = display;
3675 if(prop == 'backgroundColor' && out == 'rgba(0, 0, 0, 0)' && !supports.correctTransparentColor){
3676 out = 'transparent';
3685 if(el == document) return null;
3686 if (prop == 'opacity') {
3687 if (el.style.filter.match) {
3688 if(m = el.style.filter.match(opacityRe)){
3689 var fv = parseFloat(m[1]);
3691 return fv ? fv / 100 : 0;
3697 prop = chkCache(prop);
3698 return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
3703 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
3704 * are convert to standard 6 digit hex color.
3705 * @param {String} attr The css attribute
3706 * @param {String} defaultValue The default value to use when a valid color isn't found
3707 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
3710 getColor : function(attr, defaultValue, prefix){
3711 var v = this.getStyle(attr),
3712 color = (typeof prefix != 'undefined') ? prefix : '#',
3715 if(!v || (/transparent|inherit/.test(v))) {
3716 return defaultValue;
3719 Ext.each(v.slice(4, v.length -1).split(','), function(s){
3720 h = parseInt(s, 10);
3721 color += (h < 16 ? '0' : '') + h.toString(16);
3724 v = v.replace('#', '');
3725 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
3727 return(color.length > 5 ? color.toLowerCase() : defaultValue);
3731 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
3732 * @param {String/Object} property The style property to be set, or an object of multiple styles.
3733 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
3734 * @return {Ext.Element} this
3736 setStyle : function(prop, value){
3739 if (typeof prop != 'object') {
3744 for (style in prop) {
3745 value = prop[style];
3746 style == 'opacity' ?
3747 this.setOpacity(value) :
3748 this.dom.style[chkCache(style)] = value;
3754 * Set the opacity of the element
3755 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
3756 * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
3757 * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
3758 * @return {Ext.Element} this
3760 setOpacity : function(opacity, animate){
3764 if(!animate || !me.anim){
3766 var opac = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')' : '',
3767 val = s.filter.replace(opacityRe, '').replace(trimRe, '');
3770 s.filter = val + (val.length > 0 ? ' ' : '') + opac;
3772 s.opacity = opacity;
3775 me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn');
3781 * Clears any opacity settings from this element. Required in some cases for IE.
3782 * @return {Ext.Element} this
3784 clearOpacity : function(){
3785 var style = this.dom.style;
3787 if(!Ext.isEmpty(style.filter)){
3788 style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
3791 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
3797 * Returns the offset height of the element
3798 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
3799 * @return {Number} The element's height
3801 getHeight : function(contentHeight){
3804 hidden = Ext.isIE && me.isStyle('display', 'none'),
3805 h = MATH.max(dom.offsetHeight, hidden ? 0 : dom.clientHeight) || 0;
3807 h = !contentHeight ? h : h - me.getBorderWidth("tb") - me.getPadding("tb");
3808 return h < 0 ? 0 : h;
3812 * Returns the offset width of the element
3813 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
3814 * @return {Number} The element's width
3816 getWidth : function(contentWidth){
3819 hidden = Ext.isIE && me.isStyle('display', 'none'),
3820 w = MATH.max(dom.offsetWidth, hidden ? 0 : dom.clientWidth) || 0;
3821 w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");
3822 return w < 0 ? 0 : w;
3826 * Set the width of this Element.
3827 * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
3828 * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
3829 * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
3831 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
3832 * @return {Ext.Element} this
3834 setWidth : function(width, animate){
3836 width = me.adjustWidth(width);
3837 !animate || !me.anim ?
3838 me.dom.style.width = me.addUnits(width) :
3839 me.anim({width : {to : width}}, me.preanim(arguments, 1));
3844 * Set the height of this Element.
3846 // change the height to 200px and animate with default configuration
3847 Ext.fly('elementId').setHeight(200, true);
3849 // change the height to 150px and animate with a custom configuration
3850 Ext.fly('elId').setHeight(150, {
3851 duration : .5, // animation will have a duration of .5 seconds
3852 // will change the content to "finished"
3853 callback: function(){ this.{@link #update}("finished"); }
3856 * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
3857 * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
3858 * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
3860 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
3861 * @return {Ext.Element} this
3863 setHeight : function(height, animate){
3865 height = me.adjustHeight(height);
3866 !animate || !me.anim ?
3867 me.dom.style.height = me.addUnits(height) :
3868 me.anim({height : {to : height}}, me.preanim(arguments, 1));
3873 * Gets the width of the border(s) for the specified side(s)
3874 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
3875 * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
3876 * @return {Number} The width of the sides passed added together
3878 getBorderWidth : function(side){
3879 return this.addStyles(side, borders);
3883 * Gets the width of the padding(s) for the specified side(s)
3884 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
3885 * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
3886 * @return {Number} The padding of the sides passed added together
3888 getPadding : function(side){
3889 return this.addStyles(side, paddings);
3893 * Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
3894 * @return {Ext.Element} this
3900 if(!data(dom, ISCLIPPED)){
3901 data(dom, ISCLIPPED, true);
3902 data(dom, ORIGINALCLIP, {
3903 o: me.getStyle(OVERFLOW),
3904 x: me.getStyle(OVERFLOWX),
3905 y: me.getStyle(OVERFLOWY)
3907 me.setStyle(OVERFLOW, HIDDEN);
3908 me.setStyle(OVERFLOWX, HIDDEN);
3909 me.setStyle(OVERFLOWY, HIDDEN);
3915 * Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
3916 * @return {Ext.Element} this
3918 unclip : function(){
3922 if(data(dom, ISCLIPPED)){
3923 data(dom, ISCLIPPED, false);
3924 var o = data(dom, ORIGINALCLIP);
3926 me.setStyle(OVERFLOW, o.o);
3929 me.setStyle(OVERFLOWX, o.x);
3932 me.setStyle(OVERFLOWY, o.y);
3939 addStyles : function(sides, styles){
3941 sidesArr = sides.match(wordsRe),
3945 len = sidesArr.length;
3946 for (i = 0; i < len; i++) {
3948 size = side && parseInt(this.getStyle(styles[side]), 10);
3950 ttlSize += MATH.abs(size);
3961 * @class Ext.Element
3964 var D = Ext.lib.Dom,
3969 POSITION = "position",
3971 RELATIVE = "relative",
3975 Ext.Element.addMethods({
3977 * 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).
3978 * @return {Number} The X position of the element
3981 return D.getX(this.dom);
3985 * 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).
3986 * @return {Number} The Y position of the element
3989 return D.getY(this.dom);
3993 * 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).
3994 * @return {Array} The XY position of the element
3997 return D.getXY(this.dom);
4001 * 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.
4002 * @param {Mixed} element The element to get the offsets from.
4003 * @return {Array} The XY page offsets (e.g. [100, -200])
4005 getOffsetsTo : function(el){
4006 var o = this.getXY(),
4007 e = Ext.fly(el, '_internal').getXY();
4008 return [o[0]-e[0],o[1]-e[1]];
4012 * 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).
4013 * @param {Number} The X position of the element
4014 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4015 * @return {Ext.Element} this
4017 setX : function(x, animate){
4018 return this.setXY([x, this.getY()], this.animTest(arguments, animate, 1));
4022 * 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).
4023 * @param {Number} The Y position of the element
4024 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4025 * @return {Ext.Element} this
4027 setY : function(y, animate){
4028 return this.setXY([this.getX(), y], this.animTest(arguments, animate, 1));
4032 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
4033 * @param {String} left The left CSS property value
4034 * @return {Ext.Element} this
4036 setLeft : function(left){
4037 this.setStyle(LEFT, this.addUnits(left));
4042 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
4043 * @param {String} top The top CSS property value
4044 * @return {Ext.Element} this
4046 setTop : function(top){
4047 this.setStyle(TOP, this.addUnits(top));
4052 * Sets the element's CSS right style.
4053 * @param {String} right The right CSS property value
4054 * @return {Ext.Element} this
4056 setRight : function(right){
4057 this.setStyle(RIGHT, this.addUnits(right));
4062 * Sets the element's CSS bottom style.
4063 * @param {String} bottom The bottom CSS property value
4064 * @return {Ext.Element} this
4066 setBottom : function(bottom){
4067 this.setStyle(BOTTOM, this.addUnits(bottom));
4072 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
4073 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
4074 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
4075 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4076 * @return {Ext.Element} this
4078 setXY : function(pos, animate){
4080 if(!animate || !me.anim){
4081 D.setXY(me.dom, pos);
4083 me.anim({points: {to: pos}}, me.preanim(arguments, 1), 'motion');
4089 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
4090 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
4091 * @param {Number} x X value for new position (coordinates are page-based)
4092 * @param {Number} y Y value for new position (coordinates are page-based)
4093 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4094 * @return {Ext.Element} this
4096 setLocation : function(x, y, animate){
4097 return this.setXY([x, y], this.animTest(arguments, animate, 2));
4101 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
4102 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
4103 * @param {Number} x X value for new position (coordinates are page-based)
4104 * @param {Number} y Y value for new position (coordinates are page-based)
4105 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4106 * @return {Ext.Element} this
4108 moveTo : function(x, y, animate){
4109 return this.setXY([x, y], this.animTest(arguments, animate, 2));
4113 * Gets the left X coordinate
4114 * @param {Boolean} local True to get the local css position instead of page coordinate
4117 getLeft : function(local){
4118 return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
4122 * Gets the right X coordinate of the element (element X position + element width)
4123 * @param {Boolean} local True to get the local css position instead of page coordinate
4126 getRight : function(local){
4128 return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
4132 * Gets the top Y coordinate
4133 * @param {Boolean} local True to get the local css position instead of page coordinate
4136 getTop : function(local) {
4137 return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
4141 * Gets the bottom Y coordinate of the element (element Y position + element height)
4142 * @param {Boolean} local True to get the local css position instead of page coordinate
4145 getBottom : function(local){
4147 return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
4151 * Initializes positioning on this element. If a desired position is not passed, it will make the
4152 * the element positioned relative IF it is not already positioned.
4153 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
4154 * @param {Number} zIndex (optional) The zIndex to apply
4155 * @param {Number} x (optional) Set the page X position
4156 * @param {Number} y (optional) Set the page Y position
4158 position : function(pos, zIndex, x, y){
4161 if(!pos && me.isStyle(POSITION, STATIC)){
4162 me.setStyle(POSITION, RELATIVE);
4164 me.setStyle(POSITION, pos);
4167 me.setStyle(ZINDEX, zIndex);
4169 if(x || y) me.setXY([x || false, y || false]);
4173 * Clear positioning back to the default when the document was loaded
4174 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
4175 * @return {Ext.Element} this
4177 clearPositioning : function(value){
4178 value = value || '';
4191 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
4192 * snapshot before performing an update and then restoring the element.
4195 getPositioning : function(){
4196 var l = this.getStyle(LEFT);
4197 var t = this.getStyle(TOP);
4199 "position" : this.getStyle(POSITION),
4201 "right" : l ? "" : this.getStyle(RIGHT),
4203 "bottom" : t ? "" : this.getStyle(BOTTOM),
4204 "z-index" : this.getStyle(ZINDEX)
4209 * Set positioning with an object returned by getPositioning().
4210 * @param {Object} posCfg
4211 * @return {Ext.Element} this
4213 setPositioning : function(pc){
4215 style = me.dom.style;
4219 if(pc.right == AUTO){
4222 if(pc.bottom == AUTO){
4230 * Translates the passed page coordinates into left/top css values for this element
4231 * @param {Number/Array} x The page x or an array containing [x, y]
4232 * @param {Number} y (optional) The page y, required if x is not an array
4233 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
4235 translatePoints : function(x, y){
4236 y = isNaN(x[1]) ? y : x[1];
4237 x = isNaN(x[0]) ? x : x[0];
4239 relative = me.isStyle(POSITION, RELATIVE),
4241 l = parseInt(me.getStyle(LEFT), 10),
4242 t = parseInt(me.getStyle(TOP), 10);
4244 l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);
4245 t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);
4247 return {left: (x - o[0] + l), top: (y - o[1] + t)};
4250 animTest : function(args, animate, i) {
4251 return !!animate && this.preanim ? this.preanim(args, i) : false;
4255 * @class Ext.Element
4257 Ext.Element.addMethods({
4259 * Returns true if this element is scrollable.
4262 isScrollable : function(){
4264 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
4268 * 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().
4269 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
4270 * @param {Number} value The new scroll value.
4271 * @return {Element} this
4273 scrollTo : function(side, value){
4274 this.dom["scroll" + (/top/i.test(side) ? "Top" : "Left")] = value;
4279 * Returns the current scroll position of the element.
4280 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
4282 getScroll : function(){
4286 docElement = doc.documentElement,
4291 if(d == doc || d == body){
4292 if(Ext.isIE && Ext.isStrict){
4293 l = docElement.scrollLeft;
4294 t = docElement.scrollTop;
4296 l = window.pageXOffset;
4297 t = window.pageYOffset;
4299 ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)};
4301 ret = {left: d.scrollLeft, top: d.scrollTop};
4306 * @class Ext.Element
4309 * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
4313 Ext.Element.VISIBILITY = 1;
4315 * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
4319 Ext.Element.DISPLAY = 2;
4322 * Visibility mode constant for use with {@link #setVisibilityMode}. Use offsets (x and y positioning offscreen)
4327 Ext.Element.OFFSETS = 3;
4330 Ext.Element.ASCLASS = 4;
4333 * Defaults to 'x-hide-nosize'
4337 Ext.Element.visibilityCls = 'x-hide-nosize';
4339 Ext.Element.addMethods(function(){
4340 var El = Ext.Element,
4341 OPACITY = "opacity",
4342 VISIBILITY = "visibility",
4343 DISPLAY = "display",
4345 OFFSETS = "offsets",
4346 ASCLASS = "asclass",
4349 ORIGINALDISPLAY = 'originalDisplay',
4350 VISMODE = 'visibilityMode',
4351 ISVISIBLE = 'isVisible',
4353 getDisplay = function(dom){
4354 var d = data(dom, ORIGINALDISPLAY);
4355 if(d === undefined){
4356 data(dom, ORIGINALDISPLAY, d = '');
4360 getVisMode = function(dom){
4361 var m = data(dom, VISMODE);
4362 if(m === undefined){
4363 data(dom, VISMODE, m = 1);
4370 * The element's default display mode (defaults to "")
4373 originalDisplay : "",
4377 * Sets the element's visibility mode. When setVisible() is called it
4378 * will use this to determine whether to set the visibility or the display property.
4379 * @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY
4380 * @return {Ext.Element} this
4382 setVisibilityMode : function(visMode){
4383 data(this.dom, VISMODE, visMode);
4388 * Perform custom animation on this element.
4389 * <div><ul class="mdetail-params">
4390 * <li><u>Animation Properties</u></li>
4392 * <p>The Animation Control Object enables gradual transitions for any member of an
4393 * element's style object that takes a numeric value including but not limited to
4394 * these properties:</p><div><ul class="mdetail-params">
4395 * <li><tt>bottom, top, left, right</tt></li>
4396 * <li><tt>height, width</tt></li>
4397 * <li><tt>margin, padding</tt></li>
4398 * <li><tt>borderWidth</tt></li>
4399 * <li><tt>opacity</tt></li>
4400 * <li><tt>fontSize</tt></li>
4401 * <li><tt>lineHeight</tt></li>
4405 * <li><u>Animation Property Attributes</u></li>
4407 * <p>Each Animation Property is a config object with optional properties:</p>
4408 * <div><ul class="mdetail-params">
4409 * <li><tt>by</tt>* : relative change - start at current value, change by this value</li>
4410 * <li><tt>from</tt> : ignore current value, start from this value</li>
4411 * <li><tt>to</tt>* : start at current value, go to this value</li>
4412 * <li><tt>unit</tt> : any allowable unit specification</li>
4413 * <p>* do not specify both <tt>to</tt> and <tt>by</tt> for an animation property</p>
4416 * <li><u>Animation Types</u></li>
4418 * <p>The supported animation types:</p><div><ul class="mdetail-params">
4419 * <li><tt>'run'</tt> : Default
4421 var el = Ext.get('complexEl');
4423 // animation control object
4425 borderWidth: {to: 3, from: 0},
4426 opacity: {to: .3, from: 1},
4427 height: {to: 50, from: el.getHeight()},
4428 width: {to: 300, from: el.getWidth()},
4429 top : {by: - 100, unit: 'px'},
4431 0.35, // animation duration
4433 'easeOut', // easing method
4434 'run' // animation type ('run','color','motion','scroll')
4438 * <li><tt>'color'</tt>
4439 * <p>Animates transition of background, text, or border colors.</p>
4442 // animation control object
4444 color: { to: '#06e' },
4445 backgroundColor: { to: '#e06' }
4447 0.35, // animation duration
4449 'easeOut', // easing method
4450 'color' // animation type ('run','color','motion','scroll')
4455 * <li><tt>'motion'</tt>
4456 * <p>Animates the motion of an element to/from specific points using optional bezier
4457 * way points during transit.</p>
4460 // animation control object
4462 borderWidth: {to: 3, from: 0},
4463 opacity: {to: .3, from: 1},
4464 height: {to: 50, from: el.getHeight()},
4465 width: {to: 300, from: el.getWidth()},
4466 top : {by: - 100, unit: 'px'},
4468 to: [50, 100], // go to this point
4469 control: [ // optional bezier way points
4475 3000, // animation duration (milliseconds!)
4477 'easeOut', // easing method
4478 'motion' // animation type ('run','color','motion','scroll')
4482 * <li><tt>'scroll'</tt>
4483 * <p>Animate horizontal or vertical scrolling of an overflowing page element.</p>
4486 // animation control object
4488 scroll: {to: [400, 300]}
4490 0.35, // animation duration
4492 'easeOut', // easing method
4493 'scroll' // animation type ('run','color','motion','scroll')
4501 * @param {Object} args The animation control args
4502 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to <tt>.35</tt>)
4503 * @param {Function} onComplete (optional) Function to call when animation completes
4504 * @param {String} easing (optional) {@link Ext.Fx#easing} method to use (defaults to <tt>'easeOut'</tt>)
4505 * @param {String} animType (optional) <tt>'run'</tt> is the default. Can also be <tt>'color'</tt>,
4506 * <tt>'motion'</tt>, or <tt>'scroll'</tt>
4507 * @return {Ext.Element} this
4509 animate : function(args, duration, onComplete, easing, animType){
4510 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
4515 * @private Internal animation call
4517 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
4518 animType = animType || 'run';
4521 anim = Ext.lib.Anim[animType](
4524 (opt.duration || defaultDur) || .35,
4525 (opt.easing || defaultEase) || 'easeOut',
4528 if(opt.callback) opt.callback.call(opt.scope || me, me, opt);
4536 // private legacy anim prep
4537 preanim : function(a, i){
4538 return !a[i] ? false : (typeof a[i] == 'object' ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
4542 * Checks whether the element is currently visible using both visibility and display properties.
4543 * @return {Boolean} True if the element is currently visible, else false
4545 isVisible : function() {
4548 visible = data(dom, ISVISIBLE);
4550 if(typeof visible == 'boolean'){ //return the cached value if registered
4553 //Determine the current state based on display states
4554 visible = !me.isStyle(VISIBILITY, HIDDEN) &&
4555 !me.isStyle(DISPLAY, NONE) &&
4556 !((getVisMode(dom) == El.ASCLASS) && me.hasClass(me.visibilityCls || El.visibilityCls));
4558 data(dom, ISVISIBLE, visible);
4563 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
4564 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
4565 * @param {Boolean} visible Whether the element is visible
4566 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4567 * @return {Ext.Element} this
4569 setVisible : function(visible, animate){
4570 var me = this, isDisplay, isVisibility, isOffsets, isNosize,
4572 visMode = getVisMode(dom);
4575 // hideMode string override
4576 if (typeof animate == 'string'){
4579 visMode = El.DISPLAY;
4582 visMode = El.VISIBILITY;
4585 visMode = El.OFFSETS;
4589 visMode = El.ASCLASS;
4592 me.setVisibilityMode(visMode);
4596 if (!animate || !me.anim) {
4597 if(visMode == El.ASCLASS ){
4599 me[visible?'removeClass':'addClass'](me.visibilityCls || El.visibilityCls);
4601 } else if (visMode == El.DISPLAY){
4603 return me.setDisplayed(visible);
4605 } else if (visMode == El.OFFSETS){
4608 me.hideModeStyles = {
4609 position: me.getStyle('position'),
4610 top: me.getStyle('top'),
4611 left: me.getStyle('left')
4613 me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
4615 me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
4616 delete me.hideModeStyles;
4621 dom.style.visibility = visible ? "visible" : HIDDEN;
4624 // closure for composites
4627 me.setVisible(true);
4629 me.anim({opacity: { to: (visible?1:0) }},
4630 me.preanim(arguments, 1),
4635 visible || me.setVisible(false).setOpacity(1);
4638 data(dom, ISVISIBLE, visible); //set logical visibility state
4645 * Determine if the Element has a relevant height and width available based
4646 * upon current logical visibility state
4648 hasMetrics : function(){
4650 return this.isVisible() || (getVisMode(dom) == El.VISIBILITY);
4654 * Toggles the element's visibility or display, depending on visibility mode.
4655 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4656 * @return {Ext.Element} this
4658 toggle : function(animate){
4660 me.setVisible(!me.isVisible(), me.preanim(arguments, 0));
4665 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
4666 * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
4667 * @return {Ext.Element} this
4669 setDisplayed : function(value) {
4670 if(typeof value == "boolean"){
4671 value = value ? getDisplay(this.dom) : NONE;
4673 this.setStyle(DISPLAY, value);
4678 fixDisplay : function(){
4680 if(me.isStyle(DISPLAY, NONE)){
4681 me.setStyle(VISIBILITY, HIDDEN);
4682 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
4683 if(me.isStyle(DISPLAY, NONE)){ // if that fails, default to block
4684 me.setStyle(DISPLAY, "block");
4690 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
4691 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
4692 * @return {Ext.Element} this
4694 hide : function(animate){
4695 // hideMode override
4696 if (typeof animate == 'string'){
4697 this.setVisible(false, animate);
4700 this.setVisible(false, this.preanim(arguments, 0));
4705 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
4706 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
4707 * @return {Ext.Element} this
4709 show : function(animate){
4710 // hideMode override
4711 if (typeof animate == 'string'){
4712 this.setVisible(true, animate);
4715 this.setVisible(true, this.preanim(arguments, 0));
4722 UNDEFINED = undefined,
4736 ABSOLUTE = "absolute",
4737 VISIBLE = "visible",
4739 POSITION = "position",
4740 EASEOUT = "easeOut",
4742 * Use a light flyweight here since we are using so many callbacks and are always assured a DOM element
4744 flyEl = new Ext.Element.Flyweight(),
4746 getObject = function(o){
4749 fly = function(dom){
4751 flyEl.id = Ext.id(dom);
4755 * Queueing now stored outside of the element due to closure issues
4757 getQueue = function(id){
4763 setQueue = function(id, value){
4767 //Notifies Element that fx methods are available
4768 Ext.enableFx = TRUE;
4772 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
4773 * to the {@link Ext.Element} interface when included, so all effects calls should be performed via {@link Ext.Element}.
4774 * Conversely, since the effects are not actually defined in {@link Ext.Element}, Ext.Fx <b>must</b> be
4775 * {@link Ext#enableFx included} in order for the Element effects to work.</p><br/>
4777 * <p><b><u>Method Chaining</u></b></p>
4778 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
4779 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
4780 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
4781 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
4782 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
4783 * expected results and should be done with care. Also see <tt>{@link #callback}</tt>.</p><br/>
4785 * <p><b><u>Anchor Options for Motion Effects</u></b></p>
4786 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
4787 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
4790 ----- -----------------------------
4791 tl The top left corner
4792 t The center of the top edge
4793 tr The top right corner
4794 l The center of the left edge
4795 r The center of the right edge
4796 bl The bottom left corner
4797 b The center of the bottom edge
4798 br The bottom right corner
4800 * <b>Note</b>: some Fx methods accept specific custom config parameters. The options shown in the Config Options
4801 * section below are common options that can be passed to any Fx method unless otherwise noted.</b>
4803 * @cfg {Function} callback A function called when the effect is finished. Note that effects are queued internally by the
4804 * Fx class, so a callback is not required to specify another effect -- effects can simply be chained together
4805 * and called in sequence (see note for <b><u>Method Chaining</u></b> above), for example:<pre><code>
4806 * el.slideIn().highlight();
4808 * The callback is intended for any additional code that should run once a particular effect has completed. The Element
4809 * being operated upon is passed as the first parameter.
4811 * @cfg {Object} scope The scope (<code>this</code> reference) in which the <tt>{@link #callback}</tt> function is executed. Defaults to the browser window.
4813 * @cfg {String} easing A valid Ext.lib.Easing value for the effect:</p><div class="mdetail-params"><ul>
4814 * <li><b><tt>backBoth</tt></b></li>
4815 * <li><b><tt>backIn</tt></b></li>
4816 * <li><b><tt>backOut</tt></b></li>
4817 * <li><b><tt>bounceBoth</tt></b></li>
4818 * <li><b><tt>bounceIn</tt></b></li>
4819 * <li><b><tt>bounceOut</tt></b></li>
4820 * <li><b><tt>easeBoth</tt></b></li>
4821 * <li><b><tt>easeBothStrong</tt></b></li>
4822 * <li><b><tt>easeIn</tt></b></li>
4823 * <li><b><tt>easeInStrong</tt></b></li>
4824 * <li><b><tt>easeNone</tt></b></li>
4825 * <li><b><tt>easeOut</tt></b></li>
4826 * <li><b><tt>easeOutStrong</tt></b></li>
4827 * <li><b><tt>elasticBoth</tt></b></li>
4828 * <li><b><tt>elasticIn</tt></b></li>
4829 * <li><b><tt>elasticOut</tt></b></li>
4832 * @cfg {String} afterCls A css class to apply after the effect
4833 * @cfg {Number} duration The length of time (in seconds) that the effect should last
4835 * @cfg {Number} endOpacity Only applicable for {@link #fadeIn} or {@link #fadeOut}, a number between
4836 * <tt>0</tt> and <tt>1</tt> inclusive to configure the ending opacity value.
4838 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
4839 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
4840 * effects that end with the element being visually hidden, ignored otherwise)
4841 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. <tt>"width:100px"</tt>, or an object
4842 * in the form <tt>{width:"100px"}</tt>, or a function which returns such a specification that will be applied to the
4843 * Element after the effect finishes.
4844 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
4845 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
4846 * @cfg {Boolean} stopFx Whether preceding effects should be stopped and removed before running current effect (only applies to non blocking effects)
4850 // private - calls the function taking arguments from the argHash based on the key. Returns the return value of the function.
4851 // this is useful for replacing switch statements (for example).
4852 switchStatements : function(key, fn, argHash){
4853 return fn.apply(this, argHash[key]);
4857 * Slides the element into view. An anchor point can be optionally passed to set the point of
4858 * origin for the slide effect. This function automatically handles wrapping the element with
4859 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
4862 // default: slide the element in from the top
4865 // custom: slide the element in from the right with a 2-second duration
4866 el.slideIn('r', { duration: 2 });
4868 // common config options shown with default values
4874 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
4875 * @param {Object} options (optional) Object literal with any of the Fx config options
4876 * @return {Ext.Element} The Element
4878 slideIn : function(anchor, o){
4894 anchor = anchor || "t";
4896 me.queueFx(o, function(){
4897 xy = fly(dom).getXY();
4898 // fix display to visibility
4899 fly(dom).fixDisplay();
4901 // restore values after effect
4902 r = fly(dom).getFxRestore();
4903 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
4904 b.right = b.x + b.width;
4905 b.bottom = b.y + b.height;
4907 // fixed size for slide
4908 fly(dom).setWidth(b.width).setHeight(b.height);
4911 wrap = fly(dom).fxWrap(r.pos, o, HIDDEN);
4913 st.visibility = VISIBLE;
4914 st.position = ABSOLUTE;
4916 // clear out temp styles after slide and unwrap
4918 fly(dom).fxUnwrap(wrap, r.pos, o);
4920 st.height = r.height;
4921 fly(dom).afterFx(o);
4924 // time to calculate the positions
4925 pt = {to: [b.x, b.y]};
4927 bh = {to: b.height};
4929 function argCalc(wrap, style, ww, wh, sXY, sXYval, s1, s2, w, h, p){
4931 fly(wrap).setWidth(ww).setHeight(wh);
4933 fly(wrap)[sXY](sXYval);
4935 style[s1] = style[s2] = "0";
4948 args = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
4949 t : [wrap, st, b.width, 0, NULL, NULL, LEFT, BOTTOM, NULL, bh, NULL],
4950 l : [wrap, st, 0, b.height, NULL, NULL, RIGHT, TOP, bw, NULL, NULL],
4951 r : [wrap, st, b.width, b.height, SETX, b.right, LEFT, TOP, NULL, NULL, pt],
4952 b : [wrap, st, b.width, b.height, SETY, b.bottom, LEFT, TOP, NULL, bh, pt],
4953 tl : [wrap, st, 0, 0, NULL, NULL, RIGHT, BOTTOM, bw, bh, pt],
4954 bl : [wrap, st, 0, 0, SETY, b.y + b.height, RIGHT, TOP, bw, bh, pt],
4955 br : [wrap, st, 0, 0, SETXY, [b.right, b.bottom], LEFT, TOP, bw, bh, pt],
4956 tr : [wrap, st, 0, 0, SETX, b.x + b.width, LEFT, BOTTOM, bw, bh, pt]
4959 st.visibility = VISIBLE;
4962 arguments.callee.anim = fly(wrap).fxanim(args,
4973 * Slides the element out of view. An anchor point can be optionally passed to set the end point
4974 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
4975 * 'hidden') but block elements will still take up space in the document. The element must be removed
4976 * from the DOM using the 'remove' config option if desired. This function automatically handles
4977 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
4980 // default: slide the element out to the top
4983 // custom: slide the element out to the right with a 2-second duration
4984 el.slideOut('r', { duration: 2 });
4986 // common config options shown with default values
4994 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
4995 * @param {Object} options (optional) Object literal with any of the Fx config options
4996 * @return {Ext.Element} The Element
4998 slideOut : function(anchor, o){
5010 anchor = anchor || "t";
5012 me.queueFx(o, function(){
5014 // restore values after effect
5015 r = fly(dom).getFxRestore();
5016 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
5017 b.right = b.x + b.width;
5018 b.bottom = b.y + b.height;
5020 // fixed size for slide
5021 fly(dom).setWidth(b.width).setHeight(b.height);
5024 wrap = fly(dom).fxWrap(r.pos, o, VISIBLE);
5026 st.visibility = VISIBLE;
5027 st.position = ABSOLUTE;
5028 fly(wrap).setWidth(b.width).setHeight(b.height);
5031 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();
5032 fly(dom).fxUnwrap(wrap, r.pos, o);
5034 st.height = r.height;
5035 fly(dom).afterFx(o);
5038 function argCalc(style, s1, s2, p1, v1, p2, v2, p3, v3){
5041 style[s1] = style[s2] = "0";
5053 a = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
5054 t : [st, LEFT, BOTTOM, HEIGHT, zero],
5055 l : [st, RIGHT, TOP, WIDTH, zero],
5056 r : [st, LEFT, TOP, WIDTH, zero, POINTS, {to : [b.right, b.y]}],
5057 b : [st, LEFT, TOP, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
5058 tl : [st, RIGHT, BOTTOM, WIDTH, zero, HEIGHT, zero],
5059 bl : [st, RIGHT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
5060 br : [st, LEFT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x + b.width, b.bottom]}],
5061 tr : [st, LEFT, BOTTOM, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.right, b.y]}]
5064 arguments.callee.anim = fly(wrap).fxanim(a,
5075 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
5076 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
5077 * The element must be removed from the DOM using the 'remove' config option if desired.
5083 // common config options shown with default values
5091 * @param {Object} options (optional) Object literal with any of the Fx config options
5092 * @return {Ext.Element} The Element
5103 me.queueFx(o, function(){
5104 width = fly(dom).getWidth();
5105 height = fly(dom).getHeight();
5106 fly(dom).clearOpacity();
5109 // restore values after effect
5110 r = fly(dom).getFxRestore();
5113 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();
5114 fly(dom).clearOpacity();
5115 fly(dom).setPositioning(r.pos);
5117 st.height = r.height;
5119 fly(dom).afterFx(o);
5122 arguments.callee.anim = fly(dom).fxanim({
5123 width : {to : fly(dom).adjustWidth(width * 2)},
5124 height : {to : fly(dom).adjustHeight(height * 2)},
5125 points : {by : [-width * .5, -height * .5]},
5127 fontSize: {to : 200, unit: "%"}
5139 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
5140 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
5141 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
5147 // all config options shown with default values
5155 * @param {Object} options (optional) Object literal with any of the Fx config options
5156 * @return {Ext.Element} The Element
5158 switchOff : function(o){
5165 me.queueFx(o, function(){
5166 fly(dom).clearOpacity();
5169 // restore values after effect
5170 r = fly(dom).getFxRestore();
5173 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();
5174 fly(dom).clearOpacity();
5175 fly(dom).setPositioning(r.pos);
5177 st.height = r.height;
5178 fly(dom).afterFx(o);
5181 fly(dom).fxanim({opacity : {to : 0.3}},
5187 fly(dom).clearOpacity();
5191 points : {by : [0, fly(dom).getHeight() * .5]}
5205 * Highlights the Element by setting a color (applies to the background-color by default, but can be
5206 * changed using the "attr" config option) and then fading back to the original color. If no original
5207 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
5210 // default: highlight background to yellow
5213 // custom: highlight foreground text to blue for 2 seconds
5214 el.highlight("0000ff", { attr: 'color', duration: 2 });
5216 // common config options shown with default values
5217 el.highlight("ffff9c", {
5218 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
5219 endColor: (current color) or "ffffff",
5224 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
5225 * @param {Object} options (optional) Object literal with any of the Fx config options
5226 * @return {Ext.Element} The Element
5228 highlight : function(color, o){
5232 attr = o.attr || "backgroundColor",
5236 me.queueFx(o, function(){
5237 fly(dom).clearOpacity();
5241 dom.style[attr] = restore;
5242 fly(dom).afterFx(o);
5244 restore = dom.style[attr];
5245 a[attr] = {from: color || "ffff9c", to: o.endColor || fly(dom).getColor(attr) || "ffffff"};
5246 arguments.callee.anim = fly(dom).fxanim(a,
5257 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
5260 // default: a single light blue ripple
5263 // custom: 3 red ripples lasting 3 seconds total
5264 el.frame("ff0000", 3, { duration: 3 });
5266 // common config options shown with default values
5267 el.frame("C3DAF9", 1, {
5268 duration: 1 //duration of each individual ripple.
5269 // Note: Easing is not configurable and will be ignored if included
5272 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
5273 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
5274 * @param {Object} options (optional) Object literal with any of the Fx config options
5275 * @return {Ext.Element} The Element
5277 frame : function(color, count, o){
5284 me.queueFx(o, function(){
5285 color = color || '#C3DAF9';
5286 if(color.length == 6){
5287 color = '#' + color;
5292 var xy = fly(dom).getXY(),
5293 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight},
5295 proxy = fly(document.body || document.documentElement).createChild({
5297 position : ABSOLUTE,
5298 'z-index': 35000, // yee haw
5299 border : '0px solid ' + color
5302 return proxy.queueFx({}, animFn);
5306 arguments.callee.anim = {
5315 var scale = Ext.isBorderBox ? 2 : 1;
5316 active = proxy.anim({
5317 top : {from : b.y, to : b.y - 20},
5318 left : {from : b.x, to : b.x - 20},
5319 borderWidth : {from : 0, to : 10},
5320 opacity : {from : 1, to : 0},
5321 height : {from : b.height, to : b.height + 20 * scale},
5322 width : {from : b.width, to : b.width + 20 * scale}
5324 duration: o.duration || 1,
5325 callback: function() {
5327 --count > 0 ? queue() : fly(dom).afterFx(o);
5330 arguments.callee.anim = {
5343 * Creates a pause before any subsequent queued effects begin. If there are
5344 * no effects queued after the pause it will have no effect.
5349 * @param {Number} seconds The length of time to pause (in seconds)
5350 * @return {Ext.Element} The Element
5352 pause : function(seconds){
5356 this.queueFx({}, function(){
5357 t = setTimeout(function(){
5358 fly(dom).afterFx({});
5360 arguments.callee.anim = {
5364 fly(dom).afterFx({});
5372 * Fade an element in (from transparent to opaque). The ending opacity can be specified
5373 * using the <tt>{@link #endOpacity}</tt> config option.
5376 // default: fade in from opacity 0 to 100%
5379 // custom: fade in from opacity 0 to 75% over 2 seconds
5380 el.fadeIn({ endOpacity: .75, duration: 2});
5382 // common config options shown with default values
5384 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
5389 * @param {Object} options (optional) Object literal with any of the Fx config options
5390 * @return {Ext.Element} The Element
5392 fadeIn : function(o){
5396 to = o.endOpacity || 1;
5398 me.queueFx(o, function(){
5399 fly(dom).setOpacity(0);
5400 fly(dom).fixDisplay();
5401 dom.style.visibility = VISIBLE;
5402 arguments.callee.anim = fly(dom).fxanim({opacity:{to:to}},
5403 o, NULL, .5, EASEOUT, function(){
5405 fly(dom).clearOpacity();
5407 fly(dom).afterFx(o);
5414 * Fade an element out (from opaque to transparent). The ending opacity can be specified
5415 * using the <tt>{@link #endOpacity}</tt> config option. Note that IE may require
5416 * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
5419 // default: fade out from the element's current opacity to 0
5422 // custom: fade out from the element's current opacity to 25% over 2 seconds
5423 el.fadeOut({ endOpacity: .25, duration: 2});
5425 // common config options shown with default values
5427 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
5434 * @param {Object} options (optional) Object literal with any of the Fx config options
5435 * @return {Ext.Element} The Element
5437 fadeOut : function(o){
5442 to = o.endOpacity || 0;
5444 me.queueFx(o, function(){
5445 arguments.callee.anim = fly(dom).fxanim({
5446 opacity : {to : to}},
5453 Ext.Element.data(dom, 'visibilityMode') == Ext.Element.DISPLAY || o.useDisplay ?
5454 style.display = "none" :
5455 style.visibility = HIDDEN;
5457 fly(dom).clearOpacity();
5459 fly(dom).afterFx(o);
5466 * Animates the transition of an element's dimensions from a starting height/width
5467 * to an ending height/width. This method is a convenience implementation of {@link shift}.
5470 // change height and width to 100x100 pixels
5473 // common config options shown with default values. The height and width will default to
5474 // the element's existing values if passed as null.
5476 [element's width],
5477 [element's height], {
5483 * @param {Number} width The new width (pass undefined to keep the original width)
5484 * @param {Number} height The new height (pass undefined to keep the original height)
5485 * @param {Object} options (optional) Object literal with any of the Fx config options
5486 * @return {Ext.Element} The Element
5488 scale : function(w, h, o){
5489 this.shift(Ext.apply({}, o, {
5497 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
5498 * Any of these properties not specified in the config object will not be changed. This effect
5499 * requires that at least one new dimension, position or opacity setting must be passed in on
5500 * the config object in order for the function to have any effect.
5503 // slide the element horizontally to x position 200 while changing the height and opacity
5504 el.shift({ x: 200, height: 50, opacity: .8 });
5506 // common config options shown with default values.
5508 width: [element's width],
5509 height: [element's height],
5510 x: [element's x position],
5511 y: [element's y position],
5512 opacity: [element's opacity],
5517 * @param {Object} options Object literal with any of the Fx config options
5518 * @return {Ext.Element} The Element
5520 shift : function(o){
5525 this.queueFx(o, function(){
5526 for (var prop in o) {
5527 if (o[prop] != UNDEFINED) {
5528 a[prop] = {to : o[prop]};
5532 a.width ? a.width.to = fly(dom).adjustWidth(o.width) : a;
5533 a.height ? a.height.to = fly(dom).adjustWidth(o.height) : a;
5535 if (a.x || a.y || a.xy) {
5537 {to : [ a.x ? a.x.to : fly(dom).getX(),
5538 a.y ? a.y.to : fly(dom).getY()]};
5541 arguments.callee.anim = fly(dom).fxanim(a,
5547 fly(dom).afterFx(o);
5554 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
5555 * ending point of the effect.
5558 // default: slide the element downward while fading out
5561 // custom: slide the element out to the right with a 2-second duration
5562 el.ghost('r', { duration: 2 });
5564 // common config options shown with default values
5572 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
5573 * @param {Object} options (optional) Object literal with any of the Fx config options
5574 * @return {Ext.Element} The Element
5576 ghost : function(anchor, o){
5581 a = {opacity: {to: 0}, points: {}},
5587 anchor = anchor || "b";
5589 me.queueFx(o, function(){
5590 // restore values after effect
5591 r = fly(dom).getFxRestore();
5592 w = fly(dom).getWidth();
5593 h = fly(dom).getHeight();
5596 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();
5597 fly(dom).clearOpacity();
5598 fly(dom).setPositioning(r.pos);
5600 st.height = r.height;
5601 fly(dom).afterFx(o);
5604 pt.by = fly(dom).switchStatements(anchor.toLowerCase(), function(v1,v2){ return [v1, v2];}, {
5615 arguments.callee.anim = fly(dom).fxanim(a,
5625 * Ensures that all effects queued after syncFx is called on the element are
5626 * run concurrently. This is the opposite of {@link #sequenceFx}.
5627 * @return {Ext.Element} The Element
5629 syncFx : function(){
5631 me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
5640 * Ensures that all effects queued after sequenceFx is called on the element are
5641 * run in sequence. This is the opposite of {@link #syncFx}.
5642 * @return {Ext.Element} The Element
5644 sequenceFx : function(){
5646 me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
5655 nextFx : function(){
5656 var ef = getQueue(this.dom.id)[0];
5663 * Returns true if the element has any effects actively running or queued, else returns false.
5664 * @return {Boolean} True if element has active effects, else false
5666 hasActiveFx : function(){
5667 return getQueue(this.dom.id)[0];
5671 * Stops any running effects and clears the element's internal effects queue if it contains
5672 * any additional effects that haven't started yet.
5673 * @return {Ext.Element} The Element
5675 stopFx : function(finish){
5678 if(me.hasActiveFx()){
5679 var cur = getQueue(id)[0];
5680 if(cur && cur.anim){
5681 if(cur.anim.isAnimated){
5682 setQueue(id, [cur]); //clear
5683 cur.anim.stop(finish !== undefined ? finish : TRUE);
5693 beforeFx : function(o){
5694 if(this.hasActiveFx() && !o.concurrent){
5705 * Returns true if the element is currently blocking so that no other effect can be queued
5706 * until this effect is finished, else returns false if blocking is not set. This is commonly
5707 * used to ensure that an effect initiated by a user action runs to completion prior to the
5708 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
5709 * @return {Boolean} True if blocking, else false
5711 hasFxBlock : function(){
5712 var q = getQueue(this.dom.id);
5713 return q && q[0] && q[0].block;
5717 queueFx : function(o, fn){
5718 var me = fly(this.dom);
5719 if(!me.hasFxBlock()){
5720 Ext.applyIf(o, me.fxDefaults);
5722 var run = me.beforeFx(o);
5724 getQueue(me.dom.id).push(fn);
5736 fxWrap : function(pos, o, vis){
5740 if(!o.wrap || !(wrap = Ext.getDom(o.wrap))){
5742 wrapXY = fly(dom).getXY();
5744 var div = document.createElement("div");
5745 div.style.visibility = vis;
5746 wrap = dom.parentNode.insertBefore(div, dom);
5747 fly(wrap).setPositioning(pos);
5748 if(fly(wrap).isStyle(POSITION, "static")){
5749 fly(wrap).position("relative");
5751 fly(dom).clearPositioning('auto');
5753 wrap.appendChild(dom);
5755 fly(wrap).setXY(wrapXY);
5762 fxUnwrap : function(wrap, pos, o){
5764 fly(dom).clearPositioning();
5765 fly(dom).setPositioning(pos);
5767 var pn = fly(wrap).dom.parentNode;
5768 pn.insertBefore(dom, wrap);
5774 getFxRestore : function(){
5775 var st = this.dom.style;
5776 return {pos: this.getPositioning(), width: st.width, height : st.height};
5780 afterFx : function(o){
5784 fly(dom).setStyle(o.afterStyle);
5787 fly(dom).addClass(o.afterCls);
5789 if(o.remove == TRUE){
5793 o.callback.call(o.scope, fly(dom));
5796 getQueue(id).shift();
5802 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
5803 animType = animType || 'run';
5805 var anim = Ext.lib.Anim[animType](
5808 (opt.duration || defaultDur) || .35,
5809 (opt.easing || defaultEase) || EASEOUT,
5819 Ext.Fx.resize = Ext.Fx.scale;
5821 //When included, Ext.Fx is automatically applied to Element so that all basic
5822 //effects are available directly via the Element API
5823 Ext.Element.addMethods(Ext.Fx);
5826 * @class Ext.CompositeElementLite
5827 * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
5828 * members, or to perform collective actions upon the whole set.</p>
5829 * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
5830 * {@link Ext.Fx}. The methods from these classes will be performed on all the elements in this collection.</p>
5831 * Example:<pre><code>
5832 var els = Ext.select("#some-el div.some-class");
5833 // or select directly from an existing element
5834 var el = Ext.get('some-el');
5835 el.select('div.some-class');
5837 els.setWidth(100); // all elements become 100 width
5838 els.hide(true); // all elements fade out and hide
5840 els.setWidth(100).hide(true);
5843 Ext.CompositeElementLite = function(els, root){
5845 * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
5846 * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
5847 * to augment the capabilities of the CompositeElementLite class may use it when adding
5848 * methods to the class.</p>
5849 * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
5850 * following siblings of selected elements, the code would be</p><code><pre>
5851 Ext.override(Ext.CompositeElementLite, {
5852 nextAll: function() {
5853 var els = this.elements, i, l = els.length, n, r = [], ri = -1;
5855 // Loop through all elements in this Composite, accumulating
5856 // an Array of all siblings.
5857 for (i = 0; i < l; i++) {
5858 for (n = els[i].nextSibling; n; n = n.nextSibling) {
5863 // Add all found siblings to this Composite
5868 * @property elements
5871 this.add(els, root);
5872 this.el = new Ext.Element.Flyweight();
5875 Ext.CompositeElementLite.prototype = {
5879 getElement : function(el){
5880 // Set the shared flyweight dom property to the current element
5888 transformElement : function(el){
5889 return Ext.getDom(el);
5893 * Returns the number of elements in this Composite.
5896 getCount : function(){
5897 return this.elements.length;
5900 * Adds elements to this Composite object.
5901 * @param {Mixed} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
5902 * @return {CompositeElement} This Composite object.
5904 add : function(els, root){
5906 elements = me.elements;
5910 if(typeof els == "string"){
5911 els = Ext.Element.selectorFunction(els, root);
5912 }else if(els.isComposite){
5914 }else if(!Ext.isIterable(els)){
5918 for(var i = 0, len = els.length; i < len; ++i){
5919 elements.push(me.transformElement(els[i]));
5924 invoke : function(fn, args){
5931 for(i = 0; i < len; i++) {
5934 Ext.Element.prototype[fn].apply(me.getElement(e), args);
5940 * Returns a flyweight Element of the dom element object at the specified index
5941 * @param {Number} index
5942 * @return {Ext.Element}
5944 item : function(index){
5946 el = me.elements[index],
5950 out = me.getElement(el);
5955 // fixes scope with flyweight
5956 addListener : function(eventName, handler, scope, opt){
5957 var els = this.elements,
5961 for(i = 0; i<len; i++) {
5964 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
5970 * <p>Calls the passed function for each element in this composite.</p>
5971 * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
5972 * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
5973 * <b>This is the flyweight (shared) Ext.Element instance, so if you require a
5974 * a reference to the dom node, use el.dom.</b></div></li>
5975 * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
5976 * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
5978 * @param {Object} scope (optional) The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
5979 * @return {CompositeElement} this
5981 each : function(fn, scope){
5987 for(i = 0; i<len; i++) {
5990 e = this.getElement(e);
5991 if(fn.call(scope || e, e, me, i) === false){
6000 * Clears this Composite and adds the elements passed.
6001 * @param {Mixed} els Either an array of DOM elements, or another Composite from which to fill this Composite.
6002 * @return {CompositeElement} this
6004 fill : function(els){
6012 * Filters this composite to only elements that match the passed selector.
6013 * @param {String/Function} selector A string CSS selector or a comparison function.
6014 * The comparison function will be called with the following arguments:<ul>
6015 * <li><code>el</code> : Ext.Element<div class="sub-desc">The current DOM element.</div></li>
6016 * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
6018 * @return {CompositeElement} this
6020 filter : function(selector){
6023 fn = Ext.isFunction(selector) ? selector
6025 return el.is(selector);
6028 me.each(function(el, self, i) {
6029 if (fn(el, i) !== false) {
6030 els[els.length] = me.transformElement(el);
6039 * Find the index of the passed element within the composite collection.
6040 * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
6041 * @return Number The index of the passed Ext.Element in the composite collection, or -1 if not found.
6043 indexOf : function(el){
6044 return this.elements.indexOf(this.transformElement(el));
6048 * Replaces the specified element with the passed element.
6049 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
6051 * @param {Mixed} replacement The id of an element or the Element itself.
6052 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
6053 * @return {CompositeElement} this
6055 replaceElement : function(el, replacement, domReplace){
6056 var index = !isNaN(el) ? el : this.indexOf(el),
6059 replacement = Ext.getDom(replacement);
6061 d = this.elements[index];
6062 d.parentNode.insertBefore(replacement, d);
6065 this.elements.splice(index, 1, replacement);
6071 * Removes all elements.
6078 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
6082 * Copies all of the functions from Ext.Element's prototype onto CompositeElementLite's prototype.
6083 * This is called twice - once immediately below, and once again after additional Ext.Element
6084 * are added in Ext JS
6086 Ext.CompositeElementLite.importElementMethods = function() {
6088 ElProto = Ext.Element.prototype,
6089 CelProto = Ext.CompositeElementLite.prototype;
6091 for (fnName in ElProto) {
6092 if (typeof ElProto[fnName] == 'function'){
6094 CelProto[fnName] = CelProto[fnName] || function() {
6095 return this.invoke(fnName, arguments);
6097 }).call(CelProto, fnName);
6103 Ext.CompositeElementLite.importElementMethods();
6106 Ext.Element.selectorFunction = Ext.DomQuery.select;
6110 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
6111 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
6112 * {@link Ext.CompositeElementLite CompositeElementLite} object.
6113 * @param {String/Array} selector The CSS selector or an array of elements
6114 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
6115 * @return {CompositeElementLite/CompositeElement}
6116 * @member Ext.Element
6119 Ext.Element.select = function(selector, root){
6121 if(typeof selector == "string"){
6122 els = Ext.Element.selectorFunction(selector, root);
6123 }else if(selector.length !== undefined){
6126 throw "Invalid selector";
6128 return new Ext.CompositeElementLite(els);
6131 * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
6132 * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
6133 * {@link Ext.CompositeElementLite CompositeElementLite} object.
6134 * @param {String/Array} selector The CSS selector or an array of elements
6135 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
6136 * @return {CompositeElementLite/CompositeElement}
6140 Ext.select = Ext.Element.select;
6142 var BEFOREREQUEST = "beforerequest",
6143 REQUESTCOMPLETE = "requestcomplete",
6144 REQUESTEXCEPTION = "requestexception",
6145 UNDEFINED = undefined,
6152 * @class Ext.data.Connection
6153 * @extends Ext.util.Observable
6154 * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made
6155 * either to a configured URL, or to a URL specified at request time.</p>
6156 * <p>Requests made by this class are asynchronous, and will return immediately. No data from
6157 * the server will be available to the statement immediately following the {@link #request} call.
6158 * To process returned data, use a
6159 * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>
6160 * in the request options object,
6161 * or an {@link #requestcomplete event listener}.</p>
6162 * <p><h3>File Uploads</h3><a href="#request-option-isUpload" ext:member="request-option-isUpload" ext:cls="Ext.data.Connection">File uploads</a> are not performed using normal "Ajax" techniques, that
6163 * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
6164 * manner with the DOM <tt><form></tt> element temporarily modified to have its
6165 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
6166 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
6167 * but removed after the return data has been gathered.</p>
6168 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
6169 * server is using JSON to send the return object, then the
6170 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
6171 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
6172 * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
6173 * "<" as "&lt;", "&" as "&amp;" etc.</p>
6174 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
6175 * is created containing a <tt>responseText</tt> property in order to conform to the
6176 * requirements of event handlers and callbacks.</p>
6177 * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
6178 * and some server technologies (notably JEE) may require some custom processing in order to
6179 * retrieve parameter names and parameter values from the packet content.</p>
6180 * <p>Also note that it's not possible to check the response code of the hidden iframe, so the success handler will ALWAYS fire.</p>
6182 * @param {Object} config a configuration object.
6184 Ext.data.Connection = function(config){
6185 Ext.apply(this, config);
6188 * @event beforerequest
6189 * Fires before a network request is made to retrieve a data object.
6190 * @param {Connection} conn This Connection object.
6191 * @param {Object} options The options config object passed to the {@link #request} method.
6195 * @event requestcomplete
6196 * Fires if the request was successfully completed.
6197 * @param {Connection} conn This Connection object.
6198 * @param {Object} response The XHR object containing the response data.
6199 * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
6201 * @param {Object} options The options config object passed to the {@link #request} method.
6205 * @event requestexception
6206 * Fires if an error HTTP status was returned from the server.
6207 * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
6208 * for details of HTTP status codes.
6209 * @param {Connection} conn This Connection object.
6210 * @param {Object} response The XHR object containing the response data.
6211 * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
6213 * @param {Object} options The options config object passed to the {@link #request} method.
6217 Ext.data.Connection.superclass.constructor.call(this);
6220 Ext.extend(Ext.data.Connection, Ext.util.Observable, {
6222 * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>
6223 * <p>The <code>url</code> config may be a function which <i>returns</i> the URL to use for the Ajax request. The scope
6224 * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>
6227 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
6228 * extra parameters to each request made by this object. (defaults to undefined)
6231 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
6232 * to each request made by this object. (defaults to undefined)
6235 * @cfg {String} method (Optional) The default HTTP method to be used for requests.
6236 * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;
6237 * otherwise, GET will be used.)
6240 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
6244 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
6250 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
6253 disableCaching: true,
6256 * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
6257 * through a cache buster. Defaults to '_dc'
6260 disableCachingParam: '_dc',
6263 * <p>Sends an HTTP request to a remote server.</p>
6264 * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
6265 * return before the response has been received. Process any returned data
6266 * in a callback function.</p>
6269 url: 'ajax_demo/sample.json',
6270 success: function(response, opts) {
6271 var obj = Ext.decode(response.responseText);
6274 failure: function(response, opts) {
6275 console.log('server-side failure with status code ' + response.status);
6279 * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
6280 * @param {Object} options An object which may contain the following properties:<ul>
6281 * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
6282 * which to send the request, or a function to call which returns a URL string. The scope of the
6283 * function is specified by the <tt>scope</tt> option. Defaults to the configured
6284 * <tt>{@link #url}</tt>.</div></li>
6285 * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
6286 * An object containing properties which are used as parameters to the
6287 * request, a url encoded string or a function to call to get either. The scope of the function
6288 * is specified by the <tt>scope</tt> option.</div></li>
6289 * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
6290 * for the request. Defaults to the configured method, or if no method was configured,
6291 * "GET" if no parameters are being sent, and "POST" if parameters are being sent. Note that
6292 * the method name is case-sensitive and should be all caps.</div></li>
6293 * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
6294 * function to be called upon receipt of the HTTP response. The callback is
6295 * called regardless of success or failure and is passed the following
6297 * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
6298 * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
6299 * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.
6300 * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about
6301 * accessing elements of the response.</div></li>
6303 * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
6304 * to be called upon success of the request. The callback is passed the following
6306 * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
6307 * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
6309 * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
6310 * to be called upon failure of the request. The callback is passed the
6311 * following parameters:<ul>
6312 * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
6313 * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
6315 * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
6316 * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
6317 * specified as functions from which to draw values, then this also serves as the scope for those function calls.
6318 * Defaults to the browser window.</div></li>
6319 * <li><b>timeout</b> : Number (Optional)<div class="sub-desc">The timeout in milliseconds to be used for this request. Defaults to 30 seconds.</div></li>
6320 * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt><form></tt>
6321 * Element or the id of the <tt><form></tt> to pull parameters from.</div></li>
6322 * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used
6323 * with the <tt>form</tt> option</b>.
6324 * <p>True if the form object is a file upload (will be set automatically if the form was
6325 * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
6326 * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
6327 * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
6328 * DOM <tt><form></tt> element temporarily modified to have its
6329 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
6330 * to a dynamically generated, hidden <tt><iframe></tt> which is inserted into the document
6331 * but removed after the return data has been gathered.</p>
6332 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
6333 * server is using JSON to send the return object, then the
6334 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
6335 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
6336 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
6337 * is created containing a <tt>responseText</tt> property in order to conform to the
6338 * requirements of event handlers and callbacks.</p>
6339 * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
6340 * and some server technologies (notably JEE) may require some custom processing in order to
6341 * retrieve parameter names and parameter values from the packet content.</p>
6343 * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
6344 * headers to set for the request.</div></li>
6345 * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
6346 * to use for the post. Note: This will be used instead of params for the post
6347 * data. Any params will be appended to the URL.</div></li>
6348 * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
6349 * data to use as the post. Note: This will be used instead of params for the post
6350 * data. Any params will be appended to the URL.</div></li>
6351 * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
6352 * to add a unique cache-buster param to GET requests.</div></li>
6354 * <p>The options object may also contain any other property which might be needed to perform
6355 * postprocessing in a callback because it is passed to callback functions.</p>
6356 * @return {Number} transactionId The id of the server transaction. This may be used
6357 * to cancel the request.
6359 request : function(o){
6361 if(me.fireEvent(BEFOREREQUEST, me, o)){
6363 if(!Ext.isEmpty(o.indicatorText)){
6364 me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";
6366 if(me.indicatorText) {
6367 Ext.getDom(o.el).innerHTML = me.indicatorText;
6369 o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {
6370 Ext.getDom(o.el).innerHTML = response.responseText;
6375 url = o.url || me.url,
6377 cb = {success: me.handleResponse,
6378 failure: me.handleFailure,
6380 argument: {options: o},
6381 timeout : Ext.num(o.timeout, me.timeout)
6387 if (Ext.isFunction(p)) {
6388 p = p.call(o.scope||WINDOW, o);
6391 p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);
6393 if (Ext.isFunction(url)) {
6394 url = url.call(o.scope || WINDOW, o);
6397 if((form = Ext.getDom(o.form))){
6398 url = url || form.action;
6399 if(o.isUpload || (/multipart\/form-data/i.test(form.getAttribute("enctype")))) {
6400 return me.doFormUpload.call(me, o, p, url);
6402 serForm = Ext.lib.Ajax.serializeForm(form);
6403 p = p ? (p + '&' + serForm) : serForm;
6406 method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);
6408 if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
6409 var dcp = o.disableCachingParam || me.disableCachingParam;
6410 url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));
6413 o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});
6415 if(o.autoAbort === true || me.autoAbort) {
6419 if((method == GET || o.xmlData || o.jsonData) && p){
6420 url = Ext.urlAppend(url, p);
6423 return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
6425 return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;
6430 * Determine whether this object has a request outstanding.
6431 * @param {Number} transactionId (Optional) defaults to the last transaction
6432 * @return {Boolean} True if there is an outstanding request.
6434 isLoading : function(transId){
6435 return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;
6439 * Aborts any outstanding request.
6440 * @param {Number} transactionId (Optional) defaults to the last transaction
6442 abort : function(transId){
6443 if(transId || this.isLoading()){
6444 Ext.lib.Ajax.abort(transId || this.transId);
6449 handleResponse : function(response){
6450 this.transId = false;
6451 var options = response.argument.options;
6452 response.argument = options ? options.argument : null;
6453 this.fireEvent(REQUESTCOMPLETE, this, response, options);
6454 if(options.success){
6455 options.success.call(options.scope, response, options);
6457 if(options.callback){
6458 options.callback.call(options.scope, options, true, response);
6463 handleFailure : function(response, e){
6464 this.transId = false;
6465 var options = response.argument.options;
6466 response.argument = options ? options.argument : null;
6467 this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
6468 if(options.failure){
6469 options.failure.call(options.scope, response, options);
6471 if(options.callback){
6472 options.callback.call(options.scope, options, false, response);
6477 doFormUpload : function(o, ps, url){
6480 frame = doc.createElement('iframe'),
6481 form = Ext.getDom(o.form),
6484 encoding = 'multipart/form-data',
6486 target: form.target,
6487 method: form.method,
6488 encoding: form.encoding,
6489 enctype: form.enctype,
6494 * Originally this behaviour was modified for Opera 10 to apply the secure URL after
6495 * the frame had been added to the document. It seems this has since been corrected in
6496 * Opera so the behaviour has been reverted, the URL will be set before being added.
6498 Ext.fly(frame).set({
6502 src: Ext.SSL_SECURE_URL
6505 doc.body.appendChild(frame);
6507 // This is required so that IE doesn't pop the response up in a new window.
6509 document.frames[id].name = id;
6518 action: url || buf.action
6521 // add dynamic params
6522 Ext.iterate(Ext.urlDecode(ps, false), function(k, v){
6523 hd = doc.createElement('input');
6529 form.appendChild(hd);
6535 // bogus response object
6536 r = {responseText : '',
6538 argument : o.argument},
6543 doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
6546 if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea
6547 r.responseText = firstChild.value;
6549 r.responseText = doc.body.innerHTML;
6552 //in IE the document may still have a body even if returns XML.
6553 r.responseXML = doc.XMLDocument || doc;
6558 Ext.EventManager.removeListener(frame, LOAD, cb, me);
6560 me.fireEvent(REQUESTCOMPLETE, me, r, o);
6562 function runCallback(fn, scope, args){
6563 if(Ext.isFunction(fn)){
6564 fn.apply(scope, args);
6568 runCallback(o.success, o.scope, [r, o]);
6569 runCallback(o.callback, o.scope, [o, true, r]);
6571 if(!me.debugUploads){
6572 setTimeout(function(){Ext.removeNode(frame);}, 100);
6576 Ext.EventManager.on(frame, LOAD, cb, this);
6579 Ext.fly(form).set(buf);
6580 Ext.each(hiddens, function(h) {
6589 * @extends Ext.data.Connection
6590 * <p>The global Ajax request class that provides a simple way to make Ajax requests
6591 * with maximum flexibility.</p>
6592 * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once
6593 * and override them at the request function level only if necessary.</p>
6594 * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>
6595 * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>
6596 * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>
6597 * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>
6600 // Default headers to pass in every request
6601 Ext.Ajax.defaultHeaders = {
6606 * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>
6607 * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>
6608 * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>
6609 * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>
6612 // Example: show a spinner during all Ajax requests
6613 Ext.Ajax.on('beforerequest', this.showSpinner, this);
6614 Ext.Ajax.on('requestcomplete', this.hideSpinner, this);
6615 Ext.Ajax.on('requestexception', this.hideSpinner, this);
6618 * <p>An example request:</p>
6621 Ext.Ajax.{@link Ext.data.Connection#request request}({
6628 params: { foo: 'bar' }
6631 // Simple ajax form submission
6632 Ext.Ajax.{@link Ext.data.Connection#request request}({
6640 Ext.Ajax = new Ext.data.Connection({
6642 * @cfg {String} url @hide
6645 * @cfg {Object} extraParams @hide
6648 * @cfg {Object} defaultHeaders @hide
6651 * @cfg {String} method (Optional) @hide
6654 * @cfg {Number} timeout (Optional) @hide
6657 * @cfg {Boolean} autoAbort (Optional) @hide
6661 * @cfg {Boolean} disableCaching (Optional) @hide
6665 * @property disableCaching
6666 * True to add a unique cache-buster param to GET requests. (defaults to true)
6671 * The default URL to be used for requests to the server. (defaults to undefined)
6672 * If the server receives all requests through one URL, setting this once is easier than
6673 * entering it on every request.
6677 * @property extraParams
6678 * An object containing properties which are used as extra parameters to each request made
6679 * by this object (defaults to undefined). Session information and other data that you need
6680 * to pass with each request are commonly put here.
6684 * @property defaultHeaders
6685 * An object containing request headers which are added to each request made by this object
6686 * (defaults to undefined).
6691 * The default HTTP method to be used for requests. Note that this is case-sensitive and
6692 * should be all caps (defaults to undefined; if not set but params are present will use
6693 * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
6698 * The timeout in milliseconds to be used for requests. (defaults to 30000)
6703 * @property autoAbort
6704 * Whether a new request should abort any pending requests. (defaults to false)
6710 * Serialize the passed form into a url encoded string
6711 * @param {String/HTMLElement} form
6714 serializeForm : function(form){
6715 return Ext.lib.Ajax.serializeForm(form);
6719 * @class Ext.util.JSON
6720 * Modified version of Douglas Crockford"s json.js that doesn"t
6721 * mess with the Object prototype
6722 * http://www.json.org/js.html
6725 Ext.util.JSON = new (function(){
6726 var useHasOwn = !!{}.hasOwnProperty,
6727 isNative = function() {
6728 var useNative = null;
6731 if (useNative === null) {
6732 useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
6739 return n < 10 ? "0" + n : n;
6741 doDecode = function(json){
6742 return eval("(" + json + ")");
6744 doEncode = function(o){
6745 if(!Ext.isDefined(o) || o === null){
6747 }else if(Ext.isArray(o)){
6748 return encodeArray(o);
6749 }else if(Ext.isDate(o)){
6750 return Ext.util.JSON.encodeDate(o);
6751 }else if(Ext.isString(o)){
6752 return encodeString(o);
6753 }else if(typeof o == "number"){
6754 //don't use isNumber here, since finite checks happen inside isNumber
6755 return isFinite(o) ? String(o) : "null";
6756 }else if(Ext.isBoolean(o)){
6759 var a = ["{"], b, i, v;
6761 // don't encode DOM objects
6762 if(!o.getElementsByTagName){
6763 if(!useHasOwn || o.hasOwnProperty(i)) {
6774 a.push(doEncode(i), ":",
6775 v === null ? "null" : doEncode(v));
6794 encodeString = function(s){
6795 if (/["\\\x00-\x1f]/.test(s)) {
6796 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
6803 Math.floor(c / 16).toString(16) +
6804 (c % 16).toString(16);
6807 return '"' + s + '"';
6809 encodeArray = function(o){
6810 var a = ["["], b, i, l = o.length, v;
6811 for (i = 0; i < l; i += 1) {
6822 a.push(v === null ? "null" : Ext.util.JSON.encode(v));
6831 * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
6832 * <b>The returned value includes enclosing double quotation marks.</b></p>
6833 * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
6834 * <p>To override this:</p><pre><code>
6835 Ext.util.JSON.encodeDate = function(d) {
6836 return d.format('"Y-m-d"');
6839 * @param {Date} d The Date to encode
6840 * @return {String} The string literal to use in a JSON string.
6842 this.encodeDate = function(o){
6843 return '"' + o.getFullYear() + "-" +
6844 pad(o.getMonth() + 1) + "-" +
6845 pad(o.getDate()) + "T" +
6846 pad(o.getHours()) + ":" +
6847 pad(o.getMinutes()) + ":" +
6848 pad(o.getSeconds()) + '"';
6852 * Encodes an Object, Array or other value
6853 * @param {Mixed} o The variable to encode
6854 * @return {String} The JSON string
6856 this.encode = function() {
6858 return function(o) {
6860 // setup encoding function on first access
6861 ec = isNative() ? JSON.stringify : doEncode;
6869 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
6870 * @param {String} json The JSON string
6871 * @return {Object} The resulting object
6873 this.decode = function() {
6875 return function(json) {
6877 // setup decoding function on first access
6878 dc = isNative() ? JSON.parse : doDecode;
6886 * Shorthand for {@link Ext.util.JSON#encode}
6887 * @param {Mixed} o The variable to encode
6888 * @return {String} The JSON string
6892 Ext.encode = Ext.util.JSON.encode;
6894 * Shorthand for {@link Ext.util.JSON#decode}
6895 * @param {String} json The JSON string
6896 * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
6897 * @return {Object} The resulting object
6901 Ext.decode = Ext.util.JSON.decode;
6903 * @class Ext.EventManager
6904 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6905 * several useful events directly.
6906 * See {@link Ext.EventObject} for more details on normalized event objects.
6909 Ext.EventManager = function(){
6912 docReadyState = false,
6913 DETECT_NATIVE = Ext.isGecko || Ext.isWebKit || Ext.isSafari,
6918 DOMCONTENTLOADED = "DOMContentLoaded",
6919 COMPLETE = 'complete',
6920 propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
6922 * This cache is used to hold special js objects, the document and window, that don't have an id. We need to keep
6923 * a reference to them so we can look them up at a later point.
6925 specialElCache = [];
6930 len = specialElCache.length,
6935 if (el.getElementById || el.navigator) {
6937 for(; i < len; ++i){
6938 o = specialElCache[i];
6945 // for browsers that support it, ensure that give the el the same id
6947 specialElCache.push({
6956 if(!Ext.elCache[id]){
6957 Ext.Element.addToCache(new Ext.Element(el), id);
6959 Ext.elCache[id].skipGC = true;
6966 /// There is some jquery work around stuff here that isn't needed in Ext Core.
6967 function addListener(el, ename, fn, task, wrap, scope){
6968 el = Ext.getDom(el);
6970 es = Ext.elCache[id].events,
6973 wfn = E.on(el, ename, wrap);
6974 es[ename] = es[ename] || [];
6976 /* 0 = Original Function,
6977 1 = Event Manager Wrapped Function,
6979 3 = Adapter Wrapped Function,
6982 es[ename].push([fn, wrap, scope, wfn, task]);
6984 // this is a workaround for jQuery and should somehow be removed from Ext Core in the future
6985 // without breaking ExtJS.
6987 // workaround for jQuery
6988 if(el.addEventListener && ename == "mousewheel"){
6989 var args = ["DOMMouseScroll", wrap, false];
6990 el.addEventListener.apply(el, args);
6991 Ext.EventManager.addListener(WINDOW, 'unload', function(){
6992 el.removeEventListener.apply(el, args);
6996 // fix stopped mousedowns on the document
6997 if(el == DOC && ename == "mousedown"){
6998 Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
7002 function doScrollChk(){
7004 'doScroll' will NOT work in a IFRAME/FRAMESET.
7005 The method succeeds but, a DOM query done immediately after -- FAILS.
7012 DOC.documentElement.doScroll('left');
7021 * @return {Boolean} True if the document is in a 'complete' state (or was determined to
7022 * be true by other means). If false, the state is evaluated again until canceled.
7024 function checkReadyState(e){
7026 if(Ext.isIE && doScrollChk()){
7029 if(DOC.readyState == COMPLETE){
7033 docReadyState || (docReadyProcId = setTimeout(arguments.callee, 2));
7038 function checkStyleSheets(e){
7039 styles || (styles = Ext.query('style, link[rel=stylesheet]'));
7040 if(styles.length == DOC.styleSheets.length){
7044 docReadyState || (docReadyProcId = setTimeout(arguments.callee, 2));
7048 function OperaDOMContentLoaded(e){
7049 DOC.removeEventListener(DOMCONTENTLOADED, arguments.callee, false);
7053 function fireDocReady(e){
7055 docReadyState = true; //only attempt listener removal once
7058 clearTimeout(docReadyProcId);
7061 DOC.removeEventListener(DOMCONTENTLOADED, fireDocReady, false);
7063 if(Ext.isIE && checkReadyState.bindIE){ //was this was actually set ??
7064 DOC.detachEvent('onreadystatechange', checkReadyState);
7066 E.un(WINDOW, "load", arguments.callee);
7068 if(docReadyEvent && !Ext.isReady){
7070 docReadyEvent.fire();
7071 docReadyEvent.listeners = [];
7076 function initDocReady(){
7077 docReadyEvent || (docReadyEvent = new Ext.util.Event());
7078 if (DETECT_NATIVE) {
7079 DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false);
7082 * Handle additional (exceptional) detection strategies here
7085 //Use readystatechange as a backup AND primary detection mechanism for a FRAME/IFRAME
7086 //See if page is already loaded
7087 if(!checkReadyState()){
7088 checkReadyState.bindIE = true;
7089 DOC.attachEvent('onreadystatechange', checkReadyState);
7092 }else if(Ext.isOpera ){
7094 Opera needs special treatment needed here because CSS rules are NOT QUITE
7095 available after DOMContentLoaded is raised.
7098 //See if page is already loaded and all styleSheets are in place
7099 (DOC.readyState == COMPLETE && checkStyleSheets()) ||
7100 DOC.addEventListener(DOMCONTENTLOADED, OperaDOMContentLoaded, false);
7102 }else if (Ext.isWebKit){
7103 //Fallback for older Webkits without DOMCONTENTLOADED support
7106 // no matter what, make sure it fires on load
7107 E.on(WINDOW, "load", fireDocReady);
7110 function createTargeted(h, o){
7112 var args = Ext.toArray(arguments);
7113 if(o.target == Ext.EventObject.setEvent(args[0]).target){
7114 h.apply(this, args);
7119 function createBuffered(h, o, task){
7121 // create new event object impl so new events don't wipe out properties
7122 task.delay(o.buffer, h, null, [new Ext.EventObjectImpl(e)]);
7126 function createSingle(h, el, ename, fn, scope){
7128 Ext.EventManager.removeListener(el, ename, fn, scope);
7133 function createDelayed(h, o, fn){
7135 var task = new Ext.util.DelayedTask(h);
7139 fn.tasks.push(task);
7140 task.delay(o.delay || 10, h, null, [new Ext.EventObjectImpl(e)]);
7144 function listen(element, ename, opt, fn, scope){
7145 var o = (!opt || typeof opt == "boolean") ? {} : opt,
7146 el = Ext.getDom(element), task;
7149 scope = scope || o.scope;
7152 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7155 // prevent errors while unload occurring
7156 if(!Ext){// !window[xname]){ ==> can't we do this?
7159 e = Ext.EventObject.setEvent(e);
7162 if(!(t = e.getTarget(o.delegate, el))){
7171 if (o.preventDefault) {
7174 if (o.stopPropagation) {
7175 e.stopPropagation();
7177 if (o.normalized === false) {
7181 fn.call(scope || el, e, t, o);
7184 h = createTargeted(h, o);
7187 h = createDelayed(h, o, fn);
7190 h = createSingle(h, el, ename, fn, scope);
7193 task = new Ext.util.DelayedTask(h);
7194 h = createBuffered(h, o, task);
7197 addListener(el, ename, fn, task, h, scope);
7203 * Appends an event handler to an element. The shorthand version {@link #on} is equivalent. Typically you will
7204 * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
7205 * @param {String/HTMLElement} el The html element or id to assign the event handler to.
7206 * @param {String} eventName The name of the event to listen for.
7207 * @param {Function} handler The handler function the event invokes. This function is passed
7208 * the following parameters:<ul>
7209 * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
7210 * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
7211 * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
7212 * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
7214 * @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>.
7215 * @param {Object} options (optional) An object containing handler configuration properties.
7216 * This may contain any of the following properties:<ul>
7217 * <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>
7218 * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
7219 * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
7220 * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
7221 * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
7222 * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
7223 * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
7224 * <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>
7225 * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
7226 * by the specified number of milliseconds. If the event fires again within that time, the original
7227 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
7228 * <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>
7230 * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
7232 addListener : function(element, eventName, fn, scope, options){
7233 if(typeof eventName == 'object'){
7234 var o = eventName, e, val;
7237 if(!propRe.test(e)){
7238 if(Ext.isFunction(val)){
7240 listen(element, e, o, val, o.scope);
7242 // individual options
7243 listen(element, e, val);
7248 listen(element, eventName, options, fn, scope);
7253 * Removes an event handler from an element. The shorthand version {@link #un} is equivalent. Typically
7254 * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
7255 * @param {String/HTMLElement} el The id or html element from which to remove the listener.
7256 * @param {String} eventName The name of the event.
7257 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
7258 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
7259 * then this must refer to the same object.
7261 removeListener : function(el, eventName, fn, scope){
7262 el = Ext.getDom(el);
7264 f = el && (Ext.elCache[id].events)[eventName] || [],
7265 wrap, i, l, k, len, fnc;
7267 for (i = 0, len = f.length; i < len; i++) {
7269 /* 0 = Original Function,
7270 1 = Event Manager Wrapped Function,
7272 3 = Adapter Wrapped Function,
7275 if (Ext.isArray(fnc = f[i]) && fnc[0] == fn && (!scope || fnc[2] == scope)) {
7279 k = fn.tasks && fn.tasks.length;
7282 fn.tasks[k].cancel();
7287 E.un(el, eventName, E.extAdapter ? fnc[3] : wrap);
7289 // jQuery workaround that should be removed from Ext Core
7290 if(wrap && el.addEventListener && eventName == "mousewheel"){
7291 el.removeEventListener("DOMMouseScroll", wrap, false);
7294 // fix stopped mousedowns on the document
7295 if(wrap && el == DOC && eventName == "mousedown"){
7296 Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
7300 if (f.length === 0) {
7301 delete Ext.elCache[id].events[eventName];
7303 for (k in Ext.elCache[id].events) {
7306 Ext.elCache[id].events = {};
7313 * Removes all event handers from an element. Typically you will use {@link Ext.Element#removeAllListeners}
7314 * directly on an Element in favor of calling this version.
7315 * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
7317 removeAll : function(el){
7318 el = Ext.getDom(el);
7320 ec = Ext.elCache[id] || {},
7321 es = ec.events || {},
7322 f, i, len, ename, fn, k, wrap;
7325 if(es.hasOwnProperty(ename)){
7327 /* 0 = Original Function,
7328 1 = Event Manager Wrapped Function,
7330 3 = Adapter Wrapped Function,
7333 for (i = 0, len = f.length; i < len; i++) {
7338 if(fn[0].tasks && (k = fn[0].tasks.length)) {
7340 fn[0].tasks[k].cancel();
7345 E.un(el, ename, E.extAdapter ? fn[3] : wrap);
7347 // jQuery workaround that should be removed from Ext Core
7348 if(el.addEventListener && wrap && ename == "mousewheel"){
7349 el.removeEventListener("DOMMouseScroll", wrap, false);
7352 // fix stopped mousedowns on the document
7353 if(wrap && el == DOC && ename == "mousedown"){
7354 Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
7359 if (Ext.elCache[id]) {
7360 Ext.elCache[id].events = {};
7364 getListeners : function(el, eventName) {
7365 el = Ext.getDom(el);
7367 ec = Ext.elCache[id] || {},
7368 es = ec.events || {},
7370 if (es && es[eventName]) {
7371 return es[eventName];
7377 purgeElement : function(el, recurse, eventName) {
7378 el = Ext.getDom(el);
7380 ec = Ext.elCache[id] || {},
7381 es = ec.events || {},
7384 if (es && es.hasOwnProperty(eventName)) {
7386 for (i = 0, len = f.length; i < len; i++) {
7387 Ext.EventManager.removeListener(el, eventName, f[i][0]);
7391 Ext.EventManager.removeAll(el);
7393 if (recurse && el && el.childNodes) {
7394 for (i = 0, len = el.childNodes.length; i < len; i++) {
7395 Ext.EventManager.purgeElement(el.childNodes[i], recurse, eventName);
7400 _unload : function() {
7402 for (el in Ext.elCache) {
7403 Ext.EventManager.removeAll(el);
7406 delete Ext.Element._flyweights;
7408 // Abort any outstanding Ajax requests
7412 ajax = Ext.lib.Ajax;
7413 (typeof ajax.conn == 'object') ? conn = ajax.conn : conn = {};
7417 ajax.abort({conn: c, tId: tid});
7422 * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
7423 * accessed shorthanded as Ext.onReady().
7424 * @param {Function} fn The method the event invokes.
7425 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
7426 * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
7427 * <code>{single: true}</code> be used so that the handler is removed on first invocation.
7429 onDocumentReady : function(fn, scope, options){
7430 if (Ext.isReady) { // if it already fired or document.body is present
7431 docReadyEvent || (docReadyEvent = new Ext.util.Event());
7432 docReadyEvent.addListener(fn, scope, options);
7433 docReadyEvent.fire();
7434 docReadyEvent.listeners = [];
7436 if (!docReadyEvent) {
7439 options = options || {};
7440 options.delay = options.delay || 1;
7441 docReadyEvent.addListener(fn, scope, options);
7446 * Forces a document ready state transition for the framework. Used when Ext is loaded
7447 * into a DOM structure AFTER initial page load (Google API or other dynamic load scenario.
7448 * Any pending 'onDocumentReady' handlers will be fired (if not already handled).
7450 fireDocReady : fireDocReady
7453 * Appends an event handler to an element. Shorthand for {@link #addListener}.
7454 * @param {String/HTMLElement} el The html element or id to assign the event handler to
7455 * @param {String} eventName The name of the event to listen for.
7456 * @param {Function} handler The handler function the event invokes.
7457 * @param {Object} scope (optional) (<code>this</code> reference) in which the handler function executes. <b>Defaults to the Element</b>.
7458 * @param {Object} options (optional) An object containing standard {@link #addListener} options
7459 * @member Ext.EventManager
7462 pub.on = pub.addListener;
7464 * Removes an event handler from an element. Shorthand for {@link #removeListener}.
7465 * @param {String/HTMLElement} el The id or html element from which to remove the listener.
7466 * @param {String} eventName The name of the event.
7467 * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #on} call.</b>
7468 * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
7469 * then this must refer to the same object.
7470 * @member Ext.EventManager
7473 pub.un = pub.removeListener;
7475 pub.stoppedMouseDownEvent = new Ext.util.Event();
7479 * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}.
7480 * @param {Function} fn The method the event invokes.
7481 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
7482 * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
7483 * <code>{single: true}</code> be used so that the handler is removed on first invocation.
7487 Ext.onReady = Ext.EventManager.onDocumentReady;
7490 //Initialize doc classes
7492 var initExtCss = function() {
7493 // find the body element
7494 var bd = document.body || document.getElementsByTagName('body')[0];
7500 Ext.isIE ? "ext-ie " + (Ext.isIE6 ? 'ext-ie6' : (Ext.isIE7 ? 'ext-ie7' : 'ext-ie8'))
7501 : Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? 'ext-gecko2' : 'ext-gecko3')
7502 : Ext.isOpera ? "ext-opera"
7503 : Ext.isWebKit ? "ext-webkit" : ""];
7506 cls.push("ext-safari " + (Ext.isSafari2 ? 'ext-safari2' : (Ext.isSafari3 ? 'ext-safari3' : 'ext-safari4')));
7507 } else if(Ext.isChrome) {
7508 cls.push("ext-chrome");
7512 cls.push("ext-mac");
7515 cls.push("ext-linux");
7518 // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7519 if (Ext.isStrict || Ext.isBorderBox) {
7520 var p = bd.parentNode;
7522 Ext.fly(p, '_internal').addClass(((Ext.isStrict && Ext.isIE ) || (!Ext.enableForcedBoxModel && !Ext.isIE)) ? ' ext-strict' : ' ext-border-box');
7525 // Forced border box model class applied to all elements. Bypassing javascript based box model adjustments
7526 // in favor of css. This is for non-IE browsers.
7527 if (Ext.enableForcedBoxModel && !Ext.isIE) {
7528 Ext.isForcedBorderBox = true;
7529 cls.push("ext-forced-border-box");
7532 Ext.fly(bd, '_internal').addClass(cls);
7536 if (!initExtCss()) {
7537 Ext.onReady(initExtCss);
7542 * Code used to detect certain browser feature/quirks/bugs at startup.
7545 var supports = Ext.apply(Ext.supports, {
7547 * In Webkit, there is an issue with getting the margin right property, see
7548 * https://bugs.webkit.org/show_bug.cgi?id=13343
7550 correctRightMargin: true,
7553 * Webkit browsers return rgba(0, 0, 0) when a transparent color is used
7555 correctTransparentColor: true,
7558 * IE uses styleFloat, not cssFloat for the float property.
7563 var supportTests = function(){
7564 var div = document.createElement('div'),
7569 div.innerHTML = '<div style="height:30px;width:50px;"><div style="height:20px;width:20px;"></div></div><div style="float:left;background-color:transparent;">';
7570 doc.body.appendChild(div);
7571 last = div.lastChild;
7573 if((view = doc.defaultView)){
7574 if(view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px'){
7575 supports.correctRightMargin = false;
7577 if(view.getComputedStyle(last, null).backgroundColor != 'transparent'){
7578 supports.correctTransparentColor = false;
7581 supports.cssFloat = !!last.style.cssFloat;
7582 doc.body.removeChild(div);
7588 Ext.onReady(supportTests);
7594 * @class Ext.EventObject
7595 * Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject
7596 * wraps the browser's native event-object normalizing cross-browser differences,
7597 * such as which mouse button is clicked, keys pressed, mechanisms to stop
7598 * event-propagation along with a method to prevent default actions from taking place.
7599 * <p>For example:</p>
7601 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
7603 var target = e.getTarget(); // same as t (the target HTMLElement)
7606 var myDiv = {@link Ext#get Ext.get}("myDiv"); // get reference to an {@link Ext.Element}
7607 myDiv.on( // 'on' is shorthand for addListener
7608 "click", // perform an action on click of myDiv
7609 handleClick // reference to the action handler
7611 // other methods to do the same:
7612 Ext.EventManager.on("myDiv", 'click', handleClick);
7613 Ext.EventManager.addListener("myDiv", 'click', handleClick);
7617 Ext.EventObject = function(){
7618 var E = Ext.lib.Event,
7619 clickRe = /(dbl)?click/,
7620 // safari keypress events for special keys return bad keycodes
7624 63235 : 39, // right
7627 63276 : 33, // page up
7628 63277 : 34, // page down
7629 63272 : 46, // delete
7633 // normalize button clicks
7634 btnMap = Ext.isIE ? {1:0,4:1,2:2} : {0:0,1:1,2:2};
7636 Ext.EventObjectImpl = function(e){
7638 this.setEvent(e.browserEvent || e);
7642 Ext.EventObjectImpl.prototype = {
7644 setEvent : function(e){
7646 if(e == me || (e && e.browserEvent)){ // already wrapped
7649 me.browserEvent = e;
7651 // normalize buttons
7652 me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);
7653 if(clickRe.test(e.type) && me.button == -1){
7657 me.shiftKey = e.shiftKey;
7658 // mac metaKey behaves like ctrlKey
7659 me.ctrlKey = e.ctrlKey || e.metaKey || false;
7660 me.altKey = e.altKey;
7661 // in getKey these will be normalized for the mac
7662 me.keyCode = e.keyCode;
7663 me.charCode = e.charCode;
7664 // cache the target for the delayed and or buffered events
7665 me.target = E.getTarget(e);
7670 me.shiftKey = false;
7682 * Stop the event (preventDefault and stopPropagation)
7684 stopEvent : function(){
7686 if(me.browserEvent){
7687 if(me.browserEvent.type == 'mousedown'){
7688 Ext.EventManager.stoppedMouseDownEvent.fire(me);
7690 E.stopEvent(me.browserEvent);
7695 * Prevents the browsers default handling of the event.
7697 preventDefault : function(){
7698 if(this.browserEvent){
7699 E.preventDefault(this.browserEvent);
7704 * Cancels bubbling of the event.
7706 stopPropagation : function(){
7708 if(me.browserEvent){
7709 if(me.browserEvent.type == 'mousedown'){
7710 Ext.EventManager.stoppedMouseDownEvent.fire(me);
7712 E.stopPropagation(me.browserEvent);
7717 * Gets the character code for the event.
7720 getCharCode : function(){
7721 return this.charCode || this.keyCode;
7725 * Returns a normalized keyCode for the event.
7726 * @return {Number} The key code
7728 getKey : function(){
7729 return this.normalizeKey(this.keyCode || this.charCode);
7733 normalizeKey: function(k){
7734 return Ext.isSafari ? (safariKeys[k] || k) : k;
7738 * Gets the x coordinate of the event.
7741 getPageX : function(){
7746 * Gets the y coordinate of the event.
7749 getPageY : function(){
7754 * Gets the page coordinates of the event.
7755 * @return {Array} The xy values like [x, y]
7762 * Gets the target for the event.
7763 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7764 * @param {Number/Mixed} maxDepth (optional) The max depth to
7765 search as a number or element (defaults to 10 || document.body)
7766 * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
7767 * @return {HTMLelement}
7769 getTarget : function(selector, maxDepth, returnEl){
7770 return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);
7774 * Gets the related target.
7775 * @return {HTMLElement}
7777 getRelatedTarget : function(){
7778 return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;
7782 * Normalizes mouse wheel delta across browsers
7783 * @return {Number} The delta
7785 getWheelDelta : function(){
7786 var e = this.browserEvent;
7788 if(e.wheelDelta){ /* IE/Opera. */
7789 delta = e.wheelDelta/120;
7790 }else if(e.detail){ /* Mozilla case. */
7791 delta = -e.detail/3;
7797 * 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.
7798 * Example usage:<pre><code>
7799 // Handle click on any child of an element
7800 Ext.getBody().on('click', function(e){
7801 if(e.within('some-el')){
7802 alert('Clicked on a child of some-el!');
7806 // Handle click directly on an element, ignoring clicks on child nodes
7807 Ext.getBody().on('click', function(e,t){
7808 if((t.id == 'some-el') && !e.within(t, true)){
7809 alert('Clicked directly on some-el!');
7813 * @param {Mixed} el The id, DOM element or Ext.Element to check
7814 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7815 * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
7818 within : function(el, related, allowEl){
7820 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7821 return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));
7827 return new Ext.EventObjectImpl();
7832 * Simple class to help load JavaScript files on demand
7834 Ext.Loader = Ext.apply({}, {
7836 * Loads a given set of .js files. Calls the callback function when all files have been loaded
7837 * Set preserveOrder to true to ensure non-parallel loading of files if load order is important
7838 * @param {Array} fileList Array of all files to load
7839 * @param {Function} callback Callback to call after all files have been loaded
7840 * @param {Object} scope The scope to call the callback in
7841 * @param {Boolean} preserveOrder True to make files load in serial, one after the other (defaults to false)
7843 load: function(fileList, callback, scope, preserveOrder) {
7844 var scope = scope || this,
7845 head = document.getElementsByTagName("head")[0],
7846 fragment = document.createDocumentFragment(),
7847 numFiles = fileList.length,
7852 * Loads a particular file from the fileList by index. This is used when preserving order
7854 var loadFileIndex = function(index) {
7856 me.buildScriptTag(fileList[index], onFileLoaded)
7861 * Callback function which is called after each file has been loaded. This calls the callback
7862 * passed to load once the final file in the fileList has been loaded
7864 var onFileLoaded = function() {
7867 //if this was the last file, call the callback, otherwise load the next file
7868 if (numFiles == loadedFiles && typeof callback == 'function') {
7869 callback.call(scope);
7871 if (preserveOrder === true) {
7872 loadFileIndex(loadedFiles);
7877 if (preserveOrder === true) {
7878 loadFileIndex.call(this, 0);
7880 //load each file (most browsers will do this in parallel)
7881 Ext.each(fileList, function(file, index) {
7882 fragment.appendChild(
7883 this.buildScriptTag(file, onFileLoaded)
7887 head.appendChild(fragment);
7893 * Creates and returns a script tag, but does not place it into the document. If a callback function
7894 * is passed, this is called when the script has been loaded
7895 * @param {String} filename The name of the file to create a script tag for
7896 * @param {Function} callback Optional callback, which is called when the script has been loaded
7897 * @return {Element} The new script ta
7899 buildScriptTag: function(filename, callback) {
7900 var script = document.createElement('script');
7901 script.type = "text/javascript";
7902 script.src = filename;
7904 //IE has a different way of handling <script> loads, so we need to check for it here
7905 if (script.readyState) {
7906 script.onreadystatechange = function() {
7907 if (script.readyState == "loaded" || script.readyState == "complete") {
7908 script.onreadystatechange = null;
7913 script.onload = callback;