Subversion Repositories eFlore/Applications.cel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
27 jpm 1
/*
2
 * Ext JS Library 2.0.2
3
 * Copyright(c) 2006-2008, Ext JS, LLC.
4
 * licensing@extjs.com
5
 *
6
 * http://extjs.com/license
7
 */
8
 
9
/**
10
 * @class Ext.Element
11
 * Represents an Element in the DOM.<br><br>
12
 * Usage:<br>
13
<pre><code>
14
var el = Ext.get("my-div");
15
 
16
// or with getEl
17
var el = getEl("my-div");
18
 
19
// or with a DOM element
20
var el = Ext.get(myDivElement);
21
</code></pre>
22
 * Using Ext.get() or getEl() instead of calling the constructor directly ensures you get the same object
23
 * each call instead of constructing a new one.<br><br>
24
 * <b>Animations</b><br />
25
 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
26
 * should either be a boolean (true) or an object literal with animation options. Note that the supported Element animation
27
 * options are a subset of the {@link Ext.Fx} animation options specific to Fx effects.  The Element animation options are:
28
<pre>
29
Option    Default   Description
30
--------- --------  ---------------------------------------------
31
duration  .35       The duration of the animation in seconds
32
easing    easeOut   The easing method
33
callback  none      A function to execute when the anim completes
34
scope     this      The scope (this) of the callback function
35
</pre>
36
* Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
37
* manipulate the animation. Here's an example:
38
<pre><code>
39
var el = Ext.get("my-div");
40
 
41
// no animation
42
el.setWidth(100);
43
 
44
// default animation
45
el.setWidth(100, true);
46
 
47
// animation with some options set
48
el.setWidth(100, {
49
    duration: 1,
50
    callback: this.foo,
51
    scope: this
52
});
53
 
54
// using the "anim" property to get the Anim object
55
var opt = {
56
    duration: 1,
57
    callback: this.foo,
58
    scope: this
59
};
60
el.setWidth(100, opt);
61
...
62
if(opt.anim.isAnimated()){
63
    opt.anim.stop();
64
}
65
</code></pre>
66
* <b> Composite (Collections of) Elements</b><br />
67
 * For working with collections of Elements, see {@link Ext.CompositeElement}
68
 * @constructor Create a new Element directly.
69
 * @param {String/HTMLElement} element
70
 * @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).
71
 */
