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;