summaryrefslogtreecommitdiff
path: root/frontend/beta/js/YUI-extensions/Element.js
Unidiff
Diffstat (limited to 'frontend/beta/js/YUI-extensions/Element.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/beta/js/YUI-extensions/Element.js2157
1 files changed, 2157 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI-extensions/Element.js b/frontend/beta/js/YUI-extensions/Element.js
new file mode 100644
index 0000000..4019923
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/Element.js
@@ -0,0 +1,2157 @@
1/**
2 * @class YAHOO.ext.Element
3 * Wraps around a DOM element and provides convenient access to Yahoo
4 * UI library functionality (and more).<br><br>
5 * Usage:<br>
6 * <pre><code>
7 * var el = YAHOO.ext.Element.get('myElementId');
8 * // or the shorter
9 * var el = getEl('myElementId');
10 * </code></pre>
11 * Using YAHOO.ext.Element.get() instead of calling the constructor directly ensures you get the same object
12 * each call instead of constructing a new one.<br><br>
13 * For working with collections of Elements, see <a href="YAHOO.ext.CompositeElement.html">YAHOO.ext.CompositeElement</a>
14 * @requires YAHOO.util.Dom
15 * @requires YAHOO.util.Event
16 * @requires YAHOO.util.CustomEvent
17 * @requires YAHOO.util.Anim (optional) to support animation
18 * @requires YAHOO.util.Motion (optional) to support animation
19 * @requires YAHOO.util.Easing (optional) to support animation
20 * @constructor Create a new Element directly.
21 * @param {String/HTMLElement} element
22 * @param {<i>Boolean</i>} 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).
23 */
24YAHOO.ext.Element = function(element, forceNew){
25 var dom = typeof element == 'string' ?
26 document.getElementById(element) : element;
27 if(!dom){ // invalid id/element
28 return null;
29 }
30 if(!forceNew && YAHOO.ext.Element.cache[dom.id]){ // element object already exists
31 return YAHOO.ext.Element.cache[dom.id];
32 }
33 /**
34 * The DOM element
35 * @type HTMLElement
36 */
37 this.dom = dom;
38
39 /**
40 * The DOM element ID
41 * @type String
42 */
43 this.id = dom.id;
44
45 /**
46 * The element's default display mode @type String
47 */
48 this.originalDisplay = YAHOO.util.Dom.getStyle(dom, 'display') || '';
49 if(this.autoDisplayMode){
50 if(this.originalDisplay == 'none'){
51 this.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
52 }
53 }
54 if(this.originalDisplay == 'none'){
55 this.originalDisplay = '';
56 }
57}
58
59YAHOO.ext.Element.prototype = {
60 visibilityMode : 1,
61 /**
62 * The default unit to append to CSS values where a unit isn't provided (Defaults to px).
63 * @type String
64 */
65 defaultUnit : 'px',
66 /**
67 * Sets the elements visibility mode. When setVisible() is called it
68 * will use this to determine whether to set the visibility or the display property.
69 * @param visMode Element.VISIBILITY or Element.DISPLAY
70 * @return {YAHOO.ext.Element} this
71 */
72 setVisibilityMode : function(visMode){
73 this.visibilityMode = visMode;
74 return this;
75 },
76 /**
77 * Convenience method for setVisibilityMode(Element.DISPLAY)
78 * @param {String} display (optional) What to set display to when visible
79 * @return {YAHOO.ext.Element} this
80 */
81 enableDisplayMode : function(display){
82 this.setVisibilityMode(YAHOO.ext.Element.DISPLAY);
83 if(typeof display != 'undefined') this.originalDisplay = display;
84 return this;
85 },
86
87 /**
88 * Perform Yahoo UI animation on this element.
89 * @param {Object} args The YUI animation control args
90 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
91 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
92 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
93 * @param {<i>Function</i>} animType (optional) YAHOO.util.Anim subclass to use. For example: YAHOO.util.Motion
94 * @return {YAHOO.ext.Element} this
95 */
96 animate : function(args, duration, onComplete, easing, animType, stopAnims){
97 this.anim(args, duration, onComplete, easing, animType);
98 return this;
99 },
100
101 /**
102 * @private Internal animation call
103 */
104 anim : function(args, duration, onComplete, easing, animType){
105 animType = animType || YAHOO.util.Anim;
106 var anim = new animType(this.dom, args, duration || .35,
107 easing || YAHOO.util.Easing.easeBoth);
108 if(onComplete){
109 anim.onComplete.subscribe(function(){
110 if(typeof onComplete == 'function'){
111 onComplete.call(this);
112 }else if(onComplete instanceof Array){
113 for(var i = 0; i < onComplete.length; i++){
114 var fn = onComplete[i];
115 if(fn) fn.call(this);
116 }
117 }
118 }, this, true);
119 }
120 anim.animate();
121 return anim;
122 },
123
124 /**
125 * Scrolls this element into view within the passed container.
126 * @param {<i>String/HTMLElement/Element</i>} container (optional) The container element to scroll (defaults to document.body)
127 * @return {YAHOO.ext.Element} this
128 */
129 scrollIntoView : function(container){
130 var c = getEl(container || document.body, true);
131 var cp = c.getStyle('position');
132 var restorePos = false;
133 if(cp != 'relative' && cp != 'absolute'){
134 c.setStyle('position', 'relative');
135 restorePos = true;
136 }
137 var el = this.dom;
138 var childTop = parseInt(el.offsetTop, 10);
139 var childBottom = childTop + el.offsetHeight;
140 var containerTop = parseInt(c.dom.scrollTop, 10); // parseInt for safari bug
141 var containerBottom = containerTop + c.dom.clientHeight;
142 if(childTop < containerTop){
143 c.dom.scrollTop = childTop;
144 }else if(childBottom > containerBottom){
145 c.dom.scrollTop = childBottom-c.dom.clientHeight;
146 }
147 if(restorePos){
148 c.setStyle('position', cp);
149 }
150 return this;
151 },
152
153 /**
154 * Measures the elements content height and updates height to match. Note, this function uses setTimeout and
155 * the new height may not be available immediately.
156 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
157 * @param {<i>Float</i>} duration (optional) Length of the animation. (Defaults to .35 seconds)
158 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
159 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut for hiding or YAHOO.util.Easing.easeIn for showing)
160 * @return {YAHOO.ext.Element} this
161 */
162 autoHeight : function(animate, duration, onComplete, easing){
163 var oldHeight = this.getHeight();
164 this.clip();
165 this.setHeight(1); // force clipping
166 setTimeout(function(){
167 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
168 if(!animate){
169 this.setHeight(height);
170 this.unclip();
171 if(typeof onComplete == 'function'){
172 onComplete();
173 }
174 }else{
175 this.setHeight(oldHeight); // restore original height
176 this.setHeight(height, animate, duration, function(){
177 this.unclip();
178 if(typeof onComplete == 'function') onComplete();
179 }.createDelegate(this), easing);
180 }
181 }.createDelegate(this), 0);
182 return this;
183 },
184
185 contains : function(el){
186 if(!el){return false;}
187 return YAHOO.util.Dom.isAncestor(this.dom, el.dom ? el.dom : el);
188 },
189
190 /**
191 * Checks whether the element is currently visible using both visibility and display properties.
192 * @param {<i>Boolean</i>} deep True to walk the dom and see if parent elements are hidden.
193 * @return {Boolean} true if the element is currently visible
194 */
195 isVisible : function(deep) {
196 var vis = YAHOO.util.Dom.getStyle(this.dom, 'visibility') != 'hidden'
197 && YAHOO.util.Dom.getStyle(this.dom, 'display') != 'none';
198 if(!deep || !vis){
199 return vis;
200 }
201 var p = this.dom.parentNode;
202 while(p && p.tagName.toLowerCase() != 'body'){
203 if(YAHOO.util.Dom.getStyle(p, 'visibility') == 'hidden' || YAHOO.util.Dom.getStyle(p, 'display') == 'none'){
204 return false;
205 }
206 p = p.parentNode;
207 }
208 return true;
209 },
210
211 /**
212 * Selects child nodes based on the passed CSS selector (the selector should not contain an id)
213 * @param {String} selector The CSS selector
214 * @param {Boolean} unique true to create a unique YAHOO.ext.Element for each child (defaults to a shared flyweight object)
215 * @return {CompositeElement/CompositeElementLite} The composite element
216 */
217 select : function(selector, unique){
218 return YAHOO.ext.Element.select('#' + this.dom.id + ' ' + selector, unique);
219 },
220
221 /**
222 * Initializes a YAHOO.util.DD object for this element.
223 * @param {String} group The group the DD object is member of
224 * @param {Object} config The DD config object
225 * @param {Object} overrides An object containing methods to override/implement on the DD object
226 * @return {YAHOO.util.DD} The DD object
227 */
228 initDD : function(group, config, overrides){
229 var dd = new YAHOO.util.DD(YAHOO.util.Dom.generateId(this.dom), group, config);
230 return YAHOO.ext.util.Config.apply(dd, overrides);
231 },
232
233 /**
234 * Initializes a YAHOO.util.DDProxy object for this element.
235 * @param {String} group The group the DDProxy object is member of
236 * @param {Object} config The DDProxy config object
237 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
238 * @return {YAHOO.util.DDProxy} The DDProxy object
239 */
240 initDDProxy : function(group, config, overrides){
241 var dd = new YAHOO.util.DDProxy(YAHOO.util.Dom.generateId(this.dom), group, config);
242 return YAHOO.ext.util.Config.apply(dd, overrides);
243 },
244
245 /**
246 * Initializes a YAHOO.util.DDTarget object for this element.
247 * @param {String} group The group the DDTarget object is member of
248 * @param {Object} config The DDTarget config object
249 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
250 * @return {YAHOO.util.DDTarget} The DDTarget object
251 */
252 initDDTarget : function(group, config, overrides){
253 var dd = new YAHOO.util.DDTarget(YAHOO.util.Dom.generateId(this.dom), group, config);
254 return YAHOO.ext.util.Config.apply(dd, overrides);
255 },
256
257 /**
258 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
259 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
260 * @param {Boolean} visible Whether the element is visible
261 * @param {<i>Boolean</i>} animate (optional) Fade the element in or out (Default is false)
262 * @param {<i>Float</i>} duration (optional) How long the fade effect lasts. (Defaults to .35 seconds)
263 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
264 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut for hiding or YAHOO.util.Easing.easeIn for showing)
265 * @return {YAHOO.ext.Element} this
266 */
267 setVisible : function(visible, animate, duration, onComplete, easing){
268 //if(this.isVisible() == visible) return; // nothing to do
269 if(!animate || !YAHOO.util.Anim){
270 if(this.visibilityMode == YAHOO.ext.Element.DISPLAY){
271 this.setDisplayed(visible);
272 }else{
273 YAHOO.util.Dom.setStyle(this.dom, 'visibility', visible ? 'visible' : 'hidden');
274 }
275 }else{
276 // make sure they can see the transition
277 this.setOpacity(visible?0:1);
278 YAHOO.util.Dom.setStyle(this.dom, 'visibility', 'visible');
279 if(this.visibilityMode == YAHOO.ext.Element.DISPLAY){
280 this.setDisplayed(true);
281 }
282 var args = {opacity: { from: (visible?0:1), to: (visible?1:0) }};
283 var anim = new YAHOO.util.Anim(this.dom, args, duration || .35,
284 easing || (visible ? YAHOO.util.Easing.easeIn : YAHOO.util.Easing.easeOut));
285 anim.onComplete.subscribe((function(){
286 if(this.visibilityMode == YAHOO.ext.Element.DISPLAY){
287 this.setDisplayed(visible);
288 }else{
289 YAHOO.util.Dom.setStyle(this.dom, 'visibility', visible ? 'visible' : 'hidden');
290 }
291 }).createDelegate(this));
292 if(onComplete){
293 anim.onComplete.subscribe(onComplete);
294 }
295 anim.animate();
296 }
297 return this;
298 },
299
300 /**
301 * Returns true if display is not "none"
302 * @return {Boolean}
303 */
304 isDisplayed : function() {
305 return YAHOO.util.Dom.getStyle(this.dom, 'display') != 'none';
306 },
307
308 /**
309 * Toggles the elements visibility or display, depending on visibility mode.
310 * @param {<i>Boolean</i>} animate (optional) Fade the element in or out (Default is false)
311 * @param {<i>float</i>} duration (optional) How long the fade effect lasts. (Defaults to .35 seconds)
312 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
313 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut for hiding or YAHOO.util.Easing.easeIn for showing)
314 * @return {YAHOO.ext.Element} this
315 */
316 toggle : function(animate, duration, onComplete, easing){
317 this.setVisible(!this.isVisible(), animate, duration, onComplete, easing);
318 return this;
319 },
320
321 /**
322 * Sets the css display. Uses originalDisplay if value is a boolean true.
323 * @param {Boolean} value Boolean to display the element using it's default display or a string to set the display directly
324 * @return {YAHOO.ext.Element} this
325 */
326 setDisplayed : function(value) {
327 if(typeof value == 'boolean'){
328 value = value ? this.originalDisplay : 'none';
329 }
330 YAHOO.util.Dom.setStyle(this.dom, 'display', value);
331 return this;
332 },
333
334 /**
335 * Tries to focus the element. Any exceptions are caught.
336 * @return {YAHOO.ext.Element} this
337 */
338 focus : function() {
339 try{
340 this.dom.focus();
341 }catch(e){}
342 return this;
343 },
344
345 /**
346 * Tries to blur the element. Any exceptions are caught.
347 * @return {YAHOO.ext.Element} this
348 */
349 blur : function() {
350 try{
351 this.dom.blur();
352 }catch(e){}
353 return this;
354 },
355
356 /**
357 * Add a CSS class to the element.
358 * @param {String/Array} className The CSS class to add or an array of classes
359 * @return {YAHOO.ext.Element} this
360 */
361 addClass : function(className){
362 if(className instanceof Array){
363 for(var i = 0, len = className.length; i < len; i++) {
364 this.addClass(className[i]);
365 }
366 }else{
367 if(!this.hasClass(className)){
368 this.dom.className = this.dom.className + ' ' + className;
369 }
370 }
371 return this;
372 },
373
374 /**
375 * Adds the passed className to this element and removes the class from all siblings
376 * @param {String} className The className to add
377 * @return {YAHOO.ext.Element} this
378 */
379 radioClass : function(className){
380 var siblings = this.dom.parentNode.childNodes;
381 for(var i = 0; i < siblings.length; i++) {
382 var s = siblings[i];
383 if(s.nodeType == 1){
384 YAHOO.util.Dom.removeClass(s, className);
385 }
386 }
387 this.addClass(className);
388 return this;
389 },
390 /**
391 * Removes a CSS class from the element.
392 * @param {String/Array} className The CSS class to remove or an array of classes
393 * @return {YAHOO.ext.Element} this
394 */
395 removeClass : function(className){
396 if(!className){
397 return this;
398 }
399 if(className instanceof Array){
400 for(var i = 0, len = className.length; i < len; i++) {
401 this.removeClass(className[i]);
402 }
403 }else{
404 var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');
405 var c = this.dom.className;
406 if(re.test(c)){
407 this.dom.className = c.replace(re, ' ');
408 }
409 }
410 return this;
411 },
412
413 /**
414 * Toggles (adds or removes) the passed class.
415 * @param {String} className
416 * @return {YAHOO.ext.Element} this
417 */
418 toggleClass : function(className){
419 if(this.hasClass(className)){
420 this.removeClass(className);
421 }else{
422 this.addClass(className);
423 }
424 return this;
425 },
426
427 /**
428 * Checks if a CSS class is in use by the element.
429 * @param {String} className The CSS class to check
430 * @return {Boolean} true or false
431 */
432 hasClass : function(className){
433 var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
434 return re.test(this.dom.className);
435 },
436
437 /**
438 * Replaces a CSS class on the element with another.
439 * @param {String} oldClassName The CSS class to replace
440 * @param {String} newClassName The replacement CSS class
441 * @return {YAHOO.ext.Element} this
442 */
443 replaceClass : function(oldClassName, newClassName){
444 this.removeClass(oldClassName);
445 this.addClass(newClassName);
446 return this;
447 },
448
449 /**
450 * Normalizes currentStyle and ComputedStyle.
451 * @param {String} property The style property whose value is returned.
452 * @return {String} The current value of the style property for this element.
453 */
454 getStyle : function(name){
455 return YAHOO.util.Dom.getStyle(this.dom, name);
456 },
457
458 /**
459 * Wrapper for setting style properties, also takes single object parameter of multiple styles
460 * @param {String/Object} property The style property to be set or an object of multiple styles.
461 * @param {String} val (optional) The value to apply to the given property or null if an object was passed.
462 * @return {YAHOO.ext.Element} this
463 */
464 setStyle : function(name, value){
465 if(typeof name == 'string'){
466 YAHOO.util.Dom.setStyle(this.dom, name, value);
467 }else{
468 var D = YAHOO.util.Dom;
469 for(var style in name){
470 if(typeof name[style] != 'function'){
471 D.setStyle(this.dom, style, name[style]);
472 }
473 }
474 }
475 return this;
476 },
477
478 /**
479 * More flexible version of {@link #setStyle} for setting style properties.
480 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
481 * a function which returns such a specification.
482 * @return {YAHOO.ext.Element} this
483 */
484 applyStyles : function(style){
485 YAHOO.ext.DomHelper.applyStyles(this.dom, style);
486 },
487
488 /**
489 * 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).
490 @ return {Number} The X position of the element
491 */
492 getX : function(){
493 return YAHOO.util.Dom.getX(this.dom);
494 },
495
496 /**
497 * 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).
498 @ return {Number} The Y position of the element
499 */
500 getY : function(){
501 return YAHOO.util.Dom.getY(this.dom);
502 },
503
504 /**
505 * 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).
506 @ return {Array} The XY position of the element
507 */
508 getXY : function(){
509 return YAHOO.util.Dom.getXY(this.dom);
510 },
511
512 /**
513 * 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).
514 @param {Number} The X position of the element
515 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
516 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
517 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
518 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
519 * @return {YAHOO.ext.Element} this
520 */
521 setX : function(x, animate, duration, onComplete, easing){
522 if(!animate || !YAHOO.util.Anim){
523 YAHOO.util.Dom.setX(this.dom, x);
524 }else{
525 this.setXY([x, this.getY()], animate, duration, onComplete, easing);
526 }
527 return this;
528 },
529
530 /**
531 * 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).
532 @param {Number} The Y position of the element
533 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
534 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
535 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
536 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
537 * @return {YAHOO.ext.Element} this
538 */
539 setY : function(y, animate, duration, onComplete, easing){
540 if(!animate || !YAHOO.util.Anim){
541 YAHOO.util.Dom.setY(this.dom, y);
542 }else{
543 this.setXY([this.getX(), y], animate, duration, onComplete, easing);
544 }
545 return this;
546 },
547
548 /**
549 * Set the element's left position directly using CSS style (instead of setX())
550 * @param {String} left The left CSS property value
551 * @return {YAHOO.ext.Element} this
552 */
553 setLeft : function(left){
554 YAHOO.util.Dom.setStyle(this.dom, 'left', this.addUnits(left));
555 return this;
556 },
557
558 /**
559 * Set the element's top position directly using CSS style (instead of setY())
560 * @param {String} top The top CSS property value
561 * @return {YAHOO.ext.Element} this
562 */
563 setTop : function(top){
564 YAHOO.util.Dom.setStyle(this.dom, 'top', this.addUnits(top));
565 return this;
566 },
567
568 /**
569 * Set the element's css right style
570 * @param {String} right The right CSS property value
571 * @return {YAHOO.ext.Element} this
572 */
573 setRight : function(right){
574 YAHOO.util.Dom.setStyle(this.dom, 'right', this.addUnits(right));
575 return this;
576 },
577
578 /**
579 * Set the element's css bottom style
580 * @param {String} bottom The bottom CSS property value
581 * @return {YAHOO.ext.Element} this
582 */
583 setBottom : function(bottom){
584 YAHOO.util.Dom.setStyle(this.dom, 'bottom', this.addUnits(bottom));
585 return this;
586 },
587
588 /**
589 * Set the position of the element in page coordinates, regardless of how the element is positioned.
590 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
591 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
592 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
593 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
594 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
595 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
596 * @return {YAHOO.ext.Element} this
597 */
598 setXY : function(pos, animate, duration, onComplete, easing){
599 if(!animate || !YAHOO.util.Anim){
600 YAHOO.util.Dom.setXY(this.dom, pos);
601 }else{
602 this.anim({points: {to: pos}}, duration, onComplete, easing, YAHOO.util.Motion);
603 }
604 return this;
605 },
606
607 /**
608 * Set the position of the element in page coordinates, regardless of how the element is positioned.
609 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
610 * @param {Number} x X value for new position (coordinates are page-based)
611 * @param {Number} y Y value for new position (coordinates are page-based)
612 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
613 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
614 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
615 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
616 * @return {YAHOO.ext.Element} this
617 */
618 setLocation : function(x, y, animate, duration, onComplete, easing){
619 this.setXY([x, y], animate, duration, onComplete, easing);
620 return this;
621 },
622
623 /**
624 * Set the position of the element in page coordinates, regardless of how the element is positioned.
625 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
626 * @param {Number} x X value for new position (coordinates are page-based)
627 * @param {Number} y Y value for new position (coordinates are page-based)
628 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
629 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
630 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
631 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
632 * @return {YAHOO.ext.Element} this
633 */
634 moveTo : function(x, y, animate, duration, onComplete, easing){
635 //YAHOO.util.Dom.setStyle(this.dom, 'left', this.addUnits(x));
636 //YAHOO.util.Dom.setStyle(this.dom, 'top', this.addUnits(y));
637 this.setXY([x, y], animate, duration, onComplete, easing);
638 return this;
639 },
640
641 /**
642 * Returns the region of the given element.
643 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
644 * @return {Region} A YAHOO.util.Region containing "top, left, bottom, right" member data.
645 */
646 getRegion : function(){
647 return YAHOO.util.Dom.getRegion(this.dom);
648 },
649
650 /**
651 * Returns the offset height of the element
652 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
653 * @return {Number} The element's height
654 */
655 getHeight : function(contentHeight){
656 var h = this.dom.offsetHeight;
657 return contentHeight !== true ? h : h-this.getBorderWidth('tb')-this.getPadding('tb');
658 },
659
660 /**
661 * Returns the offset width of the element
662 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
663 * @return {Number} The element's width
664 */
665 getWidth : function(contentWidth){
666 var w = this.dom.offsetWidth;
667 return contentWidth !== true ? w : w-this.getBorderWidth('lr')-this.getPadding('lr');
668 },
669
670 /**
671 * Returns the size of the element
672 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
673 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
674 */
675 getSize : function(contentSize){
676 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
677 },
678
679 /** @private */
680 adjustWidth : function(width){
681 if(typeof width == 'number'){
682 if(this.autoBoxAdjust && !this.isBorderBox()){
683 width -= (this.getBorderWidth('lr') + this.getPadding('lr'));
684 }
685 if(width < 0){
686 width = 0;
687 }
688 }
689 return width;
690 },
691
692 /** @private */
693 adjustHeight : function(height){
694 if(typeof height == 'number'){
695 if(this.autoBoxAdjust && !this.isBorderBox()){
696 height -= (this.getBorderWidth('tb') + this.getPadding('tb'));
697 }
698 if(height < 0){
699 height = 0;
700 }
701 }
702 return height;
703 },
704
705 /**
706 * Set the width of the element
707 * @param {Number} width The new width
708 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
709 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
710 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
711 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut if width is larger or YAHOO.util.Easing.easeIn if it is smaller)
712 * @return {YAHOO.ext.Element} this
713 */
714 setWidth : function(width, animate, duration, onComplete, easing){
715 width = this.adjustWidth(width);
716 if(!animate || !YAHOO.util.Anim){
717 this.dom.style.width = this.addUnits(width);
718 //YAHOO.util.Dom.setStyle(this.dom, 'width', this.addUnits(width));
719 }else{
720 this.anim({width: {to: width}}, duration, onComplete,
721 easing || (width > this.getWidth() ? YAHOO.util.Easing.easeOut : YAHOO.util.Easing.easeIn));
722 }
723 return this;
724 },
725
726 /**
727 * Set the height of the element
728 * @param {Number} height The new height
729 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
730 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
731 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
732 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut if height is larger or YAHOO.util.Easing.easeIn if it is smaller)
733 * @return {YAHOO.ext.Element} this
734 */
735 setHeight : function(height, animate, duration, onComplete, easing){
736 height = this.adjustHeight(height);
737 if(!animate || !YAHOO.util.Anim){
738 this.dom.style.height = this.addUnits(height);
739 //YAHOO.util.Dom.setStyle(this.dom, 'height', this.addUnits(height));
740 }else{
741 this.anim({height: {to: height}}, duration, onComplete,
742 easing || (height > this.getHeight() ? YAHOO.util.Easing.easeOut : YAHOO.util.Easing.easeIn));
743 }
744 return this;
745 },
746
747 /**
748 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
749 * @param {Number} width The new width
750 * @param {Number} height The new height
751 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
752 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
753 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
754 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
755 * @return {YAHOO.ext.Element} this
756 */
757 setSize : function(width, height, animate, duration, onComplete, easing){
758 width = this.adjustWidth(width); height = this.adjustHeight(height);
759 if(!animate || !YAHOO.util.Anim){
760 this.dom.style.width = this.addUnits(width);
761 this.dom.style.height = this.addUnits(height);
762 }else{
763 this.anim({width: {to: width}, height: {to: height}}, duration, onComplete, easing);
764 }
765 return this;
766 },
767
768 /**
769 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
770 * @param {Number} x X value for new position (coordinates are page-based)
771 * @param {Number} y Y value for new position (coordinates are page-based)
772 * @param {Number} width The new width
773 * @param {Number} height The new height
774 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
775 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
776 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
777 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
778 * @return {YAHOO.ext.Element} this
779 */
780 setBounds : function(x, y, width, height, animate, duration, onComplete, easing){
781 if(!animate || !YAHOO.util.Anim){
782 this.setSize(width, height);
783 this.setLocation(x, y);
784 }else{
785 width = this.adjustWidth(width); height = this.adjustHeight(height);
786 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}}, duration, onComplete, easing, YAHOO.util.Motion);
787 }
788 return this;
789 },
790
791 /**
792 * 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.
793 * @param {YAHOO.util.Region} region The region to fill
794 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
795 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
796 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
797 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
798 * @return {YAHOO.ext.Element} this
799 */
800 setRegion : function(region, animate, duration, onComplete, easing){
801 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, animate, duration, onComplete, easing);
802 return this;
803 },
804
805 /**
806 * Appends an event handler to this element
807 * @param {String} eventName The type of event to listen for
808 * @param {Function} handler The method the event invokes
809 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
810 * passed as a parameter to the handler
811 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
812 * the execution scope of the listener
813 * @return {YAHOO.ext.Element} this
814 */
815 addListener : function(eventName, handler, scope, override){
816 YAHOO.util.Event.addListener(this.dom, eventName, handler, scope || this, true);
817 return this;
818 },
819 /**
820 * Appends an event handler to this element that is buffered. If the event is triggered more than once
821 * in the specified time-frame, only the last one actually fires.
822 * @param {String} eventName The type of event to listen for
823 * @param {Function} handler The method the event invokes
824 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
825 * @param {<i>Number</i>} millis (optional) The number of milliseconds to buffer (defaults to 250)
826 * @return {Function} The wrapped function that was created (can be used to remove the listener)
827 */
828 bufferedListener : function(eventName, fn, scope, millis){
829 var task = new YAHOO.ext.util.DelayedTask();
830 scope = scope || this;
831 var newFn = function(e){
832 task.delay(millis || 250, fn, scope, Array.prototype.slice.call(arguments, 0));
833 }
834 this.addListener(eventName, newFn);
835 return newFn;
836 },
837
838
839 /**
840 * Appends an event handler to this element. The difference between this function and addListener is this
841 * function prevents the default action, and if set stops propagation (bubbling) as well
842 * @param {String} eventName The type of event to listen for
843 * @param {Boolean} stopPropagation Whether to also stopPropagation (bubbling)
844 * @param {Function} handler The method the event invokes
845 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
846 * passed as a parameter to the handler
847 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
848 * the execution scope of the listener
849 * @return {YAHOO.ext.Element} this
850 */
851 addHandler : function(eventName, stopPropagation, handler, scope, override){
852 var fn = YAHOO.ext.Element.createStopHandler(stopPropagation, handler, scope || this, true);
853 YAHOO.util.Event.addListener(this.dom, eventName, fn);
854 return fn;
855 },
856
857 /**
858 * Appends an event handler to this element (Same as addListener)
859 * @param {String} eventName The type of event to listen for
860 * @param {Function} handler The method the event invokes
861 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
862 * passed as a parameter to the handler
863 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
864 * the execution scope of the listener
865 * @return {YAHOO.ext.Element} this
866 */
867 on : function(eventName, handler, scope, override){
868 YAHOO.util.Event.addListener(this.dom, eventName, handler, scope || this, true);
869 return this;
870 },
871
872 /**
873 * Append a managed listener - See {@link YAHOO.ext.EventObject} for more details. Use mon() for a shorter version.
874 * @param {String} eventName The type of event to listen for
875 * @param {Function} fn The method the event invokes
876 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
877 * passed as a parameter to the handler
878 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
879 * the execution scope of the listener
880 * @return {Function} The EventManager wrapped function that can be used to remove the listener
881 */
882 addManagedListener : function(eventName, fn, scope, override){
883 return YAHOO.ext.EventManager.on(this.dom, eventName, fn, scope || this, true);
884 },
885
886 /**
887 * Append a managed listener (shorthanded for {@link #addManagedListener})
888 * @param {String} eventName The type of event to listen for
889 * @param {Function} fn The method the event invokes
890 * @param {<i>Object</i>} scope (optional) An arbitrary object that will be
891 * passed as a parameter to the handler
892 * @param {<i>boolean</i>} override (optional) If true, the obj passed in becomes
893 * the execution scope of the listener
894 * @return {Function} The EventManager wrapped function that can be used to remove the listener
895 */
896 mon : function(eventName, fn, scope, override){
897 return YAHOO.ext.EventManager.on(this.dom, eventName, fn, scope || this, true);
898 },
899 /**
900 * Removes an event handler from this element
901 * @param {String} sType the type of event to remove
902 * @param {Function} fn the method the event invokes
903 * @param {Object} scope
904 * @return {YAHOO.ext.Element} this
905 */
906 removeListener : function(eventName, handler, scope){
907 YAHOO.util.Event.removeListener(this.dom, eventName, handler);
908 return this;
909 },
910
911 /**
912 * Removes all previous added listeners from this element
913 * @return {YAHOO.ext.Element} this
914 */
915 removeAllListeners : function(){
916 YAHOO.util.Event.purgeElement(this.dom);
917 return this;
918 },
919
920
921 /**
922 * Set the opacity of the element
923 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
924 * @param {<i>Boolean</i>} animate (optional) Animate (fade) the transition (Default is false)
925 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
926 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
927 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeOut if height is larger or YAHOO.util.Easing.easeIn if it is smaller)
928 * @return {YAHOO.ext.Element} this
929 */
930 setOpacity : function(opacity, animate, duration, onComplete, easing){
931 if(!animate || !YAHOO.util.Anim){
932 YAHOO.util.Dom.setStyle(this.dom, 'opacity', opacity);
933 }else{
934 this.anim({opacity: {to: opacity}}, duration, onComplete, easing);
935 }
936 return this;
937 },
938
939 /**
940 * Gets the left X coordinate
941 * @param {Boolean} local True to get the local css position instead of page coordinate
942 * @return {Number}
943 */
944 getLeft : function(local){
945 if(!local){
946 return this.getX();
947 }else{
948 return parseInt(this.getStyle('left'), 10) || 0;
949 }
950 },
951
952 /**
953 * Gets the right X coordinate of the element (element X position + element width)
954 * @param {Boolean} local True to get the local css position instead of page coordinate
955 * @return {Number}
956 */
957 getRight : function(local){
958 if(!local){
959 return this.getX() + this.getWidth();
960 }else{
961 return (this.getLeft(true) + this.getWidth()) || 0;
962 }
963 },
964
965 /**
966 * Gets the top Y coordinate
967 * @param {Boolean} local True to get the local css position instead of page coordinate
968 * @return {Number}
969 */
970 getTop : function(local) {
971 if(!local){
972 return this.getY();
973 }else{
974 return parseInt(this.getStyle('top'), 10) || 0;
975 }
976 },
977
978 /**
979 * Gets the bottom Y coordinate of the element (element Y position + element height)
980 * @param {Boolean} local True to get the local css position instead of page coordinate
981 * @return {Number}
982 */
983 getBottom : function(local){
984 if(!local){
985 return this.getY() + this.getHeight();
986 }else{
987 return (this.getTop(true) + this.getHeight()) || 0;
988 }
989 },
990
991 /**
992 * Set the element as absolute positioned with the specified z-index
993 * @param {<i>Number</i>} zIndex (optional)
994 * @return {YAHOO.ext.Element} this
995 */
996 setAbsolutePositioned : function(zIndex){
997 this.setStyle('position', 'absolute');
998 if(zIndex){
999 this.setStyle('z-index', zIndex);
1000 }
1001 return this;
1002 },
1003
1004 /**
1005 * Set the element as relative positioned with the specified z-index
1006 * @param {<i>Number</i>} zIndex (optional)
1007 * @return {YAHOO.ext.Element} this
1008 */
1009 setRelativePositioned : function(zIndex){
1010 this.setStyle('position', 'relative');
1011 if(zIndex){
1012 this.setStyle('z-index', zIndex);
1013 }
1014 return this;
1015 },
1016
1017 /**
1018 * Clear positioning back to the default when the document was loaded
1019 * @return {YAHOO.ext.Element} this
1020 */
1021 clearPositioning : function(){
1022 this.setStyle('position', '');
1023 this.setStyle('left', '');
1024 this.setStyle('right', '');
1025 this.setStyle('top', '');
1026 this.setStyle('bottom', '');
1027 return this;
1028 },
1029
1030 /**
1031 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
1032 * snapshot before performing an update and then restoring the element.
1033 * @return {Object}
1034 */
1035 getPositioning : function(){
1036 return {
1037 'position' : this.getStyle('position'),
1038 'left' : this.getStyle('left'),
1039 'right' : this.getStyle('right'),
1040 'top' : this.getStyle('top'),
1041 'bottom' : this.getStyle('bottom')
1042 };
1043 },
1044
1045 /**
1046 * Gets the width of the border(s) for the specified side(s)
1047 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1048 * passing lr would get the border (l)eft width + the border (r)ight width.
1049 * @return {Number} The width of the sides passed added together
1050 */
1051 getBorderWidth : function(side){
1052 return this.addStyles(side, YAHOO.ext.Element.borders);
1053 },
1054
1055 /**
1056 * Gets the width of the padding(s) for the specified side(s)
1057 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
1058 * passing lr would get the padding (l)eft + the padding (r)ight.
1059 * @return {Number} The padding of the sides passed added together
1060 */
1061 getPadding : function(side){
1062 return this.addStyles(side, YAHOO.ext.Element.paddings);
1063 },
1064
1065 /**
1066 * Set positioning with an object returned by getPositioning().
1067 * @param {Object} posCfg
1068 * @return {YAHOO.ext.Element} this
1069 */
1070 setPositioning : function(positionCfg){
1071 if(positionCfg.position)this.setStyle('position', positionCfg.position);
1072 if(positionCfg.left)this.setLeft(positionCfg.left);
1073 if(positionCfg.right)this.setRight(positionCfg.right);
1074 if(positionCfg.top)this.setTop(positionCfg.top);
1075 if(positionCfg.bottom)this.setBottom(positionCfg.bottom);
1076 return this;
1077 },
1078
1079
1080 /**
1081 * Quick set left and top adding default units
1082 * @return {YAHOO.ext.Element} this
1083 */
1084 setLeftTop : function(left, top){
1085 this.dom.style.left = this.addUnits(left);
1086 this.dom.style.top = this.addUnits(top);
1087 return this;
1088 },
1089
1090 /**
1091 * Move this element relative to it's current position.
1092 * @param {String} direction Possible values are: 'l','left' - 'r','right' - 't','top','up' - 'b','bottom','down'.
1093 * @param {Number} distance How far to move the element in pixels
1094 * @param {<i>Boolean</i>} animate (optional) Animate the movement (Default is false)
1095 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1096 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1097 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use.
1098 * @return {YAHOO.ext.Element} this
1099 */
1100 move : function(direction, distance, animate, duration, onComplete, easing){
1101 var xy = this.getXY();
1102 direction = direction.toLowerCase();
1103 switch(direction){
1104 case 'l':
1105 case 'left':
1106 this.moveTo(xy[0]-distance, xy[1], animate, duration, onComplete, easing);
1107 break;
1108 case 'r':
1109 case 'right':
1110 this.moveTo(xy[0]+distance, xy[1], animate, duration, onComplete, easing);
1111 break;
1112 case 't':
1113 case 'top':
1114 case 'up':
1115 this.moveTo(xy[0], xy[1]-distance, animate, duration, onComplete, easing);
1116 break;
1117 case 'b':
1118 case 'bottom':
1119 case 'down':
1120 this.moveTo(xy[0], xy[1]+distance, animate, duration, onComplete, easing);
1121 break;
1122 }
1123 return this;
1124 },
1125
1126 /**
1127 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
1128 * @return {YAHOO.ext.Element} this
1129 */
1130 clip : function(){
1131 if(!this.isClipped){
1132 this.isClipped = true;
1133 this.originalClip = {
1134 'o': this.getStyle('overflow'),
1135 'x': this.getStyle('overflow-x'),
1136 'y': this.getStyle('overflow-y')
1137 };
1138 this.setStyle('overflow', 'hidden');
1139 this.setStyle('overflow-x', 'hidden');
1140 this.setStyle('overflow-y', 'hidden');
1141 }
1142 return this;
1143 },
1144
1145 /**
1146 * Return clipping (overflow) to original clipping before clip() was called
1147 * @return {YAHOO.ext.Element} this
1148 */
1149 unclip : function(){
1150 if(this.isClipped){
1151 this.isClipped = false;
1152 var o = this.originalClip;
1153 if(o.o){this.setStyle('overflow', o.o);}
1154 if(o.x){this.setStyle('overflow-x', o.x);}
1155 if(o.y){this.setStyle('overflow-y', o.y);}
1156 }
1157 return this;
1158 },
1159
1160 /**
1161 * Align this element with another element.
1162 * @param {String/HTMLElement/YAHOO.ext.Element} element The element to align to.
1163 * @param {String} position The position to align to. Possible values are 'tl' - top left, 'tr' - top right, 'bl' - bottom left, and 'br' - bottom right.
1164 * @param {<i>Array</i>} offsets (optional) Offset the positioning by [x, y]
1165 * @param {<i>Boolean</i>} animate (optional) Animate the movement (Default is false)
1166 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1167 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1168 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use.
1169 * @return {YAHOO.ext.Element} this
1170 */
1171 alignTo : function(element, position, offsets, animate, duration, onComplete, easing){
1172 var otherEl = getEl(element);
1173 if(!otherEl){
1174 return this; // must not exist
1175 }
1176 offsets = offsets || [0, 0];
1177 var r = otherEl.getRegion();
1178 position = position.toLowerCase();
1179 switch(position){
1180 case 'bl':
1181 this.moveTo(r.left + offsets[0], r.bottom + offsets[1],
1182 animate, duration, onComplete, easing);
1183 break;
1184 case 'br':
1185 this.moveTo(r.right + offsets[0], r.bottom + offsets[1],
1186 animate, duration, onComplete, easing);
1187 break;
1188 case 'tl':
1189 this.moveTo(r.left + offsets[0], r.top + offsets[1],
1190 animate, duration, onComplete, easing);
1191 break;
1192 case 'tr':
1193 this.moveTo(r.right + offsets[0], r.top + offsets[1],
1194 animate, duration, onComplete, easing);
1195 break;
1196 }
1197 return this;
1198 },
1199
1200 /**
1201 * Clears any opacity settings from this element. Required in some cases for IE.
1202 * @return {YAHOO.ext.Element} this
1203 */
1204 clearOpacity : function(){
1205 if (window.ActiveXObject) {
1206 this.dom.style.filter = '';
1207 } else {
1208 this.dom.style.opacity = '';
1209 this.dom.style['-moz-opacity'] = '';
1210 this.dom.style['-khtml-opacity'] = '';
1211 }
1212 return this;
1213 },
1214
1215 /**
1216 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1217 * @param {<i>Boolean</i>} animate (optional) Animate (fade) the transition (Default is false)
1218 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1219 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1220 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
1221 * @return {YAHOO.ext.Element} this
1222 */
1223 hide : function(animate, duration, onComplete, easing){
1224 this.setVisible(false, animate, duration, onComplete, easing);
1225 return this;
1226 },
1227
1228 /**
1229 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
1230 * @param {<i>Boolean</i>} animate (optional) Animate (fade in) the transition (Default is false)
1231 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1232 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1233 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
1234 * @return {YAHOO.ext.Element} this
1235 */
1236 show : function(animate, duration, onComplete, easing){
1237 this.setVisible(true, animate, duration, onComplete, easing);
1238 return this;
1239 },
1240
1241 /**
1242 * @private Test if size has a unit, otherwise appends the default
1243 */
1244 addUnits : function(size){
1245 if(size === '' || size == 'auto' || typeof size == 'undefined'){
1246 return size;
1247 }
1248 if(typeof size == 'number' || !YAHOO.ext.Element.unitPattern.test(size)){
1249 return size + this.defaultUnit;
1250 }
1251 return size;
1252 },
1253
1254 /**
1255 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
1256 * @return {YAHOO.ext.Element} this
1257 */
1258 beginMeasure : function(){
1259 var el = this.dom;
1260 if(el.offsetWidth || el.offsetHeight){
1261 return this; // offsets work already
1262 }
1263 var changed = [];
1264 var p = this.dom; // start with this element
1265 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p.tagName.toLowerCase() != 'body'){
1266 if(YAHOO.util.Dom.getStyle(p, 'display') == 'none'){
1267 changed.push({el: p, visibility: YAHOO.util.Dom.getStyle(p, 'visibility')});
1268 p.style.visibility = 'hidden';
1269 p.style.display = 'block';
1270 }
1271 p = p.parentNode;
1272 }
1273 this._measureChanged = changed;
1274 return this;
1275
1276 },
1277
1278 /**
1279 * Restores displays to before beginMeasure was called
1280 * @return {YAHOO.ext.Element} this
1281 */
1282 endMeasure : function(){
1283 var changed = this._measureChanged;
1284 if(changed){
1285 for(var i = 0, len = changed.length; i < len; i++) {
1286 var r = changed[i];
1287 r.el.style.visibility = r.visibility;
1288 r.el.style.display = 'none';
1289 }
1290 this._measureChanged = null;
1291 }
1292 return this;
1293 },
1294
1295 /**
1296 * Update the innerHTML of this element, optionally searching for and processing scripts
1297 * @param {String} html The new HTML
1298 * @param {<i>Boolean</i>} loadScripts (optional) true to look for and process scripts
1299 * @param {Function} callback For async script loading you can be noticed when the update completes
1300 * @return {YAHOO.ext.Element} this
1301 */
1302 update : function(html, loadScripts, callback){
1303 if(typeof html == 'undefined'){
1304 html = '';
1305 }
1306 if(loadScripts !== true){
1307 this.dom.innerHTML = html;
1308 if(typeof callback == 'function'){
1309 callback();
1310 }
1311 return this;
1312 }
1313 var id = YAHOO.util.Dom.generateId();
1314 var dom = this.dom;
1315
1316 html += '<span id="' + id + '"></span>';
1317
1318 YAHOO.util.Event.onAvailable(id, function(){
1319 var hd = document.getElementsByTagName("head")[0];
1320 var re = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/img;
1321 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
1322 var match;
1323 while(match = re.exec(html)){
1324 var srcMatch = match[0].match(srcRe);
1325 if(srcMatch && srcMatch[2]){
1326 var s = document.createElement("script");
1327 s.src = srcMatch[2];
1328 hd.appendChild(s);
1329 }else if(match[1] && match[1].length > 0){
1330 eval(match[1]);
1331 }
1332 }
1333 var el = document.getElementById(id);
1334 if(el){el.parentNode.removeChild(el);}
1335 if(typeof callback == 'function'){
1336 callback();
1337 }
1338 });
1339 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/img, '');
1340 return this;
1341 },
1342
1343 /**
1344 * Direct access to the UpdateManager update() method (takes the same parameters).
1345 * @param {String/Function} url The url for this request or a function to call to get the url
1346 * @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
1347 * @param {<i>Function</i>} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
1348 * @param {<i>Boolean</i>} 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.
1349 * @return {YAHOO.ext.Element} this
1350 */
1351 load : function(){
1352 var um = this.getUpdateManager();
1353 um.update.apply(um, arguments);
1354 return this;
1355 },
1356
1357 /**
1358 * Gets this elements UpdateManager
1359 * @return {YAHOO.ext.UpdateManager} The UpdateManager
1360 */
1361 getUpdateManager : function(){
1362 if(!this.updateManager){
1363 this.updateManager = new YAHOO.ext.UpdateManager(this);
1364 }
1365 return this.updateManager;
1366 },
1367
1368 /**
1369 * Disables text selection for this element (normalized across browsers)
1370 * @return {YAHOO.ext.Element} this
1371 */
1372 unselectable : function(){
1373 this.dom.unselectable = 'on';
1374 this.swallowEvent('selectstart', true);
1375 this.applyStyles('-moz-user-select:none;-khtml-user-select:none;');
1376 return this;
1377 },
1378
1379 /**
1380 * Calculates the x, y to center this element on the screen
1381 * @param {Boolean} offsetScroll True to offset the documents current scroll position
1382 * @return {Array} The x, y values [x, y]
1383 */
1384 getCenterXY : function(offsetScroll){
1385 var centerX = Math.round((YAHOO.util.Dom.getViewportWidth()-this.getWidth())/2);
1386 var centerY = Math.round((YAHOO.util.Dom.getViewportHeight()-this.getHeight())/2);
1387 if(!offsetScroll){
1388 return [centerX, centerY];
1389 }else{
1390 var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft || 0;
1391 var scrollY = document.documentElement.scrollTop || document.body.scrollTop || 0;
1392 return[centerX + scrollX, centerY + scrollY];
1393 }
1394 },
1395
1396 /**
1397 * Centers the Element in either the viewport, or another Element.
1398 * @param {String/HTMLElement/YAHOO.ext.Element} centerIn (optional) The element in which to center the element.
1399 */
1400 center : function(centerIn) {
1401 if(!centerIn){
1402 this.setXY(this.getCenterXY(true));
1403 }else{
1404 var box = YAHOO.ext.Element.get(centerIn).getBox();
1405 this.setXY([box.x + (box.width / 2) - (this.getWidth() / 2),
1406 box.y + (box.height / 2) - (this.getHeight() / 2)]);
1407 }
1408 return this;
1409 },
1410
1411 /**
1412 * Gets an array of child YAHOO.ext.Element objects by tag name
1413 * @param {String} tagName
1414 * @return {Array} The children
1415 */
1416 getChildrenByTagName : function(tagName){
1417 var children = this.dom.getElementsByTagName(tagName);
1418 var len = children.length;
1419 var ce = new Array(len);
1420 for(var i = 0; i < len; ++i){
1421 ce[i] = YAHOO.ext.Element.get(children[i], true);
1422 }
1423 return ce;
1424 },
1425
1426 /**
1427 * Gets an array of child YAHOO.ext.Element objects by class name and optional tagName
1428 * @param {String} className
1429 * @param {<i>String</i>} tagName (optional)
1430 * @return {Array} The children
1431 */
1432 getChildrenByClassName : function(className, tagName){
1433 var children = YAHOO.util.Dom.getElementsByClassName(className, tagName, this.dom);
1434 var len = children.length;
1435 var ce = new Array(len);
1436 for(var i = 0; i < len; ++i){
1437 ce[i] = YAHOO.ext.Element.get(children[i], true);
1438 }
1439 return ce;
1440 },
1441
1442 /**
1443 * Tests various css rules/browsers to determine if this element uses a border box
1444 * @return {Boolean}
1445 */
1446 isBorderBox : function(){
1447 if(typeof this.bbox == 'undefined'){
1448 var el = this.dom;
1449 var b = YAHOO.ext.util.Browser;
1450 var strict = YAHOO.ext.Strict;
1451 this.bbox = ((b.isIE && !strict && el.style.boxSizing != 'content-box') ||
1452 (b.isGecko && YAHOO.util.Dom.getStyle(el, "-moz-box-sizing") == 'border-box') ||
1453 (!b.isSafari && YAHOO.util.Dom.getStyle(el, "box-sizing") == 'border-box'));
1454 }
1455 return this.bbox;
1456 },
1457
1458 /**
1459 * Return a box {x, y, width, height} that can be used to set another elements
1460 * size/location to match this element.
1461 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
1462 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
1463 * @return {Object}
1464 */
1465 getBox : function(contentBox, local){
1466 var xy;
1467 if(!local){
1468 xy = this.getXY();
1469 }else{
1470 var left = parseInt(YAHOO.util.Dom.getStyle('left'), 10) || 0;
1471 var top = parseInt(YAHOO.util.Dom.getStyle('top'), 10) || 0;
1472 xy = [left, top];
1473 }
1474 var el = this.dom;
1475 var w = el.offsetWidth;
1476 var h = el.offsetHeight;
1477 if(!contentBox){
1478 return {x: xy[0], y: xy[1], width: w, height: h};
1479 }else{
1480 var l = this.getBorderWidth('l')+this.getPadding('l');
1481 var r = this.getBorderWidth('r')+this.getPadding('r');
1482 var t = this.getBorderWidth('t')+this.getPadding('t');
1483 var b = this.getBorderWidth('b')+this.getPadding('b');
1484 return {x: xy[0]+l, y: xy[1]+t, width: w-(l+r), height: h-(t+b)};
1485 }
1486 },
1487
1488 /**
1489 * 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.
1490 * @param {Object} box The box to fill {x, y, width, height}
1491 * @param {<i>Boolean</i>} adjust (optional) Whether to adjust for box-model issues automatically
1492 * @param {<i>Boolean</i>} animate (optional) Animate the transition (Default is false)
1493 * @param {<i>float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1494 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1495 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use. (Defaults to YAHOO.util.Easing.easeBoth)
1496 * @return {YAHOO.ext.Element} this
1497 */
1498 setBox : function(box, adjust, animate, duration, onComplete, easing){
1499 var w = box.width, h = box.height;
1500 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
1501 w -= (this.getBorderWidth('lr') + this.getPadding('lr'));
1502 h -= (this.getBorderWidth('tb') + this.getPadding('tb'));
1503 }
1504 this.setBounds(box.x, box.y, w, h, animate, duration, onComplete, easing);
1505 return this;
1506 },
1507
1508 /**
1509 * Forces the browser to repaint this element
1510 * @return {YAHOO.ext.Element} this
1511 */
1512 repaint : function(){
1513 var dom = this.dom;
1514 YAHOO.util.Dom.addClass(dom, 'yui-ext-repaint');
1515 setTimeout(function(){
1516 YAHOO.util.Dom.removeClass(dom, 'yui-ext-repaint');
1517 }, 1);
1518 return this;
1519 },
1520
1521 /**
1522 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
1523 * then it returns the calculated width of the sides (see getPadding)
1524 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
1525 * @return {Object/Number}
1526 */
1527 getMargins : function(side){
1528 if(!side){
1529 return {
1530 top: parseInt(this.getStyle('margin-top'), 10) || 0,
1531 left: parseInt(this.getStyle('margin-left'), 10) || 0,
1532 bottom: parseInt(this.getStyle('margin-bottom'), 10) || 0,
1533 right: parseInt(this.getStyle('margin-right'), 10) || 0
1534 };
1535 }else{
1536 return this.addStyles(side, YAHOO.ext.Element.margins);
1537 }
1538 },
1539
1540 addStyles : function(sides, styles){
1541 var val = 0;
1542 for(var i = 0, len = sides.length; i < len; i++){
1543 var w = parseInt(this.getStyle(styles[sides.charAt(i)]), 10);
1544 if(!isNaN(w)) val += w;
1545 }
1546 return val;
1547 },
1548
1549 /**
1550 * Creates a proxy element of this element
1551 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
1552 * @param {<i>String/HTMLElement</i>} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
1553 * @param {<i>Boolean</i>} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
1554 * @return {YAHOO.ext.Element} The new proxy element
1555 */
1556 createProxy : function(config, renderTo, matchBox){
1557 if(renderTo){
1558 renderTo = YAHOO.util.Dom.get(renderTo);
1559 }else{
1560 renderTo = document.body;
1561 }
1562 config = typeof config == 'object' ?
1563 config : {tag : 'div', cls: config};
1564 var proxy = YAHOO.ext.DomHelper.append(renderTo, config, true);
1565 if(matchBox){
1566 proxy.setBox(this.getBox());
1567 }
1568 return proxy;
1569 },
1570
1571 /**
1572 * Puts a mask over this element to disable user interaction. Requires core.css.
1573 * This method can only be applied to elements which accept child nodes.
1574 * @return {Element} The message element
1575 */
1576 mask : function(){
1577 if(this.getStyle('position') == 'static'){
1578 this.setStyle('position', 'relative');
1579 }
1580 if(!this._mask){
1581 this._mask = YAHOO.ext.DomHelper.append(this.dom, {tag:'div', cls:'ext-el-mask'}, true);
1582 }
1583 this.addClass('ext-masked');
1584 this._mask.setDisplayed(true);
1585 return this._mask;
1586 },
1587
1588 /**
1589 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
1590 * it is cached for reuse.
1591 */
1592 unmask : function(removeEl){
1593 if(this._mask){
1594 removeEl === true ?
1595 this._mask.remove() : this._mask.setDisplayed(false);
1596 }
1597 this.removeClass('ext-masked');
1598 },
1599
1600 /**
1601 * Creates an iframe shim for this element to keep selects and other windowed objects from
1602 * showing through.
1603 * @return {YAHOO.ext.Element} The new shim element
1604 */
1605 createShim : function(){
1606 var config = {
1607 tag : 'iframe',
1608 frameBorder:'no',
1609 cls: 'yiframe-shim',
1610 style: 'position:absolute;visibility:hidden;left:0;top:0;overflow:hidden;',
1611 src: YAHOO.ext.SSL_SECURE_URL
1612 };
1613 var shim = YAHOO.ext.DomHelper.insertBefore(this.dom, config, true);
1614 shim.setOpacity(.01);
1615 shim.setBox(this.getBox());
1616 return shim;
1617 },
1618
1619 /**
1620 * Removes this element from the DOM and deletes it from the cache
1621 */
1622 remove : function(){
1623 this.dom.parentNode.removeChild(this.dom);
1624 delete YAHOO.ext.Element.cache[this.dom.id];
1625 },
1626
1627 /**
1628 * Sets up event handlers to add and remove a css class when the mouse is over this element
1629 * @param {String} className
1630 * @return {YAHOO.ext.Element} this
1631 */
1632 addClassOnOver : function(className){
1633 this.on('mouseover', function(){
1634 this.addClass(className);
1635 }, this, true);
1636 this.on('mouseout', function(){
1637 this.removeClass(className);
1638 }, this, true);
1639 return this;
1640 },
1641
1642 /**
1643 * Stops the specified event from bubbling and optionally prevent's the default action
1644 * @param {String} eventName
1645 * @param {Boolean} preventDefault (optional) true to prevent the default action too
1646 * @return {YAHOO.ext.Element} this
1647 */
1648 swallowEvent : function(eventName, preventDefault){
1649 var fn = function(e){
1650 e.stopPropagation();
1651 if(preventDefault){
1652 e.preventDefault();
1653 }
1654 };
1655 this.mon(eventName, fn);
1656 return this;
1657 },
1658
1659 /**
1660 * Sizes this element to it's parent element's dimensions performing
1661 * neccessary box adjustments.
1662 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
1663 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
1664 * @return {YAHOO.ext.Element} this
1665 */
1666 fitToParent : function(monitorResize, targetParent){
1667 var p = getEl(targetParent || this.dom.parentNode);
1668 p.beginMeasure(); // in case parent is display:none
1669 var box = p.getBox(true, true);
1670 p.endMeasure();
1671 this.setSize(box.width, box.height);
1672 if(monitorResize === true){
1673 YAHOO.ext.EventManager.onWindowResize(this.fitToParent, this, true);
1674 }
1675 return this;
1676 },
1677
1678 /**
1679 * Gets the next sibling, skipping text nodes
1680 * @return {HTMLElement} The next sibling or null
1681 */
1682 getNextSibling : function(){
1683 var n = this.dom.nextSibling;
1684 while(n && n.nodeType != 1){
1685 n = n.nextSibling;
1686 }
1687 return n;
1688 },
1689
1690 /**
1691 * Gets the previous sibling, skipping text nodes
1692 * @return {HTMLElement} The previous sibling or null
1693 */
1694 getPrevSibling : function(){
1695 var n = this.dom.previousSibling;
1696 while(n && n.nodeType != 1){
1697 n = n.previousSibling;
1698 }
1699 return n;
1700 },
1701
1702
1703 /**
1704 * Appends the passed element(s) to this element
1705 * @param {String/HTMLElement/Array/Element/CompositeElement} el
1706 * @return {YAHOO.ext.Element} this
1707 */
1708 appendChild: function(el){
1709 el = getEl(el);
1710 el.appendTo(this);
1711 return this;
1712 },
1713
1714 /**
1715 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
1716 * @param {Object} config DomHelper element config object
1717 * @param {<i>HTMLElement</i>} insertBefore (optional) a child element of this element
1718 * @return {YAHOO.ext.Element} The new child element
1719 */
1720 createChild: function(config, insertBefore){
1721 var c;
1722 if(insertBefore){
1723 c = YAHOO.ext.DomHelper.insertBefore(insertBefore, config, true);
1724 }else{
1725 c = YAHOO.ext.DomHelper.append(this.dom, config, true);
1726 }
1727 return c;
1728 },
1729
1730 /**
1731 * Appends this element to the passed element
1732 * @param {String/HTMLElement/Element} el The new parent element
1733 * @return {YAHOO.ext.Element} this
1734 */
1735 appendTo: function(el){
1736 var node = getEl(el).dom;
1737 node.appendChild(this.dom);
1738 return this;
1739 },
1740
1741 /**
1742 * Inserts this element before the passed element in the DOM
1743 * @param {String/HTMLElement/Element} el The element to insert before
1744 * @return {YAHOO.ext.Element} this
1745 */
1746 insertBefore: function(el){
1747 var node = getEl(el).dom;
1748 node.parentNode.insertBefore(this.dom, node);
1749 return this;
1750 },
1751
1752 /**
1753 * Inserts this element after the passed element in the DOM
1754 * @param {String/HTMLElement/Element} el The element to insert after
1755 * @return {YAHOO.ext.Element} this
1756 */
1757 insertAfter: function(el){
1758 var node = getEl(el).dom;
1759 node.parentNode.insertBefore(this.dom, node.nextSibling);
1760 return this;
1761 },
1762
1763 /**
1764 * Creates and wraps this element with another element
1765 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
1766 * @return {Element} The newly created wrapper element
1767 */
1768 wrap: function(config){
1769 if(!config){
1770 config = {tag: 'div'};
1771 }
1772 var newEl = YAHOO.ext.DomHelper.insertBefore(this.dom, config, true);
1773 newEl.dom.appendChild(this.dom);
1774 return newEl;
1775 },
1776
1777 /**
1778 * Replaces the passed element with this element
1779 * @param {String/HTMLElement/Element} el The element to replace
1780 * @return {YAHOO.ext.Element} this
1781 */
1782 replace: function(el){
1783 el = getEl(el);
1784 this.insertBefore(el);
1785 el.remove();
1786 return this;
1787 },
1788
1789 /**
1790 * Inserts an html fragment into this element
1791 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
1792 * @param {String} html The HTML fragment
1793 * @return {HTMLElement} The inserted node (or nearest related if more than 1 inserted)
1794 */
1795 insertHtml : function(where, html){
1796 return YAHOO.ext.DomHelper.insertHtml(where, this.dom, html);
1797 },
1798
1799 /**
1800 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
1801 * @param {Object} o The object with the attributes
1802 * @return {YAHOO.ext.Element} this
1803 */
1804 set : function(o){
1805 var el = this.dom;
1806 var useSet = el.setAttribute ? true : false;
1807 for(var attr in o){
1808 if(attr == 'style' || typeof o[attr] == 'function') continue;
1809 if(attr=='cls'){
1810 el.className = o['cls'];
1811 }else{
1812 if(useSet) el.setAttribute(attr, o[attr]);
1813 else el[attr] = o[attr];
1814 }
1815 }
1816 YAHOO.ext.DomHelper.applyStyles(el, o.style);
1817 return this;
1818 },
1819
1820 /**
1821 * Convenience method for constructing a KeyMap
1822 * @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:
1823 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
1824 * @param {Function} fn The function to call
1825 * @param {Object} scope (optional) The scope of the function
1826 * @return {YAHOO.ext.KeyMap} The KeyMap created
1827 */
1828 addKeyListener : function(key, fn, scope){
1829 var config;
1830 if(typeof key != 'object' || key instanceof Array){
1831 config = {
1832 key: key,
1833 fn: fn,
1834 scope: scope
1835 };
1836 }else{
1837 config = {
1838 key : key.key,
1839 shift : key.shift,
1840 ctrl : key.ctrl,
1841 alt : key.alt,
1842 fn: fn,
1843 scope: scope
1844 };
1845 }
1846 var map = new YAHOO.ext.KeyMap(this, config);
1847 return map;
1848 },
1849
1850 /**
1851 * Creates a KeyMap for this element
1852 * @param {Object} config The KeyMap config. See {@link YAHOO.ext.KeyMap} for more details
1853 * @return {YAHOO.ext.KeyMap} The KeyMap created
1854 */
1855 addKeyMap : function(config){
1856 return new YAHOO.ext.KeyMap(this, config);
1857 },
1858
1859 /**
1860 * Returns true if this element is scrollable.
1861 * @return {Boolean}
1862 */
1863 isScrollable : function(){
1864 var dom = this.dom;
1865 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
1866 },
1867
1868 /**
1869 * 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().
1870 * @param {String} side Either 'left' for scrollLeft values or 'top' for scrollTop values.
1871 * @param {Number} value The new scroll value
1872 * @param {<i>Boolean</i>} animate (optional) Animate the scroll (Default is false)
1873 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1874 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1875 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use.
1876 * @return {Element} this
1877 */
1878
1879 scrollTo : function(side, value, animate, duration, onComplete, easing){
1880 var prop = side.toLowerCase() == 'left' ? 'scrollLeft' : 'scrollTop';
1881 if(!animate || !YAHOO.util.Anim){
1882 this.dom[prop] = value;
1883 }else{
1884 var to = prop == 'scrollLeft' ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
1885 this.anim({scroll: {'to': to}}, duration, onComplete, easing || YAHOO.util.Easing.easeOut, YAHOO.util.Scroll);
1886 }
1887 return this;
1888 },
1889
1890 /**
1891 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
1892 * within this elements scrollable range.
1893 * @param {String} direction Possible values are: 'l','left' - 'r','right' - 't','top','up' - 'b','bottom','down'.
1894 * @param {Number} distance How far to scroll the element in pixels
1895 * @param {<i>Boolean</i>} animate (optional) Animate the scroll (Default is false)
1896 * @param {<i>Float</i>} duration (optional) How long the animation lasts. (Defaults to .35 seconds)
1897 * @param {<i>Function</i>} onComplete (optional) Function to call when animation completes.
1898 * @param {<i>Function</i>} easing (optional) YAHOO.util.Easing method to use.
1899 * @return {Boolean} Returns true if a scroll was triggered or false if the element
1900 * was scrolled as far as it could go.
1901 */
1902 scroll : function(direction, distance, animate, duration, onComplete, easing){
1903 if(!this.isScrollable()){
1904 return;
1905 }
1906 var el = this.dom;
1907 var l = el.scrollLeft, t = el.scrollTop;
1908 var w = el.scrollWidth, h = el.scrollHeight;
1909 var cw = el.clientWidth, ch = el.clientHeight;
1910 direction = direction.toLowerCase();
1911 var scrolled = false;
1912 switch(direction){
1913 case 'l':
1914 case 'left':
1915 if(w - l > cw){
1916 var v = Math.min(l + distance, w-cw);
1917 this.scrollTo('left', v, animate, duration, onComplete, easing);
1918 scrolled = true;
1919 }
1920 break;
1921 case 'r':
1922 case 'right':
1923 if(l > 0){
1924 var v = Math.max(l - distance, 0);
1925 this.scrollTo('left', v, animate, duration, onComplete, easing);
1926 scrolled = true;
1927 }
1928 break;
1929 case 't':
1930 case 'top':
1931 case 'up':
1932 if(t > 0){
1933 var v = Math.max(t - distance, 0);
1934 this.scrollTo('top', v, animate, duration, onComplete, easing);
1935 scrolled = true;
1936 }
1937 break;
1938 case 'b':
1939 case 'bottom':
1940 case 'down':
1941 if(h - t > ch){
1942 var v = Math.min(t + distance, h-ch);
1943 this.scrollTo('top', v, animate, duration, onComplete, easing);
1944 scrolled = true;
1945 }
1946 break;
1947 }
1948 return scrolled;
1949 },
1950
1951 /**
1952 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
1953 * are convert to standard 6 digit hex color.
1954 * @param {String} attr The css attribute
1955 * @param {String} defaultValue The default value to use when a valid color isn't found
1956 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
1957 * YUI color anims.
1958 */
1959 getColor : function(attr, defaultValue, prefix){
1960 var v = this.getStyle(attr);
1961 if(!v || v == 'transparent' || v == 'inherit') {
1962 return defaultValue;
1963 }
1964 var color = typeof prefix == 'undefined' ? '#' : prefix;
1965 if(v.substr(0, 4) == 'rgb('){
1966 var rvs = v.slice(4, v.length -1).split(',');
1967 for(var i = 0; i < 3; i++){
1968 var h = parseInt(rvs[i]).toString(16);
1969 if(h < 16){
1970 h = '0' + h;
1971 }
1972 color += h;
1973 }
1974 } else {
1975 if(v.substr(0, 1) == '#'){
1976 if(v.length == 4) {
1977 for(var i = 1; i < 4; i++){
1978 var c = v.charAt(i);
1979 color += c + c;
1980 }
1981 }else if(v.length == 7){
1982 color += v.slice(1, 6);
1983 }
1984 }
1985 }
1986 return(color.length > 5 ? color.toLowerCase() : defaultValue);
1987 },
1988
1989 /**
1990 * Highlights the Element by setting a color (defaults to background-color) and then
1991 * fading back to the original color. If no original color is available, you should
1992 * provide an "endColor" option which will be cleared after the animation. The available options
1993 * for the "options" parameter are listed below (with their default values): <br/>
1994<pre><code>
1995el.highlight('ff0000', {<br/>
1996 attr: 'background-color',<br/>
1997 endColor: (current color) or 'ffffff'<br/>
1998 callback: yourFunction,<br/>
1999 scope: yourObject,<br/>
2000 easing: YAHOO.util.Easing.easeNone, <br/>
2001 duration: .75<br/>
2002});
2003</code></pre>
2004 * @param {String} color (optional) The highlight color. Should be a 6 char hex color (no #). (defaults to ffff9c)
2005 * @param {Object} options (optional) Object literal with any of the options listed above
2006 */
2007 highlight : function(color, options){
2008 color = color || 'ffff9c';
2009 options = options || {};
2010 attr = options.attr || 'background-color';
2011 var origColor = this.getColor(attr);
2012 endColor = (options.endColor || origColor) || 'ffffff';
2013 var dom = this.dom;
2014 var cb = function(){
2015 YAHOO.util.Dom.setStyle(dom, attr, origColor || '');
2016 if(options.callback){
2017 options.callback.call(options.scope || window);
2018 }
2019 };
2020 var o = {};
2021 o[attr] = {from: color, to: endColor};
2022 this.anim(o, options.duration || .75, cb, options.easing || YAHOO.util.Easing.easeNone, YAHOO.util.ColorAnim);
2023 return this;
2024 }
2025};
2026
2027/**
2028 * true to automatically adjust width and height settings for box-model issues (default to true)
2029 */
2030YAHOO.ext.Element.prototype.autoBoxAdjust = true;
2031/**
2032 * true to automatically detect display mode and use display instead of visibility with show()/hide() (defaults to false).
2033 * To enable this globally:<pre><code>YAHOO.ext.Element.prototype.autoDisplayMode = true;</code></pre>
2034 */
2035YAHOO.ext.Element.prototype.autoDisplayMode = true;
2036
2037YAHOO.ext.Element.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
2038/**
2039 * Visibility mode constant - Use visibility to hide element
2040 * @static
2041 * @type Number
2042 */
2043YAHOO.ext.Element.VISIBILITY = 1;
2044/**
2045 * Visibility mode constant - Use display to hide element
2046 * @static
2047 * @type Number
2048 */
2049YAHOO.ext.Element.DISPLAY = 2;
2050
2051YAHOO.ext.Element.blockElements = /^(?:address|blockquote|center|dir|div|dl|fieldset|form|h\d|hr|isindex|menu|ol|ul|p|pre|table|dd|dt|li|tbody|tr|td|thead|tfoot|iframe)$/i;
2052YAHOO.ext.Element.borders = {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'};
2053YAHOO.ext.Element.paddings = {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'};
2054YAHOO.ext.Element.margins = {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'};
2055
2056/**
2057 * @private Call out to here so we make minimal closure
2058 */
2059YAHOO.ext.Element.createStopHandler = function(stopPropagation, handler, scope, override){
2060 return function(e){
2061 if(e){
2062 if(stopPropagation){
2063 YAHOO.util.Event.stopEvent(e);
2064 }else {
2065 YAHOO.util.Event.preventDefault(e);
2066 }
2067 }
2068 handler.call(override && scope ? scope : window, e, scope);
2069 };
2070};
2071
2072/**
2073 * @private
2074 */
2075YAHOO.ext.Element.cache = {};
2076
2077/**
2078 * Static method to retreive Element objects. Uses simple caching to consistently return the same object.
2079 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
2080 * @param {String/HTMLElement/Element} el The id of the element or the element to wrap (must have an id). If you pass in an element, it is returned
2081 * @return {Element} The element object
2082 * @static
2083 */
2084YAHOO.ext.Element.get = function(){
2085 var doc = document; // prevent IE dom lookup on every call to getEl
2086 var docEl;
2087 var E = YAHOO.ext.Element;
2088 var D = YAHOO.util.Dom;
2089
2090 return function(el){
2091 if(!el){ return null; }
2092 if(el instanceof E){
2093 if(el != docEl){
2094 el.dom = doc.getElementById(el.id); // refresh dom element in case no longer valid
2095 E.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
2096 }
2097 return el;
2098 }else if(el.isComposite){
2099 return el;
2100 }else if(el instanceof Array){
2101 return E.select(el);
2102 }else if(el == doc){
2103 // create a bogus element object representing the document object
2104 if(!docEl){
2105 var f = function(){};
2106 f.prototype = E.prototype;
2107 docEl = new f();
2108 docEl.dom = doc;
2109 }
2110 return docEl;
2111 }
2112 var key = el;
2113 if(typeof el != 'string'){ // must be an element
2114 D.generateId(el, 'elgen-');
2115 key = el.id;
2116 }
2117 var element = E.cache[key];
2118 if(!element){
2119 element = new E(key);
2120 if(!element.dom) return null;
2121 E.cache[key] = element;
2122 }else{
2123 element.dom = doc.getElementById(key);
2124 }
2125 return element;
2126 };
2127}();
2128
2129/*
2130 * Gets the globally shared flyweight Element. Use sparingly for
2131 * bulk operations where a unique instance isn't needed.
2132 * Do not store a reference to this element - the dom node
2133 * can be overwritten by other code.
2134 */
2135YAHOO.ext.Element.fly = function(el){
2136 var E = YAHOO.ext.Element;
2137 if(typeof el == 'string'){
2138 el = document.getElementById(el);
2139 }
2140 if(!E._flyweight){
2141 var f = function(){};
2142 f.prototype = E.prototype;
2143 E._flyweight = new f();
2144 }
2145 E._flyweight.dom = el;
2146 return E._flyweight;
2147}
2148
2149/*
2150 * Shorthand function for YAHOO.ext.Element.get()
2151 */
2152getEl = YAHOO.ext.Element.get;
2153
2154YAHOO.util.Event.addListener(window, 'unload', function(){
2155 YAHOO.ext.Element.cache = null;
2156});
2157