72
(function(){
73
var D = Ext.lib.Dom;
74
var E = Ext.lib.Event;
75
var A = Ext.lib.Anim;
76
 
77
// local style camelizing for speed
78
var propCache = {};
79
var camelRe = /(-[a-z])/gi;
80
var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
81
var view = document.defaultView;
82
 
83
Ext.Element = function(element, forceNew){
84
    var dom = typeof element == "string" ?
85
            document.getElementById(element) : element;
86
    if(!dom){ // invalid id/element
87
        return null;
88
    }
89
    var id = dom.id;
90
    if(forceNew !== true && id && Ext.Element.cache[id]){ // element object already exists
91
        return Ext.Element.cache[id];
92
    }
93
 
94
    /**
95
     * The DOM element
96
     * @type HTMLElement
97
     */
98
    this.dom = dom;
99
 
100
    /**
101
     * The DOM element ID
102
     * @type String
103
     */
104
    this.id = id || Ext.id(dom);
105
};
106
 
107
var El = Ext.Element;
108
 
109
El.prototype = {
110
    /**
111
     * The element's default display mode  (defaults to "")
112
     * @type String
113
     */
114
    originalDisplay : "",
115
 
116
    visibilityMode : 1,
117
    /**
118
     * The default unit to append to CSS values where a unit isn't provided (defaults to px).
119
     * @type String
120
     */
121
    defaultUnit : "px",
122
    /**
123
     * Sets the element's visibility mode. When setVisible() is called it
124
     * will use this to determine whether to set the visibility or the display property.
125
     * @param visMode Element.VISIBILITY or Element.DISPLAY
126
     * @return {Ext.Element} this
127
     */
128
    setVisibilityMode : function(visMode){
129
        this.visibilityMode = visMode;
130
        return this;
131
    },
132
    /**
133
     * Convenience method for setVisibilityMode(Element.DISPLAY)
134
     * @param {String} display (optional) What to set display to when visible
135
     * @return {Ext.Element} this
136
     */
137
    enableDisplayMode : function(display){
138
        this.setVisibilityMode(El.DISPLAY);
139
        if(typeof display != "undefined") this.originalDisplay = display;
140
        return this;
141
    },
142
 
143
    /**
144
     * 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)
145
     * @param {String} selector The simple selector to test
146
     * @param {Number/Mixed} maxDepth (optional) The max depth to
147
            search as a number or element (defaults to 10 || document.body)
148
     * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
149
     * @return {HTMLElement} The matching DOM node (or null if no match was found)
150
     */
151
    findParent : function(simpleSelector, maxDepth, returnEl){
152
        var p = this.dom, b = document.body, depth = 0, dq = Ext.DomQuery, stopEl;
153
        maxDepth = maxDepth || 50;
154
        if(typeof maxDepth != "number"){
155
            stopEl = Ext.getDom(maxDepth);
156
            maxDepth = 10;
157
        }
158
        while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
159
            if(dq.is(p, simpleSelector)){
160
                return returnEl ? Ext.get(p) : p;
161
            }
162
            depth++;
163
            p = p.parentNode;
164
        }
165
        return null;
166
    },
167
 
168
 
169
    /**
170
     * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
171
     * @param {String} selector The simple selector to test
172
     * @param {Number/Mixed} maxDepth (optional) The max depth to
173
            search as a number or element (defaults to 10 || document.body)
174
     * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
175
     * @return {HTMLElement} The matching DOM node (or null if no match was found)
176
     */
177
    findParentNode : function(simpleSelector, maxDepth, returnEl){
178
        var p = Ext.fly(this.dom.parentNode, '_internal');
179
        return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
180
    },
181
 
182
    /**
183
     * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
184
     * This is a shortcut for findParentNode() that always returns an Ext.Element.
185
     * @param {String} selector The simple selector to test
186
     * @param {Number/Mixed} maxDepth (optional) The max depth to
187
            search as a number or element (defaults to 10 || document.body)
188
     * @return {Ext.Element} The matching DOM node (or null if no match was found)
189
     */
190
    up : function(simpleSelector, maxDepth){
191
        return this.findParentNode(simpleSelector, maxDepth, true);
192
    },
193
 
194
 
195
 
196
    /**
197
     * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
198
     * @param {String} selector The simple selector to test
199
     * @return {Boolean} True if this element matches the selector, else false
200
     */
201
    is : function(simpleSelector){
202
        return Ext.DomQuery.is(this.dom, simpleSelector);
203
    },
204
 
205
    /**
206
     * Perform animation on this element.
207
     * @param {Object} args The animation control args
208
     * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
209
     * @param {Function} onComplete (optional) Function to call when animation completes
210
     * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
211
     * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
212
     * @return {Ext.Element} this
213
     */
214
    animate : function(args, duration, onComplete, easing, animType){
215
        this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
216
        return this;
217
    },
218
 
219
    /*
220
     * @private Internal animation call
221
     */
222
    anim : function(args, opt, animType, defaultDur, defaultEase, cb){
223
        animType = animType || 'run';
224
        opt = opt || {};
225
        var anim = Ext.lib.Anim[animType](
226
            this.dom, args,
227
            (opt.duration || defaultDur) || .35,
228
            (opt.easing || defaultEase) || 'easeOut',
229
            function(){
230
                Ext.callback(cb, this);
231
                Ext.callback(opt.callback, opt.scope || this, [this, opt]);
232
            },
233
            this
234
        );
235
        opt.anim = anim;
236
        return anim;
237
    },
238
 
239
    // private legacy anim prep
240
    preanim : function(a, i){
241
        return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
242
    },
243
 
244
    /**
245
     * Removes worthless text nodes
246
     * @param {Boolean} forceReclean (optional) By default the element
247
     * keeps track if it has been cleaned already so
248
     * you can call this over and over. However, if you update the element and
249
     * need to force a reclean, you can pass true.
250
     */
251
    clean : function(forceReclean){
252
        if(this.isCleaned && forceReclean !== true){
253
            return this;
254
        }
255
        var ns = /\S/;
256
        var d = this.dom, n = d.firstChild, ni = -1;
257
 	    while(n){
258
 	        var nx = n.nextSibling;
259
 	        if(n.nodeType == 3 && !ns.test(n.nodeValue)){
260
 	            d.removeChild(n);
261
 	        }else{
262
 	            n.nodeIndex = ++ni;
263
 	        }
264
 	        n = nx;
265
 	    }
266
 	    this.isCleaned = true;
267
 	    return this;
268
 	},
269
 
270
    /**
271
     * Scrolls this element into view within the passed container.
272
     * @param {Mixed} container (optional) The container element to scroll (defaults to document.body)
273
     * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
274
     * @return {Ext.Element} this
275
     */
276
    scrollIntoView : function(container, hscroll){
277
        var c = Ext.getDom(container) || Ext.getBody().dom;
278
        var el = this.dom;
279
 
280
        var o = this.getOffsetsTo(c),
281
            l = o[0] + c.scrollLeft,
282
            t = o[1] + c.scrollTop,
283
            b = t+el.offsetHeight,
284
            r = l+el.offsetWidth;
285
 
286
        var ch = c.clientHeight;
287
        var ct = parseInt(c.scrollTop, 10);
288
        var cl = parseInt(c.scrollLeft, 10);
289
        var cb = ct + ch;
290
        var cr = cl + c.clientWidth;
291
 
292
        if(el.offsetHeight > ch || t < ct){
293
        	c.scrollTop = t;
294
        }else if(b > cb){
295
            c.scrollTop = b-ch;
296
        }
297
        c.scrollTop = c.scrollTop; // corrects IE, other browsers will ignore
298
 
299
        if(hscroll !== false){
300
			if(el.offsetWidth > c.clientWidth || l < cl){
301
                c.scrollLeft = l;
302
            }else if(r > cr){
303
                c.scrollLeft = r-c.clientWidth;
304
            }
305
            c.scrollLeft = c.scrollLeft;
306
        }
307
        return this;
308
    },
309
 
310
    // private
311
    scrollChildIntoView : function(child, hscroll){
312
        Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
313
    },
314
 
315
    /**
316
     * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
317
     * the new height may not be available immediately.
318
     * @param {Boolean} animate (optional) Animate the transition (defaults to false)
319
     * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
320
     * @param {Function} onComplete (optional) Function to call when animation completes
321
     * @param {String} easing (optional) Easing method to use (defaults to easeOut)
322
     * @return {Ext.Element} this
323
     */
324
    autoHeight : function(animate, duration, onComplete, easing){
325
        var oldHeight = this.getHeight();
326
        this.clip();
327
        this.setHeight(1); // force clipping
328
        setTimeout(function(){
329
            var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
330
            if(!animate){
331
                this.setHeight(height);
332
                this.unclip();
333
                if(typeof onComplete == "function"){
334
                    onComplete();
335
                }
336
            }else{
337
                this.setHeight(oldHeight); // restore original height
338
                this.setHeight(height, animate, duration, function(){
339
                    this.unclip();
340
                    if(typeof onComplete == "function") onComplete();
341
                }.createDelegate(this), easing);
342
            }
343
        }.createDelegate(this), 0);
344
        return this;
345
    },
346
 
347
    /**
348
     * Returns true if this element is an ancestor of the passed element
349
     * @param {HTMLElement/String} el The element to check
350
     * @return {Boolean} True if this element is an ancestor of el, else false
351
     */
352
    contains : function(el){
353
        if(!el){return false;}
354
        return D.isAncestor(this.dom, el.dom ? el.dom : el);
355
    },
356
 
357
    /**
358
     * Checks whether the element is currently visible using both visibility and display properties.
359
     * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
360
     * @return {Boolean} True if the element is currently visible, else false
361
     */
362
    isVisible : function(deep) {
363
        var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
364
        if(deep !== true || !vis){
365
            return vis;
366
        }
367
        var p = this.dom.parentNode;
368
        while(p && p.tagName.toLowerCase() != "body"){
369
            if(!Ext.fly(p, '_isVisible').isVisible()){
370
                return false;
371
            }
372
            p = p.parentNode;
373
        }
374
        return true;
375
    },
376
 
377
    /**
378
     * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
379
     * @param {String} selector The CSS selector
380
     * @param {Boolean} unique (optional) True to create a unique Ext.Element for each child (defaults to false, which creates a single shared flyweight object)
381
     * @return {CompositeElement/CompositeElementLite} The composite element
382
     */
383
    select : function(selector, unique){
384
        return El.select(selector, unique, this.dom);
385
    },
386
 
387
    /**
388
     * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
389
     * @param {String} selector The CSS selector
390
     * @return {Array} An array of the matched nodes
391
     */
392
    query : function(selector, unique){
393
        return Ext.DomQuery.select(selector, this.dom);
394
    },
395
 
396
    /**
397
     * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
398
     * @param {String} selector The CSS selector
399
     * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
400
     * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
401
     */
402
    child : function(selector, returnDom){
403
        var n = Ext.DomQuery.selectNode(selector, this.dom);
404
        return returnDom ? n : Ext.get(n);
405
    },
406
 
407
    /**
408
     * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
409
     * @param {String} selector The CSS selector
410
     * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
411
     * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
412
     */
413
    down : function(selector, returnDom){
414
        var n = Ext.DomQuery.selectNode(" > " + selector, this.dom);
415
        return returnDom ? n : Ext.get(n);
416
    },
417
 
418
    /**
419
     * Initializes a {@link Ext.dd.DD} drag drop object for this element.
420
     * @param {String} group The group the DD object is member of
421
     * @param {Object} config The DD config object
422
     * @param {Object} overrides An object containing methods to override/implement on the DD object
423
     * @return {Ext.dd.DD} The DD object
424
     */
425
    initDD : function(group, config, overrides){
426
        var dd = new Ext.dd.DD(Ext.id(this.dom), group, config);
427
        return Ext.apply(dd, overrides);
428
    },
429
 
430
    /**
431
     * Initializes a {@link Ext.dd.DDProxy} object for this element.
432
     * @param {String} group The group the DDProxy object is member of
433
     * @param {Object} config The DDProxy config object
434
     * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
435
     * @return {Ext.dd.DDProxy} The DDProxy object
436
     */
437
    initDDProxy : function(group, config, overrides){
438
        var dd = new Ext.dd.DDProxy(Ext.id(this.dom), group, config);
439
        return Ext.apply(dd, overrides);
440
    },
441
 
442
    /**
443
     * Initializes a {@link Ext.dd.DDTarget} object for this element.
444
     * @param {String} group The group the DDTarget object is member of
445
     * @param {Object} config The DDTarget config object
446
     * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
447
     * @return {Ext.dd.DDTarget} The DDTarget object
448
     */
449
    initDDTarget : function(group, config, overrides){
450
        var dd = new Ext.dd.DDTarget(Ext.id(this.dom), group, config);
451
        return Ext.apply(dd, overrides);
452
    },
453
 
454
    /**
455
     * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
456
     * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
457
     * @param {Boolean} visible Whether the element is visible
458
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
459
     * @return {Ext.Element} this
460
     */
461
     setVisible : function(visible, animate){
462
        if(!animate || !A){
463
            if(this.visibilityMode == El.DISPLAY){
464
                this.setDisplayed(visible);
465
            }else{
466
                this.fixDisplay();
467
                this.dom.style.visibility = visible ? "visible" : "hidden";
468
            }
469
        }else{
470
            // closure for composites
471
            var dom = this.dom;
472
            var visMode = this.visibilityMode;
473
            if(visible){
474
                this.setOpacity(.01);
475
                this.setVisible(true);
476
            }
477
            this.anim({opacity: { to: (visible?1:0) }},
478
                  this.preanim(arguments, 1),
479
                  null, .35, 'easeIn', function(){
480
                     if(!visible){
481
                         if(visMode == El.DISPLAY){
482
                             dom.style.display = "none";
483
                         }else{
484
                             dom.style.visibility = "hidden";
485
                         }
486
                         Ext.get(dom).setOpacity(1);
487
                     }
488
                 });
489
        }
490
        return this;
491
    },
492
 
493
    /**
494
     * Returns true if display is not "none"
495
     * @return {Boolean}
496
     */
497
    isDisplayed : function() {
498
        return this.getStyle("display") != "none";
499
    },
500
 
501
    /**
502
     * Toggles the element's visibility or display, depending on visibility mode.
503
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
504
     * @return {Ext.Element} this
505
     */
506
    toggle : function(animate){
507
        this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
508
        return this;
509
    },
510
 
511
    /**
512
     * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
513
     * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
514
     * @return {Ext.Element} this
515
     */
516
    setDisplayed : function(value) {
517
        if(typeof value == "boolean"){
518
           value = value ? this.originalDisplay : "none";
519
        }
520
        this.setStyle("display", value);
521
        return this;
522
    },
523
 
524
    /**
525
     * Tries to focus the element. Any exceptions are caught and ignored.
526
     * @return {Ext.Element} this
527
     */
528
    focus : function() {
529
        try{
530
            this.dom.focus();
531
        }catch(e){}
532
        return this;
533
    },
534
 
535
    /**
536
     * Tries to blur the element. Any exceptions are caught and ignored.
537
     * @return {Ext.Element} this
538
     */
539
    blur : function() {
540
        try{
541
            this.dom.blur();
542
        }catch(e){}
543
        return this;
544
    },
545
 
546
    /**
547
     * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
548
     * @param {String/Array} className The CSS class to add, or an array of classes
549
     * @return {Ext.Element} this
550
     */
551
    addClass : function(className){
552
        if(Ext.isArray(className)){
553
            for(var i = 0, len = className.length; i < len; i++) {
554
            	this.addClass(className[i]);
555
            }
556
        }else{
557
            if(className && !this.hasClass(className)){
558
                this.dom.className = this.dom.className + " " + className;
559
            }
560
        }
561
        return this;
562
    },
563
 
564
    /**
565
     * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
566
     * @param {String/Array} className The CSS class to add, or an array of classes
567
     * @return {Ext.Element} this
568
     */
569
    radioClass : function(className){
570
        var siblings = this.dom.parentNode.childNodes;
571
        for(var i = 0; i < siblings.length; i++) {
572
        	var s = siblings[i];
573
        	if(s.nodeType == 1){
574
        	    Ext.get(s).removeClass(className);
575
        	}
576
        }
577
        this.addClass(className);
578
        return this;
579
    },
580
 
581
    /**
582
     * Removes one or more CSS classes from the element.
583
     * @param {String/Array} className The CSS class to remove, or an array of classes
584
     * @return {Ext.Element} this
585
     */
586
    removeClass : function(className){
587
        if(!className || !this.dom.className){
588
            return this;
589
        }
590
        if(Ext.isArray(className)){
591
            for(var i = 0, len = className.length; i < len; i++) {
592
            	this.removeClass(className[i]);
593
            }
594
        }else{
595
            if(this.hasClass(className)){
596
                var re = this.classReCache[className];
597
                if (!re) {
598
                   re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
599
                   this.classReCache[className] = re;
600
                }
601
                this.dom.className =
602
                    this.dom.className.replace(re, " ");
603
            }
604
        }
605
        return this;
606
    },
607
 
608
    // private
609
    classReCache: {},
610
 
611
    /**
612
     * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
613
     * @param {String} className The CSS class to toggle
614
     * @return {Ext.Element} this
615
     */
616
    toggleClass : function(className){
617
        if(this.hasClass(className)){
618
            this.removeClass(className);
619
        }else{
620
            this.addClass(className);
621
        }
622
        return this;
623
    },
624
 
625
    /**
626
     * Checks if the specified CSS class exists on this element's DOM node.
627
     * @param {String} className The CSS class to check for
628
     * @return {Boolean} True if the class exists, else false
629
     */
630
    hasClass : function(className){
631
        return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
632
    },
633
 
634
    /**
635
     * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
636
     * @param {String} oldClassName The CSS class to replace
637
     * @param {String} newClassName The replacement CSS class
638
     * @return {Ext.Element} this
639
     */
640
    replaceClass : function(oldClassName, newClassName){
641
        this.removeClass(oldClassName);
642
        this.addClass(newClassName);
643
        return this;
644
    },
645
 
646
    /**
647
     * Returns an object with properties matching the styles requested.
648
     * For example, el.getStyles('color', 'font-size', 'width') might return
649
     * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
650
     * @param {String} style1 A style name
651
     * @param {String} style2 A style name
652
     * @param {String} etc.
653
     * @return {Object} The style object
654
     */
655
    getStyles : function(){
656
        var a = arguments, len = a.length, r = {};
657
        for(var i = 0; i < len; i++){
658
            r[a[i]] = this.getStyle(a[i]);
659
        }
660
        return r;
661
    },
662
 
663
    /**
664
     * Normalizes currentStyle and computedStyle.
665
     * @param {String} property The style property whose value is returned.
666
     * @return {String} The current value of the style property for this element.
667
     */
668
    getStyle : function(){
669
        return view && view.getComputedStyle ?
670
            function(prop){
671
                var el = this.dom, v, cs, camel;
672
                if(prop == 'float'){
673
                    prop = "cssFloat";
674
                }
675
                if(v = el.style[prop]){
676
                    return v;
677
                }
678
                if(cs = view.getComputedStyle(el, "")){
679
                    if(!(camel = propCache[prop])){
680
                        camel = propCache[prop] = prop.replace(camelRe, camelFn);
681
                    }
682
                    return cs[camel];
683
                }
684
                return null;
685
            } :
686
            function(prop){
687
                var el = this.dom, v, cs, camel;
688
                if(prop == 'opacity'){
689
                    if(typeof el.style.filter == 'string'){
690
                        var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
691
                        if(m){
692
                            var fv = parseFloat(m[1]);
693
                            if(!isNaN(fv)){
694
                                return fv ? fv / 100 : 0;
695
                            }
696
                        }
697
                    }
698
                    return 1;
699
                }else if(prop == 'float'){
700
                    prop = "styleFloat";
701
                }
702
                if(!(camel = propCache[prop])){
703
                    camel = propCache[prop] = prop.replace(camelRe, camelFn);
704
                }
705
                if(v = el.style[camel]){
706
                    return v;
707
                }
708
                if(cs = el.currentStyle){
709
                    return cs[camel];
710
                }
711
                return null;
712
            };
713
    }(),
714
 
715
    /**
716
     * Wrapper for setting style properties, also takes single object parameter of multiple styles.
717
     * @param {String/Object} property The style property to be set, or an object of multiple styles.
718
     * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
719
     * @return {Ext.Element} this
720
     */
721
    setStyle : function(prop, value){
722
        if(typeof prop == "string"){
723
            var camel;
724
            if(!(camel = propCache[prop])){
725
                camel = propCache[prop] = prop.replace(camelRe, camelFn);
726
            }
727
            if(camel == 'opacity') {
728
                this.setOpacity(value);
729
            }else{
730
                this.dom.style[camel] = value;
731
            }
732
        }else{
733
            for(var style in prop){
734
                if(typeof prop[style] != "function"){
735
                   this.setStyle(style, prop[style]);
736
                }
737
            }
738
        }
739
        return this;
740
    },
741
 
742
    /**
743
     * More flexible version of {@link #setStyle} for setting style properties.
744
     * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
745
     * a function which returns such a specification.
746
     * @return {Ext.Element} this
747
     */
748
    applyStyles : function(style){
749
        Ext.DomHelper.applyStyles(this.dom, style);
750
        return this;
751
    },
752
 
753
    /**
754
      * 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).
755
      * @return {Number} The X position of the element
756
      */
757
    getX : function(){
758
        return D.getX(this.dom);
759
    },
760
 
761
    /**
762
      * 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).
763
      * @return {Number} The Y position of the element
764
      */
765
    getY : function(){
766
        return D.getY(this.dom);
767
    },
768
 
769
    /**
770
      * 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).
771
      * @return {Array} The XY position of the element
772
      */
773
    getXY : function(){
774
        return D.getXY(this.dom);
775
    },
776
 
777
    /**
778
      * 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.
779
      * @param {Mixed} element The element to get the offsets from.
780
      * @return {Array} The XY page offsets (e.g. [100, -200])
781
      */
782
    getOffsetsTo : function(el){
783
        var o = this.getXY();
784
        var e = Ext.fly(el, '_internal').getXY();
785
        return [o[0]-e[0],o[1]-e[1]];
786
    },
787
 
788
    /**
789
     * 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).
790
     * @param {Number} The X position of the element
791
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
792
     * @return {Ext.Element} this
793
     */
794
    setX : function(x, animate){
795
        if(!animate || !A){
796
            D.setX(this.dom, x);
797
        }else{
798
            this.setXY([x, this.getY()], this.preanim(arguments, 1));
799
        }
800
        return this;
801
    },
802
 
803
    /**
804
     * 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).
805
     * @param {Number} The Y position of the element
806
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
807
     * @return {Ext.Element} this
808
     */
809
    setY : function(y, animate){
810
        if(!animate || !A){
811
            D.setY(this.dom, y);
812
        }else{
813
            this.setXY([this.getX(), y], this.preanim(arguments, 1));
814
        }
815
        return this;
816
    },
817
 
818
    /**
819
     * Sets the element's left position directly using CSS style (instead of {@link #setX}).
820
     * @param {String} left The left CSS property value
821
     * @return {Ext.Element} this
822
     */
823
    setLeft : function(left){
824
        this.setStyle("left", this.addUnits(left));
825
        return this;
826
    },
827
 
828
    /**
829
     * Sets the element's top position directly using CSS style (instead of {@link #setY}).
830
     * @param {String} top The top CSS property value
831
     * @return {Ext.Element} this
832
     */
833
    setTop : function(top){
834
        this.setStyle("top", this.addUnits(top));
835
        return this;
836
    },
837
 
838
    /**
839
     * Sets the element's CSS right style.
840
     * @param {String} right The right CSS property value
841
     * @return {Ext.Element} this
842
     */
843
    setRight : function(right){
844
        this.setStyle("right", this.addUnits(right));
845
        return this;
846
    },
847
 
848
    /**
849
     * Sets the element's CSS bottom style.
850
     * @param {String} bottom The bottom CSS property value
851
     * @return {Ext.Element} this
852
     */
853
    setBottom : function(bottom){
854
        this.setStyle("bottom", this.addUnits(bottom));
855
        return this;
856
    },
857
 
858
    /**
859
     * Sets the position of the element in page coordinates, regardless of how the element is positioned.
860
     * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
861
     * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
862
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
863
     * @return {Ext.Element} this
864
     */
865
    setXY : function(pos, animate){
866
        if(!animate || !A){
867
            D.setXY(this.dom, pos);
868
        }else{
869
            this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
870
        }
871
        return this;
872
    },
873
 
874
    /**
875
     * Sets the position of the element in page coordinates, regardless of how the element is positioned.
876
     * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
877
     * @param {Number} x X value for new position (coordinates are page-based)
878
     * @param {Number} y Y value for new position (coordinates are page-based)
879
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
880
     * @return {Ext.Element} this
881
     */
882
    setLocation : function(x, y, animate){
883
        this.setXY([x, y], this.preanim(arguments, 2));
884
        return this;
885
    },
886
 
887
    /**
888
     * Sets the position of the element in page coordinates, regardless of how the element is positioned.
889
     * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
890
     * @param {Number} x X value for new position (coordinates are page-based)
891
     * @param {Number} y Y value for new position (coordinates are page-based)
892
     * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
893
     * @return {Ext.Element} this
894
     */
895
    moveTo : function(x, y, animate){
896
        this.setXY([x, y], this.preanim(arguments, 2));
897
        return this;
898
    },
899
 
900
    /**
901
     * Returns the region of the given element.
902
     * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
903
     * @return {Region} A Ext.lib.Region containing "top, left, bottom, right" member data.
904
     */
905
    getRegion : function(){
906
        return D.getRegion(this.dom);
907
    },
908
 
909
    /**
910
     * Returns the offset height of the element
911
     * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
912
     * @return {Number} The element's height
913
     */
914
    getHeight : function(contentHeight){
915
        var h = this.dom.offsetHeight || 0;
916
        h = contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
917
        return h < 0 ? 0 : h;
918
    },
919
 
920
    /**
921
     * Returns the offset width of the element
922
     * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
923
     * @return {Number} The element's width
924
     */
925
    getWidth : function(contentWidth){
926
        var w = this.dom.offsetWidth || 0;
927
        w = contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
928
        return w < 0 ? 0 : w;
929
    },
930
 
931
    /**
932
     * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
933
     * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
934
     * if a height has not been set using CSS.
935
     * @return {Number}
936
     */
937
    getComputedHeight : function(){
938
        var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
939
        if(!h){
940
            h = parseInt(this.getStyle('height'), 10) || 0;
941
            if(!this.isBorderBox()){
942
                h += this.getFrameWidth('tb');
943
            }
944
        }
945
        return h;
946
    },
947
 
948
    /**
949
     * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
950
     * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
951
     * if a width has not been set using CSS.
952
     * @return {Number}
953
     */
954
    getComputedWidth : function(){
955
        var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
956
        if(!w){
957
            w = parseInt(this.getStyle('width'), 10) || 0;
958
            if(!this.isBorderBox()){
959
                w += this.getFrameWidth('lr');
960
            }
961
        }
962
        return w;
963
    },
964
 
965
    /**
966
     * Returns the size of the element.
967
     * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
968
     * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
969
     */
970
    getSize : function(contentSize){
971
        return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
972
    },
973
 
974
    getStyleSize : function(){
975
        var w, h, d = this.dom, s = d.style;
976
        if(s.width && s.width != 'auto'){
977
            w = parseInt(s.width, 10);
978
            if(Ext.isBorderBox){
979
               w -= this.getFrameWidth('lr');
980
            }
981
        }
982
        if(s.height && s.height != 'auto'){
983
            h = parseInt(s.height, 10);
984
            if(Ext.isBorderBox){
985
               h -= this.getFrameWidth('tb');
986
            }
987
        }
988
        return {width: w || this.getWidth(true), height: h || this.getHeight(true)};
989
 
990
    },
991
 
992
    /**
993
     * Returns the width and height of the viewport.
994
     * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
995
     */
996
    getViewSize : function(){
997
        var d = this.dom, doc = document, aw = 0, ah = 0;
998
        if(d == doc || d == doc.body){
999
            return {width : D.getViewWidth(), height: D.getViewHeight()};
1000
        }else{
1001
            return {
1002
                width : d.clientWidth,
1003
                height: d.clientHeight
1004
            };
1005
        }
1006
    },
1007
 
1008
    /**
1009
     * Returns the value of the "value" attribute
1010
     * @param {Boolean} asNumber true to parse the value as a number
1011
     * @return {String/Number}
1012
     */
1013
    getValue : function(asNumber){
1014
        return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
1015
    },
1016
 
1017
    // private
1018
    adjustWidth : function(width){
1019
        if(typeof width == "number"){
1020
            if(this.autoBoxAdjust && !this.isBorderBox()){
1021
               width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
1022
            }
1023
            if(width < 0){
1024
                width = 0;
1025
            }
1026
        }
1027
        return width;
1028
    },
1029
 
1030
    // private
1031
    adjustHeight : function(height){
1032
        if(typeof height == "number"){
1033
           if(this.autoBoxAdjust && !this.isBorderBox()){
1034
               height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
1035
           }
1036
           if(height < 0){
1037
               height = 0;
1038
           }
1039
        }
1040
        return height;
1041
    },
1042
 
1043
    /**
1044
     * Set the width of the element
1045
     * @param {Number} width The new width
1046
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1047
     * @return {Ext.Element} this
1048
     */
1049
    setWidth : function(width, animate){
1050
        width = this.adjustWidth(width);
1051
        if(!animate || !A){
1052
            this.dom.style.width = this.addUnits(width);
1053
        }else{
1054
            this.anim({width: {to: width}}, this.preanim(arguments, 1));
1055
        }
1056
        return this;
1057
    },
1058
 
1059
    /**
1060
     * Set the height of the element
1061
     * @param {Number} height The new height
1062
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1063
     * @return {Ext.Element} this
1064
     */
1065
     setHeight : function(height, animate){
1066
        height = this.adjustHeight(height);
1067
        if(!animate || !A){
1068
            this.dom.style.height = this.addUnits(height);
1069
        }else{
1070
            this.anim({height: {to: height}}, this.preanim(arguments, 1));
1071
        }
1072
        return this;
1073
    },
1074
 
1075
    /**
1076
     * Set the size of the element. If animation is true, both width an height will be animated concurrently.
1077
     * @param {Number} width The new width
1078
     * @param {Number} height The new height
1079
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1080
     * @return {Ext.Element} this
1081
     */
1082
     setSize : function(width, height, animate){
1083
        if(typeof width == "object"){ // in case of object from getSize()
1084
            height = width.height; width = width.width;
1085
        }
1086
        width = this.adjustWidth(width); height = this.adjustHeight(height);
1087
        if(!animate || !A){
1088
            this.dom.style.width = this.addUnits(width);
1089
            this.dom.style.height = this.addUnits(height);
1090
        }else{
1091
            this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
1092
        }
1093
        return this;
1094
    },
1095
 
1096
    /**
1097
     * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
1098
     * @param {Number} x X value for new position (coordinates are page-based)
1099
     * @param {Number} y Y value for new position (coordinates are page-based)
1100
     * @param {Number} width The new width
1101
     * @param {Number} height The new height
1102
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1103
     * @return {Ext.Element} this
1104
     */
1105
    setBounds : function(x, y, width, height, animate){
1106
        if(!animate || !A){
1107
            this.setSize(width, height);
1108
            this.setLocation(x, y);
1109
        }else{
1110
            width = this.adjustWidth(width); height = this.adjustHeight(height);
1111
            this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
1112
                          this.preanim(arguments, 4), 'motion');
1113
        }
1114
        return this;
1115
    },
1116
 
1117
    /**
1118
     * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
1119
     * @param {Ext.lib.Region} region The region to fill
1120
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1121
     * @return {Ext.Element} this
1122
     */
1123
    setRegion : function(region, animate){
1124
        this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
1125
        return this;
1126
    },
1127
 
1128
    /**
1129
     * Appends an event handler to this element.  The shorthand version {@link #on} is equivalent.
1130
     * @param {String} eventName The type of event to handle
1131
     * @param {Function} fn The handler function the event invokes
1132
     * @param {Object} scope (optional) The scope (this element) of the handler function
1133
     * @param {Object} options (optional) An object containing handler configuration properties.
1134
     * This may contain any of the following properties:<ul>
1135
     * <li>scope {Object} : The scope in which to execute the handler function. The handler function's "this" context.</li>
1136
     * <li>delegate {String} : A simple selector to filter the target or look for a descendant of the target</li>
1137
     * <li>stopEvent {Boolean} : True to stop the event. That is stop propagation, and prevent the default action.</li>
1138
     * <li>preventDefault {Boolean} : True to prevent the default action</li>
1139
     * <li>stopPropagation {Boolean} : True to prevent event propagation</li>
1140
     * <li>normalized {Boolean} : False to pass a browser event to the handler function instead of an Ext.EventObject</li>
1141
     * <li>delay {Number} : The number of milliseconds to delay the invocation of the handler after te event fires.</li>
1142
     * <li>single {Boolean} : True to add a handler to handle just the next firing of the event, and then remove itself.</li>
1143
     * <li>buffer {Number} : Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
1144
     * by the specified number of milliseconds. If the event fires again within that time, the original
1145
     * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
1146
     * </ul><br>
1147
     * <p>
1148
     * <b>Combining Options</b><br>
1149
     * In the following examples, the shorthand form {@link #on} is used rather than the more verbose
1150
     * addListener.  The two are equivalent.  Using the options argument, it is possible to combine different
1151
     * types of listeners:<br>
1152
     * <br>
1153
     * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
1154
     * Code:<pre><code>
1155
el.on('click', this.onClick, this, {
1156
    single: true,
1157
    delay: 100,
1158
    stopEvent : true,
1159
    forumId: 4
1160
});</code></pre>
1161
     * <p>
1162
     * <b>Attaching multiple handlers in 1 call</b><br>
1163
      * The method also allows for a single argument to be passed which is a config object containing properties
1164
     * which specify multiple handlers.
1165
     * <p>
1166
     * Code:<pre><code>
1167
el.on({
1168
    'click' : {
1169
        fn: this.onClick,
1170
        scope: this,
1171
        delay: 100
1172
    },
1173
    'mouseover' : {
1174
        fn: this.onMouseOver,
1175
        scope: this
1176
    },
1177
    'mouseout' : {
1178
        fn: this.onMouseOut,
1179
        scope: this
1180
    }
1181
});</code></pre>
1182
     * <p>
1183
     * Or a shorthand syntax:<br>
1184
     * Code:<pre><code>
1185
el.on({
1186
    'click' : this.onClick,
1187
    'mouseover' : this.onMouseOver,
1188
    'mouseout' : this.onMouseOut,
1189
    scope: this
1190
});</code></pre>
1191
     */
1192
    addListener : function(eventName, fn, scope, options){
1193
        Ext.EventManager.on(this.dom,  eventName, fn, scope || this, options);
1194
    },
1195
 
1196
    /**
1197
     * Removes an event handler from this element.  The shorthand version {@link #un} is equivalent.  Example:
1198
     * <pre><code>
1199
el.removeListener('click', this.handlerFn);
1200
// or
1201
el.un('click', this.handlerFn);
1202
</code></pre>
1203
     * @param {String} eventName the type of event to remove
1204
     * @param {Function} fn the method the event invokes
1205
     * @return {Ext.Element} this
1206
     */
1207
    removeListener : function(eventName, fn){
1208
        Ext.EventManager.removeListener(this.dom,  eventName, fn);
1209
        return this;
1210
    },
1211
 
1212
    /**
1213
     * Removes all previous added listeners from this element
1214
     * @return {Ext.Element} this
1215
     */
1216
    removeAllListeners : function(){
1217
        E.purgeElement(this.dom);
1218
        return this;
1219
    },
1220
 
1221
    /**
1222
     * Create an event handler on this element such that when the event fires and is handled by this element,
1223
     * it will be relayed to another object (i.e., fired again as if it originated from that object instead).
1224
     * @param {String} eventName The type of event to relay
1225
     * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
1226
     * for firing the relayed event
1227
     */
1228
    relayEvent : function(eventName, observable){
1229
        this.on(eventName, function(e){
1230
            observable.fireEvent(eventName, e);
1231
        });
1232
    },
1233
 
1234
    /**
1235
     * Set the opacity of the element
1236
     * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
1237
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1238
     * @return {Ext.Element} this
1239
     */
1240
     setOpacity : function(opacity, animate){
1241
        if(!animate || !A){
1242
            var s = this.dom.style;
1243
            if(Ext.isIE){
1244
                s.zoom = 1;
1245
                s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
1246
                           (opacity == 1 ? "" : " alpha(opacity=" + opacity * 100 + ")");
1247
            }else{
1248
                s.opacity = opacity;
1249
            }
1250
        }else{
1251
            this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
1252
        }
1253
        return this;
1254
    },
1255
 
1256
    /**
1257
     * Gets the left X coordinate
1258
     * @param {Boolean} local True to get the local css position instead of page coordinate
1259
     * @return {Number}
1260
     */
1261
    getLeft : function(local){
1262
        if(!local){
1263
            return this.getX();
1264
        }else{
1265
            return parseInt(this.getStyle("left"), 10) || 0;
1266
        }
1267
    },
1268
 
1269
    /**
1270
     * Gets the right X coordinate of the element (element X position + element width)
1271
     * @param {Boolean} local True to get the local css position instead of page coordinate
1272
     * @return {Number}
1273
     */
1274
    getRight : function(local){
1275
        if(!local){
1276
            return this.getX() + this.getWidth();
1277
        }else{
1278
            return (this.getLeft(true) + this.getWidth()) || 0;
1279
        }
1280
    },
1281
 
1282
    /**
1283
     * Gets the top Y coordinate
1284
     * @param {Boolean} local True to get the local css position instead of page coordinate
1285
     * @return {Number}
1286
     */
1287
    getTop : function(local) {
1288
        if(!local){
1289
            return this.getY();
1290
        }else{
1291
            return parseInt(this.getStyle("top"), 10) || 0;
1292
        }
1293
    },
1294
 
1295
    /**
1296
     * Gets the bottom Y coordinate of the element (element Y position + element height)
1297
     * @param {Boolean} local True to get the local css position instead of page coordinate
1298
     * @return {Number}
1299
     */
1300
    getBottom : function(local){
1301
        if(!local){
1302
            return this.getY() + this.getHeight();
1303
        }else{
1304
            return (this.getTop(true) + this.getHeight()) || 0;
1305
        }
1306
    },
1307
 
1308
    /**
1309
    * Initializes positioning on this element. If a desired position is not passed, it will make the
1310
    * the element positioned relative IF it is not already positioned.
1311
    * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
1312
    * @param {Number} zIndex (optional) The zIndex to apply
1313
    * @param {Number} x (optional) Set the page X position
1314
    * @param {Number} y (optional) Set the page Y position
1315
    */
1316
    position : function(pos, zIndex, x, y){
1317
        if(!pos){
1318
           if(this.getStyle('position') == 'static'){
1319
               this.setStyle('position', 'relative');
1320
           }
1321
        }else{
1322
            this.setStyle("position", pos);
1323
        }
1324
        if(zIndex){
1325
            this.setStyle("z-index", zIndex);
1326
        }
1327
        if(x !== undefined && y !== undefined){
1328
            this.setXY([x, y]);
1329
        }else if(x !== undefined){
1330
            this.setX(x);
1331
        }else if(y !== undefined){
1332
            this.setY(y);
1333
        }
1334
    },
1335
 
1336
    /**
1337
    * Clear positioning back to the default when the document was loaded
1338
    * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
1339
    * @return {Ext.Element} this
1340
     */
1341
    clearPositioning : function(value){
1342
        value = value ||'';
1343
        this.setStyle({
1344
            "left": value,
1345
            "right": value,
1346
            "top": value,
1347
            "bottom": value,
1348
            "z-index": "",
1349
            "position" : "static"
1350
        });
1351
        return this;
1352
    },
1353
 
1354
    /**
1355
    * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1356
    * snapshot before performing an update and then restoring the element.
1357
    * @return {Object}
1358
    */
1359
    getPositioning : function(){
1360
        var l = this.getStyle("left");
1361
        var t = this.getStyle("top");
1362
        return {
1363
            "position" : this.getStyle("position"),
1364
            "left" : l,
1365
            "right" : l ? "" : this.getStyle("right"),
1366
            "top" : t,
1367
            "bottom" : t ? "" : this.getStyle("bottom"),
1368
            "z-index" : this.getStyle("z-index")
1369
        };
1370
    },
1371
 
1372
    /**
1373
     * Gets the width of the border(s) for the specified side(s)
1374
     * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1375
     * passing lr would get the border (l)eft width + the border (r)ight width.
1376
     * @return {Number} The width of the sides passed added together
1377
     */
1378
    getBorderWidth : function(side){
1379
        return this.addStyles(side, El.borders);
1380
    },
1381
 
1382
    /**
1383
     * Gets the width of the padding(s) for the specified side(s)
1384
     * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1385
     * passing lr would get the padding (l)eft + the padding (r)ight.
1386
     * @return {Number} The padding of the sides passed added together
1387
     */
1388
    getPadding : function(side){
1389
        return this.addStyles(side, El.paddings);
1390
    },
1391
 
1392
    /**
1393
    * Set positioning with an object returned by getPositioning().
1394
    * @param {Object} posCfg
1395
    * @return {Ext.Element} this
1396
     */
1397
    setPositioning : function(pc){
1398
        this.applyStyles(pc);
1399
        if(pc.right == "auto"){
1400
            this.dom.style.right = "";
1401
        }
1402
        if(pc.bottom == "auto"){
1403
            this.dom.style.bottom = "";
1404
        }
1405
        return this;
1406
    },
1407
 
1408
    // private
1409
    fixDisplay : function(){
1410
        if(this.getStyle("display") == "none"){
1411
            this.setStyle("visibility", "hidden");
1412
            this.setStyle("display", this.originalDisplay); // first try reverting to default
1413
            if(this.getStyle("display") == "none"){ // if that fails, default to block
1414
                this.setStyle("display", "block");
1415
            }
1416
        }
1417
    },
1418
 
1419
    // private
1420
	setOverflow : function(v){
1421
    	if(v=='auto' && Ext.isMac && Ext.isGecko){ // work around stupid FF 2.0/Mac scroll bar bug
1422
    		this.dom.style.overflow = 'hidden';
1423
        	(function(){this.dom.style.overflow = 'auto';}).defer(1, this);
1424
    	}else{
1425
    		this.dom.style.overflow = v;
1426
    	}
1427
	},
1428
 
1429
    /**
1430
     * Quick set left and top adding default units
1431
     * @param {String} left The left CSS property value
1432
     * @param {String} top The top CSS property value
1433
     * @return {Ext.Element} this
1434
     */
1435
     setLeftTop : function(left, top){
1436
        this.dom.style.left = this.addUnits(left);
1437
        this.dom.style.top = this.addUnits(top);
1438
        return this;
1439
    },
1440
 
1441
    /**
1442
     * Move this element relative to its current position.
1443
     * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
1444
     * @param {Number} distance How far to move the element in pixels
1445
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1446
     * @return {Ext.Element} this
1447
     */
1448
     move : function(direction, distance, animate){
1449
        var xy = this.getXY();
1450
        direction = direction.toLowerCase();
1451
        switch(direction){
1452
            case "l":
1453
            case "left":
1454
                this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
1455
                break;
1456
           case "r":
1457
           case "right":
1458
                this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
1459
                break;
1460
           case "t":
1461
           case "top":
1462
           case "up":
1463
                this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
1464
                break;
1465
           case "b":
1466
           case "bottom":
1467
           case "down":
1468
                this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
1469
                break;
1470
        }
1471
        return this;
1472
    },
1473
 
1474
    /**
1475
     *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1476
     * @return {Ext.Element} this
1477
     */
1478
    clip : function(){
1479
        if(!this.isClipped){
1480
           this.isClipped = true;
1481
           this.originalClip = {
1482
               "o": this.getStyle("overflow"),
1483
               "x": this.getStyle("overflow-x"),
1484
               "y": this.getStyle("overflow-y")
1485
           };
1486
           this.setStyle("overflow", "hidden");
1487
           this.setStyle("overflow-x", "hidden");
1488
           this.setStyle("overflow-y", "hidden");
1489
        }
1490
        return this;
1491
    },
1492
 
1493
    /**
1494
     *  Return clipping (overflow) to original clipping before clip() was called
1495
     * @return {Ext.Element} this
1496
     */
1497
    unclip : function(){
1498
        if(this.isClipped){
1499
            this.isClipped = false;
1500
            var o = this.originalClip;
1501
            if(o.o){this.setStyle("overflow", o.o);}
1502
            if(o.x){this.setStyle("overflow-x", o.x);}
1503
            if(o.y){this.setStyle("overflow-y", o.y);}
1504
        }
1505
        return this;
1506
    },
1507
 
1508
 
1509
    /**
1510
     * Gets the x,y coordinates specified by the anchor position on the element.
1511
     * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo}
1512
     * for details on supported anchor positions.
1513
     * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead
1514
     * of page coordinates
1515
     * @param {Object} size (optional) An object containing the size to use for calculating anchor position
1516
     * {width: (target width), height: (target height)} (defaults to the element's current size)
1517
     * @return {Array} [x, y] An array containing the element's x and y coordinates
1518
     */
1519
    getAnchorXY : function(anchor, local, s){
1520
        //Passing a different size is useful for pre-calculating anchors,
1521
        //especially for anchored animations that change the el size.
1522
 
1523
        var w, h, vp = false;
1524
        if(!s){
1525
            var d = this.dom;
1526
            if(d == document.body || d == document){
1527
                vp = true;
1528
                w = D.getViewWidth(); h = D.getViewHeight();
1529
            }else{
1530
                w = this.getWidth(); h = this.getHeight();
1531
            }
1532
        }else{
1533
            w = s.width;  h = s.height;
1534
        }
1535
        var x = 0, y = 0, r = Math.round;
1536
        switch((anchor || "tl").toLowerCase()){
1537
            case "c":
1538
                x = r(w*.5);
1539
                y = r(h*.5);
1540
            break;
1541
            case "t":
1542
                x = r(w*.5);
1543
                y = 0;
1544
            break;
1545
            case "l":
1546
                x = 0;
1547
                y = r(h*.5);
1548
            break;
1549
            case "r":
1550
                x = w;
1551
                y = r(h*.5);
1552
            break;
1553
            case "b":
1554
                x = r(w*.5);
1555
                y = h;
1556
            break;
1557
            case "tl":
1558
                x = 0;
1559
                y = 0;
1560
            break;
1561
            case "bl":
1562
                x = 0;
1563
                y = h;
1564
            break;
1565
            case "br":
1566
                x = w;
1567
                y = h;
1568
            break;
1569
            case "tr":
1570
                x = w;
1571
                y = 0;
1572
            break;
1573
        }
1574
        if(local === true){
1575
            return [x, y];
1576
        }
1577
        if(vp){
1578
            var sc = this.getScroll();
1579
            return [x + sc.left, y + sc.top];
1580
        }
1581
        //Add the element's offset xy
1582
        var o = this.getXY();
1583
        return [x+o[0], y+o[1]];
1584
    },
1585
 
1586
    /**
1587
     * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
1588
     * supported position values.
1589
     * @param {Mixed} element The element to align to.
1590
     * @param {String} position The position to align to.
1591
     * @param {Array} offsets (optional) Offset the positioning by [x, y]
1592
     * @return {Array} [x, y]
1593
     */
1594
    getAlignToXY : function(el, p, o){
1595
        el = Ext.get(el);
1596
        if(!el || !el.dom){
1597
            throw "Element.alignToXY with an element that doesn't exist";
1598
        }
1599
        var d = this.dom;
1600
        var c = false; //constrain to viewport
1601
        var p1 = "", p2 = "";
1602
        o = o || [0,0];
1603
 
1604
        if(!p){
1605
            p = "tl-bl";
1606
        }else if(p == "?"){
1607
            p = "tl-bl?";
1608
        }else if(p.indexOf("-") == -1){
1609
            p = "tl-" + p;
1610
        }
1611
        p = p.toLowerCase();
1612
        var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
1613
        if(!m){
1614
           throw "Element.alignTo with an invalid alignment " + p;
1615
        }
1616
        p1 = m[1]; p2 = m[2]; c = !!m[3];
1617
 
1618
        //Subtract the aligned el's internal xy from the target's offset xy
1619
        //plus custom offset to get the aligned el's new offset xy
1620
        var a1 = this.getAnchorXY(p1, true);
1621
        var a2 = el.getAnchorXY(p2, false);
1622
 
1623
        var x = a2[0] - a1[0] + o[0];
1624
        var y = a2[1] - a1[1] + o[1];
1625
 
1626
        if(c){
1627
            //constrain the aligned el to viewport if necessary
1628
            var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
1629
            // 5px of margin for ie
1630
            var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
1631
 
1632
            //If we are at a viewport boundary and the aligned el is anchored on a target border that is
1633
            //perpendicular to the vp border, allow the aligned el to slide on that border,
1634
            //otherwise swap the aligned el to the opposite border of the target.
1635
            var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
1636
           var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
1637
           var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
1638
           var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
1639
 
1640
           var doc = document;
1641
           var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
1642
           var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
1643
 
1644
           if((x+w) > dw + scrollX){
1645
                x = swapX ? r.left-w : dw+scrollX-w;
1646
            }
1647
           if(x < scrollX){
1648
               x = swapX ? r.right : scrollX;
1649
           }
1650
           if((y+h) > dh + scrollY){
1651
                y = swapY ? r.top-h : dh+scrollY-h;
1652
            }
1653
           if (y < scrollY){
1654
               y = swapY ? r.bottom : scrollY;
1655
           }
1656
        }
1657
        return [x,y];
1658
    },
1659
 
1660
    // private
1661
    getConstrainToXY : function(){
1662
        var os = {top:0, left:0, bottom:0, right: 0};
1663
 
1664
        return function(el, local, offsets, proposedXY){
1665
            el = Ext.get(el);
1666
            offsets = offsets ? Ext.applyIf(offsets, os) : os;
1667
 
1668
            var vw, vh, vx = 0, vy = 0;
1669
            if(el.dom == document.body || el.dom == document){
1670
                vw = Ext.lib.Dom.getViewWidth();
1671
                vh = Ext.lib.Dom.getViewHeight();
1672
            }else{
1673
                vw = el.dom.clientWidth;
1674
                vh = el.dom.clientHeight;
1675
                if(!local){
1676
                    var vxy = el.getXY();
1677
                    vx = vxy[0];
1678
                    vy = vxy[1];
1679
                }
1680
            }
1681
 
1682
            var s = el.getScroll();
1683
 
1684
            vx += offsets.left + s.left;
1685
            vy += offsets.top + s.top;
1686
 
1687
            vw -= offsets.right;
1688
            vh -= offsets.bottom;
1689
 
1690
            var vr = vx+vw;
1691
            var vb = vy+vh;
1692
 
1693
            var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
1694
            var x = xy[0], y = xy[1];
1695
            var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
1696
 
1697
            // only move it if it needs it
1698
            var moved = false;
1699
 
1700
            // first validate right/bottom
1701
            if((x + w) > vr){
1702
                x = vr - w;
1703
                moved = true;
1704
            }
1705
            if((y + h) > vb){
1706
                y = vb - h;
1707
                moved = true;
1708
            }
1709
            // then make sure top/left isn't negative
1710
            if(x < vx){
1711
                x = vx;
1712
                moved = true;
1713
            }
1714
            if(y < vy){
1715
                y = vy;
1716
                moved = true;
1717
            }
1718
            return moved ? [x, y] : false;
1719
        };
1720
    }(),
1721
 
1722
    // private
1723
    adjustForConstraints : function(xy, parent, offsets){
1724
        return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
1725
    },
1726
 
1727
    /**
1728
     * Aligns this element with another element relative to the specified anchor points. If the other element is the
1729
     * document it aligns it to the viewport.
1730
     * The position parameter is optional, and can be specified in any one of the following formats:
1731
     * <ul>
1732
     *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
1733
     *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
1734
     *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
1735
     *       deprecated in favor of the newer two anchor syntax below</i>.</li>
1736
     *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
1737
     *       element's anchor point, and the second value is used as the target's anchor point.</li>
1738
     * </ul>
1739
     * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
1740
     * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
1741
     * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
1742
     * that specified in order to enforce the viewport constraints.
1743
     * Following are all of the supported anchor positions:
1744
<pre>
1745
Value  Description
1746
-----  -----------------------------
1747
tl     The top left corner (default)
1748
t      The center of the top edge
1749
tr     The top right corner
1750
l      The center of the left edge
1751
c      In the center of the element
1752
r      The center of the right edge
1753
bl     The bottom left corner
1754
b      The center of the bottom edge
1755
br     The bottom right corner
1756
</pre>
1757
Example Usage:
1758
<pre><code>
1759
// align el to other-el using the default positioning ("tl-bl", non-constrained)
1760
el.alignTo("other-el");
1761
 
1762
// align the top left corner of el with the top right corner of other-el (constrained to viewport)
1763
el.alignTo("other-el", "tr?");
1764
 
1765
// align the bottom right corner of el with the center left edge of other-el
1766
el.alignTo("other-el", "br-l?");
1767
 
1768
// align the center of el with the bottom left corner of other-el and
1769
// adjust the x position by -6 pixels (and the y position by 0)
1770
el.alignTo("other-el", "c-bl", [-6, 0]);
1771
</code></pre>
1772
     * @param {Mixed} element The element to align to.
1773
     * @param {String} position The position to align to.
1774
     * @param {Array} offsets (optional) Offset the positioning by [x, y]
1775
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1776
     * @return {Ext.Element} this
1777
     */
1778
    alignTo : function(element, position, offsets, animate){
1779
        var xy = this.getAlignToXY(element, position, offsets);
1780
        this.setXY(xy, this.preanim(arguments, 3));
1781
        return this;
1782
    },
1783
 
1784
    /**
1785
     * Anchors an element to another element and realigns it when the window is resized.
1786
     * @param {Mixed} element The element to align to.
1787
     * @param {String} position The position to align to.
1788
     * @param {Array} offsets (optional) Offset the positioning by [x, y]
1789
     * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
1790
     * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
1791
     * is a number, it is used as the buffer delay (defaults to 50ms).
1792
     * @param {Function} callback The function to call after the animation finishes
1793
     * @return {Ext.Element} this
1794
     */
1795
    anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
1796
        var action = function(){
1797
            this.alignTo(el, alignment, offsets, animate);
1798
            Ext.callback(callback, this);
1799
        };
1800
        Ext.EventManager.onWindowResize(action, this);
1801
        var tm = typeof monitorScroll;
1802
        if(tm != 'undefined'){
1803
            Ext.EventManager.on(window, 'scroll', action, this,
1804
                {buffer: tm == 'number' ? monitorScroll : 50});
1805
        }
1806
        action.call(this); // align immediately
1807
        return this;
1808
    },
1809
    /**
1810
     * Clears any opacity settings from this element. Required in some cases for IE.
1811
     * @return {Ext.Element} this
1812
     */
1813
    clearOpacity : function(){
1814
        if (window.ActiveXObject) {
1815
            if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
1816
                this.dom.style.filter = "";
1817
            }
1818
        } else {
1819
            this.dom.style.opacity = "";
1820
            this.dom.style["-moz-opacity"] = "";
1821
            this.dom.style["-khtml-opacity"] = "";
1822
        }
1823
        return this;
1824
    },
1825
 
1826
    /**
1827
     * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1828
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1829
     * @return {Ext.Element} this
1830
     */
1831
    hide : function(animate){
1832
        this.setVisible(false, this.preanim(arguments, 0));
1833
        return this;
1834
    },
1835
 
1836
    /**
1837
    * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1838
    * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
1839
     * @return {Ext.Element} this
1840
     */
1841
    show : function(animate){
1842
        this.setVisible(true, this.preanim(arguments, 0));
1843
        return this;
1844
    },
1845
 
1846
    /**
1847
     * @private Test if size has a unit, otherwise appends the default
1848
     */
1849
    addUnits : function(size){
1850
        return Ext.Element.addUnits(size, this.defaultUnit);
1851
    },
1852
 
1853
    /**
1854
    * Update the innerHTML of this element, optionally searching for and processing scripts
1855
    * @param {String} html The new HTML
1856
    * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)
1857
    * @param {Function} callback (optional) For async script loading you can be notified when the update completes
1858
    * @return {Ext.Element} this
1859
     */
1860
    update : function(html, loadScripts, callback){
1861
        if(typeof html == "undefined"){
1862
            html = "";
1863
        }
1864
        if(loadScripts !== true){
1865
            this.dom.innerHTML = html;
1866
            if(typeof callback == "function"){
1867
                callback();
1868
            }
1869
            return this;
1870
        }
1871
        var id = Ext.id();
1872
        var dom = this.dom;
1873
 
1874
        html += '<span id="' + id + '"></span>';
1875
 
1876
        E.onAvailable(id, function(){
1877
            var hd = document.getElementsByTagName("head")[0];
1878
            var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
1879
            var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1880
            var typeRe = /\stype=([\'\"])(.*?)\1/i;
1881
 
1882
            var match;
1883
            while(match = re.exec(html)){
1884
                var attrs = match[1];
1885
                var srcMatch = attrs ? attrs.match(srcRe) : false;
1886
                if(srcMatch && srcMatch[2]){
1887
                   var s = document.createElement("script");
1888
                   s.src = srcMatch[2];
1889
                   var typeMatch = attrs.match(typeRe);
1890
                   if(typeMatch && typeMatch[2]){
1891
                       s.type = typeMatch[2];
1892
                   }
1893
                   hd.appendChild(s);
1894
                }else if(match[2] && match[2].length > 0){
1895
                    if(window.execScript) {
1896
                       window.execScript(match[2]);
1897
                    } else {
1898
                       window.eval(match[2]);
1899
                    }
1900
                }
1901
            }
1902
            var el = document.getElementById(id);
1903
            if(el){Ext.removeNode(el);}
1904
            if(typeof callback == "function"){
1905
                callback();
1906
            }
1907
        });
1908
        dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
1909
        return this;
1910
    },
1911
 
1912
    /**
1913
     * Direct access to the Updater {@link Ext.Updater#update} method (takes the same parameters).
1914
     * @param {String/Function} url The url for this request or a function to call to get the url
1915
     * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
1916
     * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1917
     * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
1918
     * @return {Ext.Element} this
1919
     */
1920
    load : function(){
1921
        var um = this.getUpdater();
1922
        um.update.apply(um, arguments);
1923
        return this;
1924
    },
1925
 
1926
    /**
1927
    * Gets this element's Updater
1928
    * @return {Ext.Updater} The Updater
1929
    */
1930
    getUpdater : function(){
1931
        if(!this.updateManager){
1932
            this.updateManager = new Ext.Updater(this);
1933
        }
1934
        return this.updateManager;
1935
    },
1936
 
1937
    /**
1938
     * Disables text selection for this element (normalized across browsers)
1939
     * @return {Ext.Element} this
1940
     */
1941
    unselectable : function(){
1942
        this.dom.unselectable = "on";
1943
        this.swallowEvent("selectstart", true);
1944
        this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
1945
        this.addClass("x-unselectable");
1946
        return this;
1947
    },
1948
 
1949
    /**
1950
    * Calculates the x, y to center this element on the screen
1951
    * @return {Array} The x, y values [x, y]
1952
    */
1953
    getCenterXY : function(){
1954
        return this.getAlignToXY(document, 'c-c');
1955
    },
1956
 
1957
    /**
1958
    * Centers the Element in either the viewport, or another Element.
1959
    * @param {Mixed} centerIn (optional) The element in which to center the element.
1960
    */
1961
    center : function(centerIn){
1962
        this.alignTo(centerIn || document, 'c-c');
1963
        return this;
1964
    },
1965
 
1966
    /**
1967
     * Tests various css rules/browsers to determine if this element uses a border box
1968
     * @return {Boolean}
1969
     */
1970
    isBorderBox : function(){
1971
        return noBoxAdjust[this.dom.tagName.toLowerCase()] || Ext.isBorderBox;
1972
    },
1973
 
1974
    /**
1975
     * Return a box {x, y, width, height} that can be used to set another elements
1976
     * size/location to match this element.
1977
     * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1978
     * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1979
     * @return {Object} box An object in the format {x, y, width, height}
1980
     */
1981
    getBox : function(contentBox, local){
1982
        var xy;
1983
        if(!local){
1984
            xy = this.getXY();
1985
        }else{
1986
            var left = parseInt(this.getStyle("left"), 10) || 0;
1987
            var top = parseInt(this.getStyle("top"), 10) || 0;
1988
            xy = [left, top];
1989
        }
1990
        var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
1991
        if(!contentBox){
1992
            bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
1993
        }else{
1994
            var l = this.getBorderWidth("l")+this.getPadding("l");
1995
            var r = this.getBorderWidth("r")+this.getPadding("r");
1996
            var t = this.getBorderWidth("t")+this.getPadding("t");
1997
            var b = this.getBorderWidth("b")+this.getPadding("b");
1998
            bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
1999
        }
2000
        bx.right = bx.x + bx.width;
2001
        bx.bottom = bx.y + bx.height;
2002
        return bx;
2003
    },
2004
 
2005
    /**
2006
     * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
2007
     for more information about the sides.
2008
     * @param {String} sides
2009
     * @return {Number}
2010
     */
2011
    getFrameWidth : function(sides, onlyContentBox){
2012
        return onlyContentBox && Ext.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
2013
    },
2014
 
2015
    /**
2016
     * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
2017
     * @param {Object} box The box to fill {x, y, width, height}
2018
     * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
2019
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2020
     * @return {Ext.Element} this
2021
     */
2022
    setBox : function(box, adjust, animate){
2023
        var w = box.width, h = box.height;
2024
        if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
2025
           w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
2026
           h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
2027
        }
2028
        this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
2029
        return this;
2030
    },
2031
 
2032
    /**
2033
     * Forces the browser to repaint this element
2034
     * @return {Ext.Element} this
2035
     */
2036
     repaint : function(){
2037
        var dom = this.dom;
2038
        this.addClass("x-repaint");
2039
        setTimeout(function(){
2040
            Ext.get(dom).removeClass("x-repaint");
2041
        }, 1);
2042
        return this;
2043
    },
2044
 
2045
    /**
2046
     * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
2047
     * then it returns the calculated width of the sides (see getPadding)
2048
     * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
2049
     * @return {Object/Number}
2050
     */
2051
    getMargins : function(side){
2052
        if(!side){
2053
            return {
2054
                top: parseInt(this.getStyle("margin-top"), 10) || 0,
2055
                left: parseInt(this.getStyle("margin-left"), 10) || 0,
2056
                bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
2057
                right: parseInt(this.getStyle("margin-right"), 10) || 0
2058
            };
2059
        }else{
2060
            return this.addStyles(side, El.margins);
2061
         }
2062
    },
2063
 
2064
    // private
2065
    addStyles : function(sides, styles){
2066
        var val = 0, v, w;
2067
        for(var i = 0, len = sides.length; i < len; i++){
2068
            v = this.getStyle(styles[sides.charAt(i)]);
2069
            if(v){
2070
                 w = parseInt(v, 10);
2071
                 if(w){ val += (w >= 0 ? w : -1 * w); }
2072
            }
2073
        }
2074
        return val;
2075
    },
2076
 
2077
    /**
2078
     * Creates a proxy element of this element
2079
     * @param {String/Object} config The class name of the proxy element or a DomHelper config object
2080
     * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
2081
     * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
2082
     * @return {Ext.Element} The new proxy element
2083
     */
2084
    createProxy : function(config, renderTo, matchBox){
2085
        config = typeof config == "object" ?
2086
            config : {tag : "div", cls: config};
2087
 
2088
        var proxy;
2089
        if(renderTo){
2090
            proxy = Ext.DomHelper.append(renderTo, config, true);
2091
        }else {
2092
            proxy = Ext.DomHelper.insertBefore(this.dom, config, true);
2093
        }
2094
        if(matchBox){
2095
           proxy.setBox(this.getBox());
2096
        }
2097
        return proxy;
2098
    },
2099
 
2100
    /**
2101
     * Puts a mask over this element to disable user interaction. Requires core.css.
2102
     * This method can only be applied to elements which accept child nodes.
2103
     * @param {String} msg (optional) A message to display in the mask
2104
     * @param {String} msgCls (optional) A css class to apply to the msg element
2105
     * @return {Element} The mask element
2106
     */
2107
    mask : function(msg, msgCls){
2108
        if(this.getStyle("position") == "static"){
2109
            this.setStyle("position", "relative");
2110
        }
2111
        if(this._maskMsg){
2112
            this._maskMsg.remove();
2113
        }
2114
        if(this._mask){
2115
            this._mask.remove();
2116
        }
2117
 
2118
        this._mask = Ext.DomHelper.append(this.dom, {cls:"ext-el-mask"}, true);
2119
 
2120
        this.addClass("x-masked");
2121
        this._mask.setDisplayed(true);
2122
        if(typeof msg == 'string'){
2123
            this._maskMsg = Ext.DomHelper.append(this.dom, {cls:"ext-el-mask-msg", cn:{tag:'div'}}, true);
2124
            var mm = this._maskMsg;
2125
            mm.dom.className = msgCls ? "ext-el-mask-msg " + msgCls : "ext-el-mask-msg";
2126
            mm.dom.firstChild.innerHTML = msg;
2127
            mm.setDisplayed(true);
2128
            mm.center(this);
2129
        }
2130
        if(Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
2131
            this._mask.setSize(this.dom.clientWidth, this.getHeight());
2132
        }
2133
        return this._mask;
2134
    },
2135
 
2136
    /**
2137
     * Removes a previously applied mask.
2138
     */
2139
    unmask : function(){
2140
        if(this._mask){
2141
            if(this._maskMsg){
2142
                this._maskMsg.remove();
2143
                delete this._maskMsg;
2144
            }
2145
            this._mask.remove();
2146
            delete this._mask;
2147
        }
2148
        this.removeClass("x-masked");
2149
    },
2150
 
2151
    /**
2152
     * Returns true if this element is masked
2153
     * @return {Boolean}
2154
     */
2155
    isMasked : function(){
2156
        return this._mask && this._mask.isVisible();
2157
    },
2158
 
2159
    /**
2160
     * Creates an iframe shim for this element to keep selects and other windowed objects from
2161
     * showing through.
2162
     * @return {Ext.Element} The new shim element
2163
     */
2164
    createShim : function(){
2165
        var el = document.createElement('iframe');
2166
        el.frameBorder = 'no';
2167
        el.className = 'ext-shim';
2168
        if(Ext.isIE && Ext.isSecure){
2169
            el.src = Ext.SSL_SECURE_URL;
2170
        }
2171
        var shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
2172
        shim.autoBoxAdjust = false;
2173
        return shim;
2174
    },
2175
 
2176
    /**
2177
     * Removes this element from the DOM and deletes it from the cache
2178
     */
2179
    remove : function(){
2180
        Ext.removeNode(this.dom);
2181
        delete El.cache[this.dom.id];
2182
    },
2183
 
2184
    /**
2185
     * Sets up event handlers to call the passed functions when the mouse is over this element. Automatically
2186
     * filters child element mouse events.
2187
     * @param {Function} overFn
2188
     * @param {Function} outFn
2189
     * @param {Object} scope (optional)
2190
     * @return {Ext.Element} this
2191
     */
2192
    hover : function(overFn, outFn, scope){
2193
        var preOverFn = function(e){
2194
            if(!e.within(this, true)){
2195
                overFn.apply(scope || this, arguments);
2196
            }
2197
        };
2198
        var preOutFn = function(e){
2199
            if(!e.within(this, true)){
2200
                outFn.apply(scope || this, arguments);
2201
            }
2202
        };
2203
        this.on("mouseover", preOverFn, this.dom);
2204
        this.on("mouseout", preOutFn, this.dom);
2205
        return this;
2206
    },
2207
 
2208
    /**
2209
     * Sets up event handlers to add and remove a css class when the mouse is over this element
2210
     * @param {String} className
2211
     * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
2212
     * mouseout events for children elements
2213
     * @return {Ext.Element} this
2214
     */
2215
    addClassOnOver : function(className, preventFlicker){
2216
        this.hover(
2217
            function(){
2218
                Ext.fly(this, '_internal').addClass(className);
2219
            },
2220
            function(){
2221
                Ext.fly(this, '_internal').removeClass(className);
2222
            }
2223
        );
2224
        return this;
2225
    },
2226
 
2227
    /**
2228
     * Sets up event handlers to add and remove a css class when this element has the focus
2229
     * @param {String} className
2230
     * @return {Ext.Element} this
2231
     */
2232
    addClassOnFocus : function(className){
2233
        this.on("focus", function(){
2234
            Ext.fly(this, '_internal').addClass(className);
2235
        }, this.dom);
2236
        this.on("blur", function(){
2237
            Ext.fly(this, '_internal').removeClass(className);
2238
        }, this.dom);
2239
        return this;
2240
    },
2241
    /**
2242
     * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
2243
     * @param {String} className
2244
     * @return {Ext.Element} this
2245
     */
2246
    addClassOnClick : function(className){
2247
        var dom = this.dom;
2248
        this.on("mousedown", function(){
2249
            Ext.fly(dom, '_internal').addClass(className);
2250
            var d = Ext.getDoc();
2251
            var fn = function(){
2252
                Ext.fly(dom, '_internal').removeClass(className);
2253
                d.removeListener("mouseup", fn);
2254
            };
2255
            d.on("mouseup", fn);
2256
        });
2257
        return this;
2258
    },
2259
 
2260
    /**
2261
     * Stops the specified event from bubbling and optionally prevents the default action
2262
     * @param {String} eventName
2263
     * @param {Boolean} preventDefault (optional) true to prevent the default action too
2264
     * @return {Ext.Element} this
2265
     */
2266
    swallowEvent : function(eventName, preventDefault){
2267
        var fn = function(e){
2268
            e.stopPropagation();
2269
            if(preventDefault){
2270
                e.preventDefault();
2271
            }
2272
        };
2273
        if(Ext.isArray(eventName)){
2274
            for(var i = 0, len = eventName.length; i < len; i++){
2275
                 this.on(eventName[i], fn);
2276
            }
2277
            return this;
2278
        }
2279
        this.on(eventName, fn);
2280
        return this;
2281
    },
2282
 
2283
    /**
2284
     * Gets the parent node for this element, optionally chaining up trying to match a selector
2285
     * @param {String} selector (optional) Find a parent node that matches the passed simple selector
2286
     * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2287
     * @return {Ext.Element/HTMLElement} The parent node or null
2288
	 */
2289
    parent : function(selector, returnDom){
2290
        return this.matchNode('parentNode', 'parentNode', selector, returnDom);
2291
    },
2292
 
2293
     /**
2294
     * Gets the next sibling, skipping text nodes
2295
     * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
2296
     * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2297
     * @return {Ext.Element/HTMLElement} The next sibling or null
2298
	 */
2299
    next : function(selector, returnDom){
2300
        return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
2301
    },
2302
 
2303
    /**
2304
     * Gets the previous sibling, skipping text nodes
2305
     * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
2306
     * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2307
     * @return {Ext.Element/HTMLElement} The previous sibling or null
2308
	 */
2309
    prev : function(selector, returnDom){
2310
        return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
2311
    },
2312
 
2313
 
2314
    /**
2315
     * Gets the first child, skipping text nodes
2316
     * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
2317
     * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2318
     * @return {Ext.Element/HTMLElement} The first child or null
2319
	 */
2320
    first : function(selector, returnDom){
2321
        return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
2322
    },
2323
 
2324
    /**
2325
     * Gets the last child, skipping text nodes
2326
     * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
2327
     * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
2328
     * @return {Ext.Element/HTMLElement} The last child or null
2329
	 */
2330
    last : function(selector, returnDom){
2331
        return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
2332
    },
2333
 
2334
    matchNode : function(dir, start, selector, returnDom){
2335
        var n = this.dom[start];
2336
        while(n){
2337
            if(n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))){
2338
                return !returnDom ? Ext.get(n) : n;
2339
            }
2340
            n = n[dir];
2341
        }
2342
        return null;
2343
    },
2344
 
2345
    /**
2346
     * Appends the passed element(s) to this element
2347
     * @param {String/HTMLElement/Array/Element/CompositeElement} el
2348
     * @return {Ext.Element} this
2349
     */
2350
    appendChild: function(el){
2351
        el = Ext.get(el);
2352
        el.appendTo(this);
2353
        return this;
2354
    },
2355
 
2356
    /**
2357
     * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
2358
     * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
2359
     * automatically generated with the specified attributes.
2360
     * @param {HTMLElement} insertBefore (optional) a child element of this element
2361
     * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
2362
     * @return {Ext.Element} The new child element
2363
     */
2364
    createChild: function(config, insertBefore, returnDom){
2365
        config = config || {tag:'div'};
2366
        if(insertBefore){
2367
            return Ext.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
2368
        }
2369
        return Ext.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
2370
    },
2371
 
2372
    /**
2373
     * Appends this element to the passed element
2374
     * @param {Mixed} el The new parent element
2375
     * @return {Ext.Element} this
2376
     */
2377
    appendTo: function(el){
2378
        el = Ext.getDom(el);
2379
        el.appendChild(this.dom);
2380
        return this;
2381
    },
2382
 
2383
    /**
2384
     * Inserts this element before the passed element in the DOM
2385
     * @param {Mixed} el The element before which this element will be inserted
2386
     * @return {Ext.Element} this
2387
     */
2388
    insertBefore: function(el){
2389
        el = Ext.getDom(el);
2390
        el.parentNode.insertBefore(this.dom, el);
2391
        return this;
2392
    },
2393
 
2394
    /**
2395
     * Inserts this element after the passed element in the DOM
2396
     * @param {Mixed} el The element to insert after
2397
     * @return {Ext.Element} this
2398
     */
2399
    insertAfter: function(el){
2400
        el = Ext.getDom(el);
2401
        el.parentNode.insertBefore(this.dom, el.nextSibling);
2402
        return this;
2403
    },
2404
 
2405
    /**
2406
     * Inserts (or creates) an element (or DomHelper config) as the first child of this element
2407
     * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
2408
     * @return {Ext.Element} The new child
2409
     */
2410
    insertFirst: function(el, returnDom){
2411
        el = el || {};
2412
        if(typeof el == 'object' && !el.nodeType && !el.dom){ // dh config
2413
            return this.createChild(el, this.dom.firstChild, returnDom);
2414
        }else{
2415
            el = Ext.getDom(el);
2416
            this.dom.insertBefore(el, this.dom.firstChild);
2417
            return !returnDom ? Ext.get(el) : el;
2418
        }
2419
    },
2420
 
2421
    /**
2422
     * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
2423
     * @param {Mixed/Object/Array} el The id, element to insert or a DomHelper config to create and insert *or* an array of any of those.
2424
     * @param {String} where (optional) 'before' or 'after' defaults to before
2425
     * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
2426
     * @return {Ext.Element} the inserted Element
2427
     */
2428
    insertSibling: function(el, where, returnDom){
2429
        var rt;
2430
        if(Ext.isArray(el)){
2431
            for(var i = 0, len = el.length; i < len; i++){
2432
                rt = this.insertSibling(el[i], where, returnDom);
2433
            }
2434
            return rt;
2435
        }
2436
        where = where ? where.toLowerCase() : 'before';
2437
        el = el || {};
2438
        var refNode = where == 'before' ? this.dom : this.dom.nextSibling;
2439
 
2440
        if(typeof el == 'object' && !el.nodeType && !el.dom){ // dh config
2441
            if(where == 'after' && !this.dom.nextSibling){
2442
                rt = Ext.DomHelper.append(this.dom.parentNode, el, !returnDom);
2443
            }else{
2444
                rt = Ext.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
2445
            }
2446
 
2447
        }else{
2448
            rt = this.dom.parentNode.insertBefore(Ext.getDom(el), refNode);
2449
            if(!returnDom){
2450
                rt = Ext.get(rt);
2451
            }
2452
        }
2453
        return rt;
2454
    },
2455
 
2456
    /**
2457
     * Creates and wraps this element with another element
2458
     * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
2459
     * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
2460
     * @return {HTMLElement/Element} The newly created wrapper element
2461
     */
2462
    wrap: function(config, returnDom){
2463
        if(!config){
2464
            config = {tag: "div"};
2465
        }
2466
        var newEl = Ext.DomHelper.insertBefore(this.dom, config, !returnDom);
2467
        newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
2468
        return newEl;
2469
    },
2470
 
2471
    /**
2472
     * Replaces the passed element with this element
2473
     * @param {Mixed} el The element to replace
2474
     * @return {Ext.Element} this
2475
     */
2476
    replace: function(el){
2477
        el = Ext.get(el);
2478
        this.insertBefore(el);
2479
        el.remove();
2480
        return this;
2481
    },
2482
 
2483
    /**
2484
     * Replaces this element with the passed element
2485
     * @param {Mixed/Object} el The new element or a DomHelper config of an element to create
2486
     * @return {Ext.Element} this
2487
     */
2488
    replaceWith: function(el){
2489
        if(typeof el == 'object' && !el.nodeType && !el.dom){ // dh config
2490
            el = this.insertSibling(el, 'before');
2491
        }else{
2492
            el = Ext.getDom(el);
2493
            this.dom.parentNode.insertBefore(el, this.dom);
2494
        }
2495
        El.uncache(this.id);
2496
        this.dom.parentNode.removeChild(this.dom);
2497
        this.dom = el;
2498
        this.id = Ext.id(el);
2499
        El.cache[this.id] = this;
2500
        return this;
2501
    },
2502
 
2503
    /**
2504
     * Inserts an html fragment into this element
2505
     * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
2506
     * @param {String} html The HTML fragment
2507
     * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)
2508
     * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)
2509
     */
2510
    insertHtml : function(where, html, returnEl){
2511
        var el = Ext.DomHelper.insertHtml(where, this.dom, html);
2512
        return returnEl ? Ext.get(el) : el;
2513
    },
2514
 
2515
    /**
2516
     * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2517
     * @param {Object} o The object with the attributes
2518
     * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2519
     * @return {Ext.Element} this
2520
     */
2521
    set : function(o, useSet){
2522
        var el = this.dom;
2523
        useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
2524
        for(var attr in o){
2525
            if(attr == "style" || typeof o[attr] == "function") continue;
2526
            if(attr=="cls"){
2527
                el.className = o["cls"];
2528
            }else if(o.hasOwnProperty(attr)){
2529
                if(useSet) el.setAttribute(attr, o[attr]);
2530
                else el[attr] = o[attr];
2531
            }
2532
        }
2533
        if(o.style){
2534
            Ext.DomHelper.applyStyles(el, o.style);
2535
        }
2536
        return this;
2537
    },
2538
 
2539
    /**
2540
     * Convenience method for constructing a KeyMap
2541
     * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
2542
     *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
2543
     * @param {Function} fn The function to call
2544
     * @param {Object} scope (optional) The scope of the function
2545
     * @return {Ext.KeyMap} The KeyMap created
2546
     */
2547
    addKeyListener : function(key, fn, scope){
2548
        var config;
2549
        if(typeof key != "object" || Ext.isArray(key)){
2550
            config = {
2551
                key: key,
2552
                fn: fn,
2553
                scope: scope
2554
            };
2555
        }else{
2556
            config = {
2557
                key : key.key,
2558
                shift : key.shift,
2559
                ctrl : key.ctrl,
2560
                alt : key.alt,
2561
                fn: fn,
2562
                scope: scope
2563
            };
2564
        }
2565
        return new Ext.KeyMap(this, config);
2566
    },
2567
 
2568
    /**
2569
     * Creates a KeyMap for this element
2570
     * @param {Object} config The KeyMap config. See {@link Ext.KeyMap} for more details
2571
     * @return {Ext.KeyMap} The KeyMap created
2572
     */
2573
    addKeyMap : function(config){
2574
        return new Ext.KeyMap(this, config);
2575
    },
2576
 
2577
    /**
2578
     * Returns true if this element is scrollable.
2579
     * @return {Boolean}
2580
     */
2581
     isScrollable : function(){
2582
        var dom = this.dom;
2583
        return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
2584
    },
2585
 
2586
    /**
2587
     * 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().
2588
     * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
2589
     * @param {Number} value The new scroll value
2590
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2591
     * @return {Element} this
2592
     */
2593
    scrollTo : function(side, value, animate){
2594
        var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
2595
        if(!animate || !A){
2596
            this.dom[prop] = value;
2597
        }else{
2598
            var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
2599
            this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
2600
        }
2601
        return this;
2602
    },
2603
 
2604
    /**
2605
     * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
2606
     * within this element's scrollable range.
2607
     * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
2608
     * @param {Number} distance How far to scroll the element in pixels
2609
     * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
2610
     * @return {Boolean} Returns true if a scroll was triggered or false if the element
2611
     * was scrolled as far as it could go.
2612
     */
2613
     scroll : function(direction, distance, animate){
2614
         if(!this.isScrollable()){
2615
             return;
2616
         }
2617
         var el = this.dom;
2618
         var l = el.scrollLeft, t = el.scrollTop;
2619
         var w = el.scrollWidth, h = el.scrollHeight;
2620
         var cw = el.clientWidth, ch = el.clientHeight;
2621
         direction = direction.toLowerCase();
2622
         var scrolled = false;
2623
         var a = this.preanim(arguments, 2);
2624
         switch(direction){
2625
             case "l":
2626
             case "left":
2627
                 if(w - l > cw){
2628
                     var v = Math.min(l + distance, w-cw);
2629
                     this.scrollTo("left", v, a);
2630
                     scrolled = true;
2631
                 }
2632
                 break;
2633
            case "r":
2634
            case "right":
2635
                 if(l > 0){
2636
                     var v = Math.max(l - distance, 0);
2637
                     this.scrollTo("left", v, a);
2638
                     scrolled = true;
2639
                 }
2640
                 break;
2641
            case "t":
2642
            case "top":
2643
            case "up":
2644
                 if(t > 0){
2645
                     var v = Math.max(t - distance, 0);
2646
                     this.scrollTo("top", v, a);
2647
                     scrolled = true;
2648
                 }
2649
                 break;
2650
            case "b":
2651
            case "bottom":
2652
            case "down":
2653
                 if(h - t > ch){
2654
                     var v = Math.min(t + distance, h-ch);
2655
                     this.scrollTo("top", v, a);
2656
                     scrolled = true;
2657
                 }
2658
                 break;
2659
         }
2660
         return scrolled;
2661
    },
2662
 
2663
    /**
2664
     * Translates the passed page coordinates into left/top css values for this element
2665
     * @param {Number/Array} x The page x or an array containing [x, y]
2666
     * @param {Number} y The page y
2667
     * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
2668
     */
2669
    translatePoints : function(x, y){
2670
        if(typeof x == 'object' || Ext.isArray(x)){
2671
            y = x[1]; x = x[0];
2672
        }
2673
        var p = this.getStyle('position');
2674
        var o = this.getXY();
2675
 
2676
        var l = parseInt(this.getStyle('left'), 10);
2677
        var t = parseInt(this.getStyle('top'), 10);
2678
 
2679
        if(isNaN(l)){
2680
            l = (p == "relative") ? 0 : this.dom.offsetLeft;
2681
        }
2682
        if(isNaN(t)){
2683
            t = (p == "relative") ? 0 : this.dom.offsetTop;
2684
        }
2685
 
2686
        return {left: (x - o[0] + l), top: (y - o[1] + t)};
2687
    },
2688
 
2689
    /**
2690
     * Returns the current scroll position of the element.
2691
     * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
2692
     */
2693
    getScroll : function(){
2694
        var d = this.dom, doc = document;
2695
        if(d == doc || d == doc.body){
2696
            var l, t;
2697
            if(Ext.isIE && Ext.isStrict){
2698
                l = doc.documentElement.scrollLeft || (doc.body.scrollLeft || 0);
2699
                t = doc.documentElement.scrollTop || (doc.body.scrollTop || 0);
2700
            }else{
2701
                l = window.pageXOffset || (doc.body.scrollLeft || 0);
2702
                t = window.pageYOffset || (doc.body.scrollTop || 0);
2703
            }
2704
            return {left: l, top: t};
2705
        }else{
2706
            return {left: d.scrollLeft, top: d.scrollTop};
2707
        }
2708
    },
2709
 
2710
    /**
2711
     * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
2712
     * are convert to standard 6 digit hex color.
2713
     * @param {String} attr The css attribute
2714
     * @param {String} defaultValue The default value to use when a valid color isn't found
2715
     * @param {String} prefix (optional) defaults to #. Use an empty string when working with
2716
     * color anims.
2717
     */
2718
    getColor : function(attr, defaultValue, prefix){
2719
        var v = this.getStyle(attr);
2720
        if(!v || v == "transparent" || v == "inherit") {
2721
            return defaultValue;
2722
        }
2723
        var color = typeof prefix == "undefined" ? "#" : prefix;
2724
        if(v.substr(0, 4) == "rgb("){
2725
            var rvs = v.slice(4, v.length -1).split(",");
2726
            for(var i = 0; i < 3; i++){
2727
                var h = parseInt(rvs[i]);
2728
                var s = h.toString(16);
2729
                if(h < 16){
2730
                    s = "0" + s;
2731
                }
2732
                color += s;
2733
            }
2734
        } else {
2735
            if(v.substr(0, 1) == "#"){
2736
                if(v.length == 4) {
2737
                    for(var i = 1; i < 4; i++){
2738
                        var c = v.charAt(i);
2739
                        color +=  c + c;
2740
                    }
2741
                }else if(v.length == 7){
2742
                    color += v.substr(1);
2743
                }
2744
            }
2745
        }
2746
        return(color.length > 5 ? color.toLowerCase() : defaultValue);
2747
    },
2748
 
2749
    /**
2750
     * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
2751
     * gradient background, rounded corners and a 4-way shadow.  Example usage:
2752
     * <pre><code>
2753
// Basic box wrap
2754
Ext.get("foo").boxWrap();
2755
 
2756
// You can also add a custom class and use CSS inheritance rules to customize the box look.
2757
// 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
2758
// for how to create a custom box wrap style.
2759
Ext.get("foo").boxWrap().addClass("x-box-blue");
2760
</pre></code>
2761
     * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
2762
     * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
2763
     * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
2764
     * @return {Ext.Element} this
2765
     */
2766
    boxWrap : function(cls){
2767
        cls = cls || 'x-box';
2768
        var el = Ext.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
2769
        el.child('.'+cls+'-mc').dom.appendChild(this.dom);
2770
        return el;
2771
    },
2772
 
2773
    /**
2774
     * Returns the value of a namespaced attribute from the element's underlying DOM node.
2775
     * @param {String} namespace The namespace in which to look for the attribute
2776
     * @param {String} name The attribute name
2777
     * @return {String} The attribute value
2778
     */
2779
    getAttributeNS : Ext.isIE ? function(ns, name){
2780
        var d = this.dom;
2781
        var type = typeof d[ns+":"+name];
2782
        if(type != 'undefined' && type != 'unknown'){
2783
            return d[ns+":"+name];
2784
        }
2785
        return d[name];
2786
    } : function(ns, name){
2787
        var d = this.dom;
2788
        return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
2789
    },
2790
 
2791
    getTextWidth : function(text, min, max){
2792
        return (Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width).constrain(min || 0, max || 1000000);
2793
    }
2794
};
2795
 
2796
var ep = El.prototype;
2797
 
2798
/**
2799
 * Appends an event handler (shorthand for {@link #addListener}).
2800
 * @param {String} eventName The type of event to handle
2801
 * @param {Function} fn The handler function the event invokes
2802
 * @param {Object} scope (optional) The scope (this element) of the handler function
2803
 * @param {Object} options (optional) An object containing standard {@link #addListener} options
2804
 * @member Ext.Element
2805
 * @method on
2806
 */
2807
ep.on = ep.addListener;
2808
    // backwards compat
2809
ep.mon = ep.addListener;
2810
 
2811
ep.getUpdateManager = ep.getUpdater;
2812
 
2813
/**
2814
 * Removes an event handler from this element (shorthand for {@link #removeListener}).
2815
 * @param {String} eventName the type of event to remove
2816
 * @param {Function} fn the method the event invokes
2817
 * @return {Ext.Element} this
2818
 * @member Ext.Element
2819
 * @method un
2820
 */
2821
ep.un = ep.removeListener;
2822
 
2823
/**
2824
 * true to automatically adjust width and height settings for box-model issues (default to true)
2825
 */
2826
ep.autoBoxAdjust = true;
2827
 
2828
// private
2829
El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2830
 
2831
// private
2832
El.addUnits = function(v, defaultUnit){
2833
    if(v === "" || v == "auto"){
2834
        return v;
2835
    }
2836
    if(v === undefined){
2837
        return '';
2838
    }
2839
    if(typeof v == "number" || !El.unitPattern.test(v)){
2840
        return v + (defaultUnit || 'px');
2841
    }
2842
    return v;
2843
};
2844
 
2845
// special markup used throughout Ext when box wrapping elements
2846
El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
2847
/**
2848
 * Visibility mode constant - Use visibility to hide element
2849
 * @static
2850
 * @type Number
2851
 */
2852
El.VISIBILITY = 1;
2853
/**
2854
 * Visibility mode constant - Use display to hide element
2855
 * @static
2856
 * @type Number
2857
 */
2858
El.DISPLAY = 2;
2859
 
2860
El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
2861
El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
2862
El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
2863
 
2864
 
2865
 
2866
/**
2867
 * @private
2868
 */
2869
El.cache = {};
2870
 
2871
var docEl;
2872
 
2873
/**
2874
 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
2875
 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2876
 * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
2877
 * @return {Element} The Element object (or null if no matching element was found)
2878
 * @static
2879
 */
2880
El.get = function(el){
2881
    var ex, elm, id;
2882
    if(!el){ return null; }
2883
    if(typeof el == "string"){ // element id
2884
        if(!(elm = document.getElementById(el))){
2885
            return null;
2886
        }
2887
        if(ex = El.cache[el]){
2888
            ex.dom = elm;
2889
        }else{
2890
            ex = El.cache[el] = new El(elm);
2891
        }
2892
        return ex;
2893
    }else if(el.tagName){ // dom element
2894
        if(!(id = el.id)){
2895
            id = Ext.id(el);
2896
        }
2897
        if(ex = El.cache[id]){
2898
            ex.dom = el;
2899
        }else{
2900
            ex = El.cache[id] = new El(el);
2901
        }
2902
        return ex;
2903
    }else if(el instanceof El){
2904
        if(el != docEl){
2905
            el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
2906
                                                          // catch case where it hasn't been appended
2907
            El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2908
        }
2909
        return el;
2910
    }else if(el.isComposite){
2911
        return el;
2912
    }else if(Ext.isArray(el)){
2913
        return El.select(el);
2914
    }else if(el == document){
2915
        // create a bogus element object representing the document object
2916
        if(!docEl){
2917
            var f = function(){};
2918
            f.prototype = El.prototype;
2919
            docEl = new f();
2920
            docEl.dom = document;
2921
        }
2922
        return docEl;
2923
    }
2924
    return null;
2925
};
2926
 
2927
// private
2928
El.uncache = function(el){
2929
    for(var i = 0, a = arguments, len = a.length; i < len; i++) {
2930
        if(a[i]){
2931
            delete El.cache[a[i].id || a[i]];
2932
        }
2933
    }
2934
};
2935
 
2936
// private
2937
// Garbage collection - uncache elements/purge listeners on orphaned elements
2938
// so we don't hold a reference and cause the browser to retain them
2939
El.garbageCollect = function(){
2940
    if(!Ext.enableGarbageCollector){
2941
        clearInterval(El.collectorThread);
2942
        return;
2943
    }
2944
    for(var eid in El.cache){
2945
        var el = El.cache[eid], d = el.dom;
2946
        // -------------------------------------------------------
2947
        // Determining what is garbage:
2948
        // -------------------------------------------------------
2949
        // !d
2950
        // dom node is null, definitely garbage
2951
        // -------------------------------------------------------
2952
        // !d.parentNode
2953
        // no parentNode == direct orphan, definitely garbage
2954
        // -------------------------------------------------------
2955
        // !d.offsetParent && !document.getElementById(eid)
2956
        // display none elements have no offsetParent so we will
2957
        // also try to look it up by it's id. However, check
2958
        // offsetParent first so we don't do unneeded lookups.
2959
        // This enables collection of elements that are not orphans
2960
        // directly, but somewhere up the line they have an orphan
2961
        // parent.
2962
        // -------------------------------------------------------
2963
        if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
2964
            delete El.cache[eid];
2965
            if(d && Ext.enableListenerCollection){
2966
                E.purgeElement(d);
2967
            }
2968
        }
2969
    }
2970
}
2971
El.collectorThreadId = setInterval(El.garbageCollect, 30000);
2972
 
2973
var flyFn = function(){};
2974
flyFn.prototype = El.prototype;
2975
var _cls = new flyFn();
2976
 
2977
// dom is optional
2978
El.Flyweight = function(dom){
2979
    this.dom = dom;
2980
};
2981
 
2982
El.Flyweight.prototype = _cls;
2983
El.Flyweight.prototype.isFlyweight = true;
2984
 
2985
El._flyweights = {};
2986
/**
2987
 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
2988
 * the dom node can be overwritten by other code.
2989
 * @param {String/HTMLElement} el The dom node or id
2990
 * @param {String} named (optional) Allows for creation of named reusable flyweights to
2991
 *                                  prevent conflicts (e.g. internally Ext uses "_internal")
2992
 * @static
2993
 * @return {Element} The shared Element object (or null if no matching element was found)
2994
 */
2995
El.fly = function(el, named){
2996
    named = named || '_global';
2997
    el = Ext.getDom(el);
2998
    if(!el){
2999
        return null;
3000
    }
3001
    if(!El._flyweights[named]){
3002
        El._flyweights[named] = new El.Flyweight();
3003
    }
3004
    El._flyweights[named].dom = el;
3005
    return El._flyweights[named];
3006
};
3007
 
3008
/**
3009
 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
3010
 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
3011
 * Shorthand of {@link Ext.Element#get}
3012
 * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
3013
 * @return {Element} The Element object
3014
 * @member Ext
3015
 * @method get
3016
 */
3017
Ext.get = El.get;
3018
/**
3019
 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3020
 * the dom node can be overwritten by other code.
3021
 * Shorthand of {@link Ext.Element#fly}
3022
 * @param {String/HTMLElement} el The dom node or id
3023
 * @param {String} named (optional) Allows for creation of named reusable flyweights to
3024
 *                                  prevent conflicts (e.g. internally Ext uses "_internal")
3025
 * @static
3026
 * @return {Element} The shared Element object
3027
 * @member Ext
3028
 * @method fly
3029
 */
3030
Ext.fly = El.fly;
3031
 
3032
// speedy lookup for elements never to box adjust
3033
var noBoxAdjust = Ext.isStrict ? {
3034
    select:1
3035
} : {
3036
    input:1, select:1, textarea:1
3037
};
3038
if(Ext.isIE || Ext.isGecko){
3039
    noBoxAdjust['button'] = 1;
3040
}
3041
 
3042
 
3043
Ext.EventManager.on(window, 'unload', function(){
3044
    delete El.cache;
3045
    delete El._flyweights;
3046
});
3047
})();