2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
10 * Config is a utility used within an Object to allow the implementer to
11 * maintain a list of local configuration properties and listen for changes
12 * to those properties dynamically using CustomEvent. The initial values are
13 * also maintained so that the configuration can be reset at any given point
14 * to its initial state.
15 * @namespace YAHOO.util
18 * @param {Object} owner The owner Object to which this Config Object belongs
20 YAHOO.util.Config = function (owner) {
26 if (!owner) { YAHOO.log("No owner specified for Config object", "error", "Config"); }
31 var Lang = YAHOO.lang,
32 CustomEvent = YAHOO.util.CustomEvent,
33 Config = YAHOO.util.Config;
37 * Constant representing the CustomEvent type for the config changed event.
38 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
43 Config.CONFIG_CHANGED_EVENT = "configChanged";
46 * Constant representing the boolean type string
47 * @property YAHOO.util.Config.BOOLEAN_TYPE
52 Config.BOOLEAN_TYPE = "boolean";
57 * Object reference to the owner of this Config Object
64 * Boolean flag that specifies whether a queue is currently
66 * @property queueInProgress
69 queueInProgress: false,
72 * Maintains the local collection of configuration property objects and
73 * their specified values
81 * Maintains the local collection of configuration property objects as
82 * they were initially applied.
83 * This object is used when resetting a property.
84 * @property initialConfig
91 * Maintains the local, normalized CustomEvent queue
92 * @property eventQueue
99 * Custom Event, notifying subscribers when Config properties are set
100 * (setProperty is called without the silent flag
101 * @event configChangedEvent
103 configChangedEvent: null,
106 * Initializes the configuration Object and all of its local members.
108 * @param {Object} owner The owner Object to which this Config
111 init: function (owner) {
115 this.configChangedEvent =
116 this.createEvent(Config.CONFIG_CHANGED_EVENT);
118 this.configChangedEvent.signature = CustomEvent.LIST;
119 this.queueInProgress = false;
121 this.initialConfig = {};
122 this.eventQueue = [];
127 * Validates that the value passed in is a Boolean.
128 * @method checkBoolean
129 * @param {Object} val The value to validate
130 * @return {Boolean} true, if the value is valid
132 checkBoolean: function (val) {
133 return (typeof val == Config.BOOLEAN_TYPE);
137 * Validates that the value passed in is a number.
138 * @method checkNumber
139 * @param {Object} val The value to validate
140 * @return {Boolean} true, if the value is valid
142 checkNumber: function (val) {
143 return (!isNaN(val));
147 * Fires a configuration property event using the specified value.
150 * @param {String} key The configuration property's name
151 * @param {value} Object The value of the correct type for the property
153 fireEvent: function ( key, value ) {
154 YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
155 var property = this.config[key];
157 if (property && property.event) {
158 property.event.fire(value);
163 * Adds a property to the Config Object's private config hash.
164 * @method addProperty
165 * @param {String} key The configuration property's name
166 * @param {Object} propertyObject The Object containing all of this
167 * property's arguments
169 addProperty: function ( key, propertyObject ) {
170 key = key.toLowerCase();
171 YAHOO.log("Added property: " + key, "info", "Config");
173 this.config[key] = propertyObject;
175 propertyObject.event = this.createEvent(key, { scope: this.owner });
176 propertyObject.event.signature = CustomEvent.LIST;
179 propertyObject.key = key;
181 if (propertyObject.handler) {
182 propertyObject.event.subscribe(propertyObject.handler,
186 this.setProperty(key, propertyObject.value, true);
188 if (! propertyObject.suppressEvent) {
189 this.queueProperty(key, propertyObject.value);
195 * Returns a key-value configuration map of the values currently set in
198 * @return {Object} The current config, represented in a key-value map
200 getConfig: function () {
203 currCfg = this.config,
207 for (prop in currCfg) {
208 if (Lang.hasOwnProperty(currCfg, prop)) {
209 property = currCfg[prop];
210 if (property && property.event) {
211 cfg[prop] = property.value;
220 * Returns the value of specified property.
221 * @method getProperty
222 * @param {String} key The name of the property
223 * @return {Object} The value of the specified property
225 getProperty: function (key) {
226 var property = this.config[key.toLowerCase()];
227 if (property && property.event) {
228 return property.value;
235 * Resets the specified property's value to its initial value.
236 * @method resetProperty
237 * @param {String} key The name of the property
238 * @return {Boolean} True is the property was reset, false if not
240 resetProperty: function (key) {
242 key = key.toLowerCase();
244 var property = this.config[key];
246 if (property && property.event) {
248 if (this.initialConfig[key] &&
249 !Lang.isUndefined(this.initialConfig[key])) {
251 this.setProperty(key, this.initialConfig[key]);
265 * Sets the value of a property. If the silent property is passed as
266 * true, the property's event will not be fired.
267 * @method setProperty
268 * @param {String} key The name of the property
269 * @param {String} value The value to set the property to
270 * @param {Boolean} silent Whether the value should be set silently,
271 * without firing the property event.
272 * @return {Boolean} True, if the set was successful, false if it failed.
274 setProperty: function (key, value, silent) {
278 key = key.toLowerCase();
279 YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
281 if (this.queueInProgress && ! silent) {
282 // Currently running through a queue...
283 this.queueProperty(key,value);
287 property = this.config[key];
288 if (property && property.event) {
289 if (property.validator && !property.validator(value)) {
292 property.value = value;
294 this.fireEvent(key, value);
295 this.configChangedEvent.fire([key, value]);
306 * Sets the value of a property and queues its event to execute. If the
307 * event is already scheduled to execute, it is
308 * moved from its current position to the end of the queue.
309 * @method queueProperty
310 * @param {String} key The name of the property
311 * @param {String} value The value to set the property to
312 * @return {Boolean} true, if the set was successful, false if
315 queueProperty: function (key, value) {
317 key = key.toLowerCase();
318 YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
320 var property = this.config[key],
321 foundDuplicate = false,
336 if (property && property.event) {
338 if (!Lang.isUndefined(value) && property.validator &&
339 !property.validator(value)) { // validator
343 if (!Lang.isUndefined(value)) {
344 property.value = value;
346 value = property.value;
349 foundDuplicate = false;
350 iLen = this.eventQueue.length;
352 for (i = 0; i < iLen; i++) {
353 queueItem = this.eventQueue[i];
356 queueItemKey = queueItem[0];
357 queueItemValue = queueItem[1];
359 if (queueItemKey == key) {
362 found a dupe... push to end of queue, null
363 current item, and break
366 this.eventQueue[i] = null;
368 this.eventQueue.push(
369 [key, (!Lang.isUndefined(value) ?
370 value : queueItemValue)]);
372 foundDuplicate = true;
378 // this is a refire, or a new property in the queue
380 if (! foundDuplicate && !Lang.isUndefined(value)) {
381 this.eventQueue.push([key, value]);
385 if (property.supercedes) {
387 sLen = property.supercedes.length;
389 for (s = 0; s < sLen; s++) {
391 supercedesCheck = property.supercedes[s];
392 qLen = this.eventQueue.length;
394 for (q = 0; q < qLen; q++) {
395 queueItemCheck = this.eventQueue[q];
397 if (queueItemCheck) {
398 queueItemCheckKey = queueItemCheck[0];
399 queueItemCheckValue = queueItemCheck[1];
401 if (queueItemCheckKey ==
402 supercedesCheck.toLowerCase() ) {
404 this.eventQueue.push([queueItemCheckKey,
405 queueItemCheckValue]);
407 this.eventQueue[q] = null;
416 YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
425 * Fires the event for a property using the property's current value.
426 * @method refireEvent
427 * @param {String} key The name of the property
429 refireEvent: function (key) {
431 key = key.toLowerCase();
433 var property = this.config[key];
435 if (property && property.event &&
437 !Lang.isUndefined(property.value)) {
439 if (this.queueInProgress) {
441 this.queueProperty(key);
445 this.fireEvent(key, property.value);
453 * Applies a key-value Object literal to the configuration, replacing
454 * any existing values, and queueing the property events.
455 * Although the values will be set, fireQueue() must be called for their
456 * associated events to execute.
457 * @method applyConfig
458 * @param {Object} userConfig The configuration Object literal
459 * @param {Boolean} init When set to true, the initialConfig will
460 * be set to the userConfig passed in, so that calling a reset will
461 * reset the properties to the passed values.
463 applyConfig: function (userConfig, init) {
470 for (sKey in userConfig) {
471 if (Lang.hasOwnProperty(userConfig, sKey)) {
472 oConfig[sKey.toLowerCase()] = userConfig[sKey];
475 this.initialConfig = oConfig;
478 for (sKey in userConfig) {
479 if (Lang.hasOwnProperty(userConfig, sKey)) {
480 this.queueProperty(sKey, userConfig[sKey]);
486 * Refires the events for all configuration properties using their
490 refresh: function () {
494 for (prop in this.config) {
495 if (Lang.hasOwnProperty(this.config, prop)) {
496 this.refireEvent(prop);
502 * Fires the normalized list of queued property change events
505 fireQueue: function () {
513 this.queueInProgress = true;
514 for (i = 0;i < this.eventQueue.length; i++) {
515 queueItem = this.eventQueue[i];
519 value = queueItem[1];
520 property = this.config[key];
522 property.value = value;
524 // Clear out queue entry, to avoid it being
525 // re-added to the queue by any queueProperty/supercedes
526 // calls which are invoked during fireEvent
527 this.eventQueue[i] = null;
529 this.fireEvent(key,value);
533 this.queueInProgress = false;
534 this.eventQueue = [];
538 * Subscribes an external handler to the change event for any
540 * @method subscribeToConfigEvent
541 * @param {String} key The property name
542 * @param {Function} handler The handler function to use subscribe to
543 * the property's event
544 * @param {Object} obj The Object to use for scoping the event handler
545 * (see CustomEvent documentation)
546 * @param {Boolean} override Optional. If true, will override "this"
547 * within the handler to map to the scope Object passed into the method.
548 * @return {Boolean} True, if the subscription was successful,
551 subscribeToConfigEvent: function (key, handler, obj, override) {
553 var property = this.config[key.toLowerCase()];
555 if (property && property.event) {
556 if (!Config.alreadySubscribed(property.event, handler, obj)) {
557 property.event.subscribe(handler, obj, override);
567 * Unsubscribes an external handler from the change event for any
569 * @method unsubscribeFromConfigEvent
570 * @param {String} key The property name
571 * @param {Function} handler The handler function to use subscribe to
572 * the property's event
573 * @param {Object} obj The Object to use for scoping the event
574 * handler (see CustomEvent documentation)
575 * @return {Boolean} True, if the unsubscription was successful,
578 unsubscribeFromConfigEvent: function (key, handler, obj) {
579 var property = this.config[key.toLowerCase()];
580 if (property && property.event) {
581 return property.event.unsubscribe(handler, obj);
588 * Returns a string representation of the Config object
590 * @return {String} The Config object in string format.
592 toString: function () {
593 var output = "Config";
595 output += " [" + this.owner.toString() + "]";
601 * Returns a string representation of the Config object's current
603 * @method outputEventQueue
604 * @return {String} The string list of CustomEvents currently queued
607 outputEventQueue: function () {
612 nQueue = this.eventQueue.length;
614 for (q = 0; q < nQueue; q++) {
615 queueItem = this.eventQueue[q];
617 output += queueItem[0] + "=" + queueItem[1] + ", ";
624 * Sets all properties to null, unsubscribes all listeners from each
625 * property's change event and all listeners from the configChangedEvent.
628 destroy: function () {
630 var oConfig = this.config,
635 for (sProperty in oConfig) {
637 if (Lang.hasOwnProperty(oConfig, sProperty)) {
639 oProperty = oConfig[sProperty];
641 oProperty.event.unsubscribeAll();
642 oProperty.event = null;
648 this.configChangedEvent.unsubscribeAll();
650 this.configChangedEvent = null;
653 this.initialConfig = null;
654 this.eventQueue = null;
663 * Checks to determine if a particular function/Object pair are already
664 * subscribed to the specified CustomEvent
665 * @method YAHOO.util.Config.alreadySubscribed
667 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
669 * @param {Function} fn The function to look for in the subscribers list
670 * @param {Object} obj The execution scope Object for the subscription
671 * @return {Boolean} true, if the function/Object pair is already subscribed
672 * to the CustomEvent passed in
674 Config.alreadySubscribed = function (evt, fn, obj) {
676 var nSubscribers = evt.subscribers.length,
680 if (nSubscribers > 0) {
681 i = nSubscribers - 1;
683 subsc = evt.subscribers[i];
684 if (subsc && subsc.obj == obj && subsc.fn == fn) {
695 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
702 * The Container family of components is designed to enable developers to
703 * create different kinds of content-containing modules on the web. Module
704 * and Overlay are the most basic containers, and they can be used directly
705 * or extended to build custom containers. Also part of the Container family
706 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
707 * Dialog, and SimpleDialog.
710 * @requires yahoo, dom, event
711 * @optional dragdrop, animation, button
715 * Module is a JavaScript representation of the Standard Module Format.
716 * Standard Module Format is a simple standard for markup containers where
717 * child nodes representing the header, body, and footer of the content are
718 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
719 * Module is the base class for all other classes in the YUI
721 * @namespace YAHOO.widget
724 * @param {String} el The element ID representing the Module <em>OR</em>
725 * @param {HTMLElement} el The element representing the Module
726 * @param {Object} userConfig The configuration Object literal containing
727 * the configuration that should be set for this module. See configuration
728 * documentation for more details.
730 YAHOO.widget.Module = function (el, userConfig) {
732 this.init(el, userConfig);
734 YAHOO.log("No element or element ID specified" +
735 " for Module instantiation", "error");
739 var Dom = YAHOO.util.Dom,
740 Config = YAHOO.util.Config,
741 Event = YAHOO.util.Event,
742 CustomEvent = YAHOO.util.CustomEvent,
743 Module = YAHOO.widget.Module,
752 * Constant representing the name of the Module's events
753 * @property EVENT_TYPES
759 "BEFORE_INIT": "beforeInit",
762 "BEFORE_RENDER": "beforeRender",
764 "CHANGE_HEADER": "changeHeader",
765 "CHANGE_BODY": "changeBody",
766 "CHANGE_FOOTER": "changeFooter",
767 "CHANGE_CONTENT": "changeContent",
768 "DESTORY": "destroy",
769 "BEFORE_SHOW": "beforeShow",
771 "BEFORE_HIDE": "beforeHide",
776 * Constant representing the Module's configuration properties
777 * @property DEFAULT_CONFIG
787 validator: YAHOO.lang.isBoolean
793 supercedes: ["visible"]
797 key: "monitorresize",
801 "APPEND_TO_DOCUMENT_BODY": {
802 key: "appendtodocumentbody",
808 * Constant representing the prefix path to use for non-secure images
809 * @property YAHOO.widget.Module.IMG_ROOT
814 Module.IMG_ROOT = null;
817 * Constant representing the prefix path to use for securely served images
818 * @property YAHOO.widget.Module.IMG_ROOT_SSL
823 Module.IMG_ROOT_SSL = null;
826 * Constant for the default CSS class name that represents a Module
827 * @property YAHOO.widget.Module.CSS_MODULE
832 Module.CSS_MODULE = "yui-module";
835 * Constant representing the module header
836 * @property YAHOO.widget.Module.CSS_HEADER
841 Module.CSS_HEADER = "hd";
844 * Constant representing the module body
845 * @property YAHOO.widget.Module.CSS_BODY
850 Module.CSS_BODY = "bd";
853 * Constant representing the module footer
854 * @property YAHOO.widget.Module.CSS_FOOTER
859 Module.CSS_FOOTER = "ft";
862 * Constant representing the url for the "src" attribute of the iframe
863 * used to monitor changes to the browser's base font size
864 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
869 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
872 * Constant representing the buffer amount (in pixels) to use when positioning
873 * the text resize monitor offscreen. The resize monitor is positioned
874 * offscreen by an amount eqaul to its offsetHeight + the buffer value.
876 * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
880 // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
881 Module.RESIZE_MONITOR_BUFFER = 1;
884 * Singleton CustomEvent fired when the font size is changed in the browser.
885 * Opera's "zoom" functionality currently does not support text
887 * @event YAHOO.widget.Module.textResizeEvent
889 Module.textResizeEvent = new CustomEvent("textResize");
892 * Helper utility method, which forces a document level
893 * redraw for Opera, which can help remove repaint
894 * irregularities after applying DOM changes.
896 * @method YAHOO.widget.Module.forceDocumentRedraw
899 Module.forceDocumentRedraw = function() {
900 var docEl = document.documentElement;
902 docEl.className += " ";
903 docEl.className = YAHOO.lang.trim(docEl.className);
907 function createModuleTemplate() {
909 if (!m_oModuleTemplate) {
910 m_oModuleTemplate = document.createElement("div");
912 m_oModuleTemplate.innerHTML = ("<div class=\"" +
913 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
914 Module.CSS_BODY + "\"></div><div class=\"" +
915 Module.CSS_FOOTER + "\"></div>");
917 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
918 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
919 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
922 return m_oModuleTemplate;
925 function createHeader() {
926 if (!m_oHeaderTemplate) {
927 createModuleTemplate();
929 return (m_oHeaderTemplate.cloneNode(false));
932 function createBody() {
933 if (!m_oBodyTemplate) {
934 createModuleTemplate();
936 return (m_oBodyTemplate.cloneNode(false));
939 function createFooter() {
940 if (!m_oFooterTemplate) {
941 createModuleTemplate();
943 return (m_oFooterTemplate.cloneNode(false));
949 * The class's constructor function
950 * @property contructor
956 * The main module element that contains the header, body, and footer
963 * The header element, denoted with CSS class "hd"
970 * The body element, denoted with CSS class "bd"
977 * The footer element, denoted with CSS class "ft"
984 * The id of the element
991 * A string representing the root path for all images created by
993 * @deprecated It is recommend that any images for a Module be applied
994 * via CSS using the "background-image" property.
995 * @property imageRoot
998 imageRoot: Module.IMG_ROOT,
1001 * Initializes the custom events for Module which are fired
1002 * automatically at appropriate times by the Module class.
1003 * @method initEvents
1005 initEvents: function () {
1007 var SIGNATURE = CustomEvent.LIST;
1010 * CustomEvent fired prior to class initalization.
1011 * @event beforeInitEvent
1012 * @param {class} classRef class reference of the initializing
1013 * class, such as this.beforeInitEvent.fire(Module)
1015 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1016 this.beforeInitEvent.signature = SIGNATURE;
1019 * CustomEvent fired after class initalization.
1021 * @param {class} classRef class reference of the initializing
1022 * class, such as this.beforeInitEvent.fire(Module)
1024 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1025 this.initEvent.signature = SIGNATURE;
1028 * CustomEvent fired when the Module is appended to the DOM
1029 * @event appendEvent
1031 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1032 this.appendEvent.signature = SIGNATURE;
1035 * CustomEvent fired before the Module is rendered
1036 * @event beforeRenderEvent
1038 this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1039 this.beforeRenderEvent.signature = SIGNATURE;
1042 * CustomEvent fired after the Module is rendered
1043 * @event renderEvent
1045 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1046 this.renderEvent.signature = SIGNATURE;
1049 * CustomEvent fired when the header content of the Module
1051 * @event changeHeaderEvent
1052 * @param {String/HTMLElement} content String/element representing
1053 * the new header content
1055 this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1056 this.changeHeaderEvent.signature = SIGNATURE;
1059 * CustomEvent fired when the body content of the Module is modified
1060 * @event changeBodyEvent
1061 * @param {String/HTMLElement} content String/element representing
1062 * the new body content
1064 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1065 this.changeBodyEvent.signature = SIGNATURE;
1068 * CustomEvent fired when the footer content of the Module
1070 * @event changeFooterEvent
1071 * @param {String/HTMLElement} content String/element representing
1072 * the new footer content
1074 this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1075 this.changeFooterEvent.signature = SIGNATURE;
1078 * CustomEvent fired when the content of the Module is modified
1079 * @event changeContentEvent
1081 this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1082 this.changeContentEvent.signature = SIGNATURE;
1085 * CustomEvent fired when the Module is destroyed
1086 * @event destroyEvent
1088 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
1089 this.destroyEvent.signature = SIGNATURE;
1092 * CustomEvent fired before the Module is shown
1093 * @event beforeShowEvent
1095 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1096 this.beforeShowEvent.signature = SIGNATURE;
1099 * CustomEvent fired after the Module is shown
1102 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1103 this.showEvent.signature = SIGNATURE;
1106 * CustomEvent fired before the Module is hidden
1107 * @event beforeHideEvent
1109 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1110 this.beforeHideEvent.signature = SIGNATURE;
1113 * CustomEvent fired after the Module is hidden
1116 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1117 this.hideEvent.signature = SIGNATURE;
1121 * String representing the current user-agent platform
1122 * @property platform
1125 platform: function () {
1126 var ua = navigator.userAgent.toLowerCase();
1128 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1130 } else if (ua.indexOf("macintosh") != -1) {
1138 * String representing the user-agent of the browser
1139 * @deprecated Use YAHOO.env.ua
1143 browser: function () {
1144 var ua = navigator.userAgent.toLowerCase();
1146 Check Opera first in case of spoof and check Safari before
1147 Gecko since Safari's user agent string includes "like Gecko"
1149 if (ua.indexOf('opera') != -1) {
1151 } else if (ua.indexOf('msie 7') != -1) {
1153 } else if (ua.indexOf('msie') != -1) {
1155 } else if (ua.indexOf('safari') != -1) {
1157 } else if (ua.indexOf('gecko') != -1) {
1165 * Boolean representing whether or not the current browsing context is
1167 * @property isSecure
1170 isSecure: function () {
1171 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1179 * Initializes the custom events for Module which are fired
1180 * automatically at appropriate times by the Module class.
1182 initDefaultConfig: function () {
1183 // Add properties //
1185 * Specifies whether the Module is visible on the page.
1190 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1191 handler: this.configVisible,
1192 value: DEFAULT_CONFIG.VISIBLE.value,
1193 validator: DEFAULT_CONFIG.VISIBLE.validator
1198 * Object or array of objects representing the ContainerEffect
1199 * classes that are active for animating the container.
1202 * <strong>NOTE:</strong> Although this configuration
1203 * property is introduced at the Module level, an out of the box
1204 * implementation is not shipped for the Module class so setting
1205 * the proroperty on the Module class has no effect. The Overlay
1206 * class is the first class to provide out of the box ContainerEffect
1213 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1214 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1215 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1219 * Specifies whether to create a special proxy iframe to monitor
1220 * for user font resizing in the document
1221 * @config monitorresize
1225 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1226 handler: this.configMonitorResize,
1227 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1231 * Specifies if the module should be rendered as the first child
1232 * of document.body or appended as the last child when render is called
1233 * with document.body as the "appendToNode".
1235 * Appending to the body while the DOM is still being constructed can
1236 * lead to Operation Aborted errors in IE hence this flag is set to
1240 * @config appendtodocumentbody
1244 this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1245 value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1250 * The Module class's initialization method, which is executed for
1251 * Module and all of its subclasses. This method is automatically
1252 * called by the constructor, and sets up all DOM references for
1253 * pre-existing markup, and creates required markup if it is not
1256 * If the element passed in does not have an id, one will be generated
1260 * @param {String} el The element ID representing the Module <em>OR</em>
1261 * @param {HTMLElement} el The element representing the Module
1262 * @param {Object} userConfig The configuration Object literal
1263 * containing the configuration that should be set for this module.
1264 * See configuration documentation for more details.
1266 init: function (el, userConfig) {
1271 this.beforeInitEvent.fire(Module);
1274 * The Module's Config object used for monitoring
1275 * configuration properties.
1277 * @type YAHOO.util.Config
1279 this.cfg = new Config(this);
1281 if (this.isSecure) {
1282 this.imageRoot = Module.IMG_ROOT_SSL;
1285 if (typeof el == "string") {
1287 el = document.getElementById(el);
1289 el = (createModuleTemplate()).cloneNode(false);
1294 this.id = Dom.generateId(el);
1297 child = this.element.firstChild;
1300 var fndHd = false, fndBd = false, fndFt = false;
1302 // We're looking for elements
1303 if (1 == child.nodeType) {
1304 if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1305 this.header = child;
1307 } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1310 } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1311 this.footer = child;
1315 } while ((child = child.nextSibling));
1318 this.initDefaultConfig();
1320 Dom.addClass(this.element, Module.CSS_MODULE);
1323 this.cfg.applyConfig(userConfig, true);
1327 Subscribe to the fireQueue() method of Config so that any
1328 queued configuration changes are excecuted upon render of
1332 if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1333 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1336 this.initEvent.fire(Module);
1340 * Initialize an empty IFRAME that is placed out of the visible area
1341 * that can be used to detect text resize.
1342 * @method initResizeMonitor
1344 initResizeMonitor: function () {
1346 var isGeckoWin = (UA.gecko && this.platform == "windows");
1348 // Help prevent spinning loading icon which
1349 // started with FireFox 2.0.0.8/Win
1351 setTimeout(function(){self._initResizeMonitor();}, 0);
1353 this._initResizeMonitor();
1358 * Create and initialize the text resize monitoring iframe.
1361 * @method _initResizeMonitor
1363 _initResizeMonitor : function() {
1369 function fireTextResize() {
1370 Module.textResizeEvent.fire();
1374 oIFrame = Dom.get("_yuiResizeMonitor");
1376 var supportsCWResize = this._supportsCWResize();
1379 oIFrame = document.createElement("iframe");
1381 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1382 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1385 if (!supportsCWResize) {
1386 // Can't monitor on contentWindow, so fire from inside iframe
1387 sHTML = ["<html><head><script ",
1388 "type=\"text/javascript\">",
1389 "window.onresize=function(){window.parent.",
1390 "YAHOO.widget.Module.textResizeEvent.",
1393 "<body></body></html>"].join('');
1395 oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1398 oIFrame.id = "_yuiResizeMonitor";
1399 oIFrame.title = "Text Resize Monitor";
1401 Need to set "position" property before inserting the
1402 iframe into the document or Safari's status bar will
1403 forever indicate the iframe is loading
1404 (See SourceForge bug #1723064)
1406 oIFrame.style.position = "absolute";
1407 oIFrame.style.visibility = "hidden";
1409 var db = document.body,
1412 db.insertBefore(oIFrame, fc);
1414 db.appendChild(oIFrame);
1417 oIFrame.style.width = "2em";
1418 oIFrame.style.height = "2em";
1419 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1420 oIFrame.style.left = "0";
1421 oIFrame.style.borderWidth = "0";
1422 oIFrame.style.visibility = "visible";
1425 Don't open/close the document for Gecko like we used to, since it
1426 leads to duplicate cookies. (See SourceForge bug #1721755)
1429 oDoc = oIFrame.contentWindow.document;
1435 if (oIFrame && oIFrame.contentWindow) {
1436 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1438 if (!Module.textResizeInitialized) {
1439 if (supportsCWResize) {
1440 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1442 This will fail in IE if document.domain has
1443 changed, so we must change the listener to
1444 use the oIFrame element instead
1446 Event.on(oIFrame, "resize", fireTextResize);
1449 Module.textResizeInitialized = true;
1451 this.resizeMonitor = oIFrame;
1457 * Text resize monitor helper method.
1458 * Determines if the browser supports resize events on iframe content windows.
1461 * @method _supportsCWResize
1463 _supportsCWResize : function() {
1465 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1466 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1468 We don't want to start sniffing for patch versions, so fire textResize the same
1469 way on all FF2 flavors
1471 var bSupported = true;
1472 if (UA.gecko && UA.gecko <= 1.8) {
1479 * Event handler fired when the resize monitor element is resized.
1480 * @method onDomResize
1481 * @param {DOMEvent} e The DOM resize event
1482 * @param {Object} obj The scope object passed to the handler
1484 onDomResize: function (e, obj) {
1486 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1488 this.resizeMonitor.style.top = nTop + "px";
1489 this.resizeMonitor.style.left = "0";
1493 * Sets the Module's header content to the string specified, or appends
1494 * the passed element to the header. If no header is present, one will
1495 * be automatically created. An empty string can be passed to the method
1496 * to clear the contents of the header.
1499 * @param {String} headerContent The string used to set the header.
1500 * As a convenience, non HTMLElement objects can also be passed into
1501 * the method, and will be treated as strings, with the header innerHTML
1502 * set to their default toString implementations.
1504 * @param {HTMLElement} headerContent The HTMLElement to append to
1506 * @param {DocumentFragment} headerContent The document fragment
1507 * containing elements which are to be added to the header
1509 setHeader: function (headerContent) {
1510 var oHeader = this.header || (this.header = createHeader());
1512 if (headerContent.nodeName) {
1513 oHeader.innerHTML = "";
1514 oHeader.appendChild(headerContent);
1516 oHeader.innerHTML = headerContent;
1519 this.changeHeaderEvent.fire(headerContent);
1520 this.changeContentEvent.fire();
1525 * Appends the passed element to the header. If no header is present,
1526 * one will be automatically created.
1527 * @method appendToHeader
1528 * @param {HTMLElement | DocumentFragment} element The element to
1529 * append to the header. In the case of a document fragment, the
1530 * children of the fragment will be appended to the header.
1532 appendToHeader: function (element) {
1533 var oHeader = this.header || (this.header = createHeader());
1535 oHeader.appendChild(element);
1537 this.changeHeaderEvent.fire(element);
1538 this.changeContentEvent.fire();
1543 * Sets the Module's body content to the HTML specified.
1545 * If no body is present, one will be automatically created.
1547 * An empty string can be passed to the method to clear the contents of the body.
1549 * @param {String} bodyContent The HTML used to set the body.
1550 * As a convenience, non HTMLElement objects can also be passed into
1551 * the method, and will be treated as strings, with the body innerHTML
1552 * set to their default toString implementations.
1554 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1555 * child of the body element.
1557 * @param {DocumentFragment} bodyContent The document fragment
1558 * containing elements which are to be added to the body
1560 setBody: function (bodyContent) {
1561 var oBody = this.body || (this.body = createBody());
1563 if (bodyContent.nodeName) {
1564 oBody.innerHTML = "";
1565 oBody.appendChild(bodyContent);
1567 oBody.innerHTML = bodyContent;
1570 this.changeBodyEvent.fire(bodyContent);
1571 this.changeContentEvent.fire();
1575 * Appends the passed element to the body. If no body is present, one
1576 * will be automatically created.
1577 * @method appendToBody
1578 * @param {HTMLElement | DocumentFragment} element The element to
1579 * append to the body. In the case of a document fragment, the
1580 * children of the fragment will be appended to the body.
1583 appendToBody: function (element) {
1584 var oBody = this.body || (this.body = createBody());
1586 oBody.appendChild(element);
1588 this.changeBodyEvent.fire(element);
1589 this.changeContentEvent.fire();
1594 * Sets the Module's footer content to the HTML specified, or appends
1595 * the passed element to the footer. If no footer is present, one will
1596 * be automatically created. An empty string can be passed to the method
1597 * to clear the contents of the footer.
1599 * @param {String} footerContent The HTML used to set the footer
1600 * As a convenience, non HTMLElement objects can also be passed into
1601 * the method, and will be treated as strings, with the footer innerHTML
1602 * set to their default toString implementations.
1604 * @param {HTMLElement} footerContent The HTMLElement to append to
1607 * @param {DocumentFragment} footerContent The document fragment containing
1608 * elements which are to be added to the footer
1610 setFooter: function (footerContent) {
1612 var oFooter = this.footer || (this.footer = createFooter());
1614 if (footerContent.nodeName) {
1615 oFooter.innerHTML = "";
1616 oFooter.appendChild(footerContent);
1618 oFooter.innerHTML = footerContent;
1621 this.changeFooterEvent.fire(footerContent);
1622 this.changeContentEvent.fire();
1626 * Appends the passed element to the footer. If no footer is present,
1627 * one will be automatically created.
1628 * @method appendToFooter
1629 * @param {HTMLElement | DocumentFragment} element The element to
1630 * append to the footer. In the case of a document fragment, the
1631 * children of the fragment will be appended to the footer
1633 appendToFooter: function (element) {
1635 var oFooter = this.footer || (this.footer = createFooter());
1637 oFooter.appendChild(element);
1639 this.changeFooterEvent.fire(element);
1640 this.changeContentEvent.fire();
1645 * Renders the Module by inserting the elements that are not already
1646 * in the main Module into their correct places. Optionally appends
1647 * the Module to the specified node prior to the render's execution.
1649 * For Modules without existing markup, the appendToNode argument
1650 * is REQUIRED. If this argument is ommitted and the current element is
1651 * not present in the document, the function will return false,
1652 * indicating that the render was a failure.
1655 * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1656 * then the module is rendered as the first child of the body element,
1657 * and not appended to it, to avoid Operation Aborted errors in IE when
1658 * rendering the module before window's load event is fired. You can
1659 * use the appendtodocumentbody configuration property to change this
1660 * to append to document.body if required.
1663 * @param {String} appendToNode The element id to which the Module
1664 * should be appended to prior to rendering <em>OR</em>
1665 * @param {HTMLElement} appendToNode The element to which the Module
1666 * should be appended to prior to rendering
1667 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1668 * represents the actual Standard Module container.
1669 * @return {Boolean} Success or failure of the render
1671 render: function (appendToNode, moduleElement) {
1676 function appendTo(parentNode) {
1677 if (typeof parentNode == "string") {
1678 parentNode = document.getElementById(parentNode);
1682 me._addToParent(parentNode, me.element);
1683 me.appendEvent.fire();
1687 this.beforeRenderEvent.fire();
1689 if (! moduleElement) {
1690 moduleElement = this.element;
1694 appendTo(appendToNode);
1696 // No node was passed in. If the element is not already in the Dom, this fails
1697 if (! Dom.inDocument(this.element)) {
1698 YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
1703 // Need to get everything into the DOM if it isn't already
1704 if (this.header && ! Dom.inDocument(this.header)) {
1705 // There is a header, but it's not in the DOM yet. Need to add it.
1706 firstChild = moduleElement.firstChild;
1708 moduleElement.insertBefore(this.header, firstChild);
1710 moduleElement.appendChild(this.header);
1714 if (this.body && ! Dom.inDocument(this.body)) {
1715 // There is a body, but it's not in the DOM yet. Need to add it.
1716 if (this.footer && Dom.isAncestor(this.moduleElement, this.footer)) {
1717 moduleElement.insertBefore(this.body, this.footer);
1719 moduleElement.appendChild(this.body);
1723 if (this.footer && ! Dom.inDocument(this.footer)) {
1724 // There is a footer, but it's not in the DOM yet. Need to add it.
1725 moduleElement.appendChild(this.footer);
1728 this.renderEvent.fire();
1733 * Removes the Module element from the DOM and sets all child elements
1737 destroy: function () {
1742 Event.purgeElement(this.element, true);
1743 parent = this.element.parentNode;
1747 parent.removeChild(this.element);
1750 this.element = null;
1755 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1760 this.destroyEvent.fire();
1764 * Shows the Module element by setting the visible configuration
1765 * property to true. Also fires two events: beforeShowEvent prior to
1766 * the visibility change, and showEvent after.
1770 this.cfg.setProperty("visible", true);
1774 * Hides the Module element by setting the visible configuration
1775 * property to false. Also fires two events: beforeHideEvent prior to
1776 * the visibility change, and hideEvent after.
1780 this.cfg.setProperty("visible", false);
1783 // BUILT-IN EVENT HANDLERS FOR MODULE //
1785 * Default event handler for changing the visibility property of a
1786 * Module. By default, this is achieved by switching the "display" style
1787 * between "block" and "none".
1788 * This method is responsible for firing showEvent and hideEvent.
1789 * @param {String} type The CustomEvent type (usually the property name)
1790 * @param {Object[]} args The CustomEvent arguments. For configuration
1791 * handlers, args[0] will equal the newly applied value for the property.
1792 * @param {Object} obj The scope object. For configuration handlers,
1793 * this will usually equal the owner.
1794 * @method configVisible
1796 configVisible: function (type, args, obj) {
1797 var visible = args[0];
1799 this.beforeShowEvent.fire();
1800 Dom.setStyle(this.element, "display", "block");
1801 this.showEvent.fire();
1803 this.beforeHideEvent.fire();
1804 Dom.setStyle(this.element, "display", "none");
1805 this.hideEvent.fire();
1810 * Default event handler for the "monitorresize" configuration property
1811 * @param {String} type The CustomEvent type (usually the property name)
1812 * @param {Object[]} args The CustomEvent arguments. For configuration
1813 * handlers, args[0] will equal the newly applied value for the property.
1814 * @param {Object} obj The scope object. For configuration handlers,
1815 * this will usually equal the owner.
1816 * @method configMonitorResize
1818 configMonitorResize: function (type, args, obj) {
1819 var monitor = args[0];
1821 this.initResizeMonitor();
1823 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1824 this.resizeMonitor = null;
1829 * This method is a protected helper, used when constructing the DOM structure for the module
1830 * to account for situations which may cause Operation Aborted errors in IE. It should not
1831 * be used for general DOM construction.
1833 * If the parentNode is not document.body, the element is appended as the last element.
1836 * If the parentNode is document.body the element is added as the first child to help
1837 * prevent Operation Aborted errors in IE.
1840 * @param {parentNode} The HTML element to which the element will be added
1841 * @param {element} The HTML element to be added to parentNode's children
1842 * @method _addToParent
1845 _addToParent: function(parentNode, element) {
1846 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1847 parentNode.insertBefore(element, parentNode.firstChild);
1849 parentNode.appendChild(element);
1854 * Returns a String representation of the Object.
1856 * @return {String} The string representation of the Module
1858 toString: function () {
1859 return "Module " + this.id;
1863 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1870 * Overlay is a Module that is absolutely positioned above the page flow. It
1871 * has convenience methods for positioning and sizing, as well as options for
1872 * controlling zIndex and constraining the Overlay's position to the current
1873 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1874 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1875 * properly rendered above SELECT elements.
1876 * @namespace YAHOO.widget
1878 * @extends YAHOO.widget.Module
1879 * @param {String} el The element ID representing the Overlay <em>OR</em>
1880 * @param {HTMLElement} el The element representing the Overlay
1881 * @param {Object} userConfig The configuration object literal containing
1882 * the configuration that should be set for this Overlay. See configuration
1883 * documentation for more details.
1886 YAHOO.widget.Overlay = function (el, userConfig) {
1887 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1890 var Lang = YAHOO.lang,
1891 CustomEvent = YAHOO.util.CustomEvent,
1892 Module = YAHOO.widget.Module,
1893 Event = YAHOO.util.Event,
1894 Dom = YAHOO.util.Dom,
1895 Config = YAHOO.util.Config,
1897 Overlay = YAHOO.widget.Overlay,
1899 _SUBSCRIBE = "subscribe",
1900 _UNSUBSCRIBE = "unsubscribe",
1901 _CONTAINED = "contained",
1906 * Constant representing the name of the Overlay's events
1907 * @property EVENT_TYPES
1913 "BEFORE_MOVE": "beforeMove",
1918 * Constant representing the Overlay's configuration properties
1919 * @property DEFAULT_CONFIG
1928 validator: Lang.isNumber,
1929 suppressEvent: true,
1930 supercedes: ["iframe"]
1935 validator: Lang.isNumber,
1936 suppressEvent: true,
1937 supercedes: ["iframe"]
1942 suppressEvent: true,
1943 supercedes: ["iframe"]
1948 suppressEvent: true,
1949 supercedes: ["iframe"]
1955 supercedes: ["iframe", "visible"]
1960 suppressEvent: true,
1961 supercedes: ["context", "fixedcenter", "iframe"]
1966 suppressEvent: true,
1967 supercedes: ["context", "fixedcenter", "iframe"]
1970 "AUTO_FILL_HEIGHT" : {
1971 key: "autofillheight",
1972 supercedes: ["height"],
1981 "CONSTRAIN_TO_VIEWPORT": {
1982 key: "constraintoviewport",
1984 validator: Lang.isBoolean,
1985 supercedes: ["iframe", "x", "y", "xy"]
1990 value: (UA.ie == 6 ? true : false),
1991 validator: Lang.isBoolean,
1992 supercedes: ["zindex"]
1995 "PREVENT_CONTEXT_OVERLAP": {
1996 key: "preventcontextoverlap",
1998 validator: Lang.isBoolean,
1999 supercedes: ["constraintoviewport"]
2005 * The URL that will be placed in the iframe
2006 * @property YAHOO.widget.Overlay.IFRAME_SRC
2011 Overlay.IFRAME_SRC = "javascript:false;";
2014 * Number representing how much the iframe shim should be offset from each
2015 * side of an Overlay instance, in pixels.
2016 * @property YAHOO.widget.Overlay.IFRAME_SRC
2022 Overlay.IFRAME_OFFSET = 3;
2025 * Number representing the minimum distance an Overlay instance should be
2026 * positioned relative to the boundaries of the browser's viewport, in pixels.
2027 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2033 Overlay.VIEWPORT_OFFSET = 10;
2036 * Constant representing the top left corner of an element, used for
2037 * configuring the context element alignment
2038 * @property YAHOO.widget.Overlay.TOP_LEFT
2043 Overlay.TOP_LEFT = "tl";
2046 * Constant representing the top right corner of an element, used for
2047 * configuring the context element alignment
2048 * @property YAHOO.widget.Overlay.TOP_RIGHT
2053 Overlay.TOP_RIGHT = "tr";
2056 * Constant representing the top bottom left corner of an element, used for
2057 * configuring the context element alignment
2058 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2063 Overlay.BOTTOM_LEFT = "bl";
2066 * Constant representing the bottom right corner of an element, used for
2067 * configuring the context element alignment
2068 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2073 Overlay.BOTTOM_RIGHT = "br";
2076 * Constant representing the default CSS class used for an Overlay
2077 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2082 Overlay.CSS_OVERLAY = "yui-overlay";
2085 * Constant representing the names of the standard module elements
2086 * used in the overlay.
2087 * @property YAHOO.widget.Overlay.STD_MOD_RE
2092 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2095 * A singleton CustomEvent used for reacting to the DOM event for
2097 * @event YAHOO.widget.Overlay.windowScrollEvent
2099 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2102 * A singleton CustomEvent used for reacting to the DOM event for
2104 * @event YAHOO.widget.Overlay.windowResizeEvent
2106 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2109 * The DOM event handler used to fire the CustomEvent for window scroll
2110 * @method YAHOO.widget.Overlay.windowScrollHandler
2112 * @param {DOMEvent} e The DOM scroll event
2114 Overlay.windowScrollHandler = function (e) {
2115 var t = Event.getTarget(e);
2117 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2118 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2119 // - IE doesn't recognize scroll registered on the document.
2121 // Also, when document view is scrolled, IE doesn't provide a target,
2122 // rest of the browsers set target to window.document, apart from opera
2123 // which sets target to window.
2124 if (!t || t === window || t === window.document) {
2127 if (! window.scrollEnd) {
2128 window.scrollEnd = -1;
2131 clearTimeout(window.scrollEnd);
2133 window.scrollEnd = setTimeout(function () {
2134 Overlay.windowScrollEvent.fire();
2138 Overlay.windowScrollEvent.fire();
2144 * The DOM event handler used to fire the CustomEvent for window resize
2145 * @method YAHOO.widget.Overlay.windowResizeHandler
2147 * @param {DOMEvent} e The DOM resize event
2149 Overlay.windowResizeHandler = function (e) {
2152 if (! window.resizeEnd) {
2153 window.resizeEnd = -1;
2156 clearTimeout(window.resizeEnd);
2158 window.resizeEnd = setTimeout(function () {
2159 Overlay.windowResizeEvent.fire();
2162 Overlay.windowResizeEvent.fire();
2167 * A boolean that indicated whether the window resize and scroll events have
2168 * already been subscribed to.
2169 * @property YAHOO.widget.Overlay._initialized
2173 Overlay._initialized = null;
2175 if (Overlay._initialized === null) {
2176 Event.on(window, "scroll", Overlay.windowScrollHandler);
2177 Event.on(window, "resize", Overlay.windowResizeHandler);
2178 Overlay._initialized = true;
2182 * Internal map of special event types, which are provided
2183 * by the instance. It maps the event type to the custom event
2184 * instance. Contains entries for the "windowScroll", "windowResize" and
2185 * "textResize" static container events.
2187 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2192 Overlay._TRIGGER_MAP = {
2193 "windowScroll" : Overlay.windowScrollEvent,
2194 "windowResize" : Overlay.windowResizeEvent,
2195 "textResize" : Module.textResizeEvent
2198 YAHOO.extend(Overlay, Module, {
2202 * Array of default event types which will trigger
2203 * context alignment for the Overlay class.
2205 * <p>The array is empty by default for Overlay,
2206 * but maybe populated in future releases, so classes extending
2207 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2208 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2209 * value with their own array of values.
2213 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2216 * @property CONTEXT_TRIGGERS
2220 CONTEXT_TRIGGERS : [],
2223 * The Overlay initialization method, which is executed for Overlay and
2224 * all of its subclasses. This method is automatically called by the
2225 * constructor, and sets up all DOM references for pre-existing markup,
2226 * and creates required markup if it is not already present.
2228 * @param {String} el The element ID representing the Overlay <em>OR</em>
2229 * @param {HTMLElement} el The element representing the Overlay
2230 * @param {Object} userConfig The configuration object literal
2231 * containing the configuration that should be set for this Overlay.
2232 * See configuration documentation for more details.
2234 init: function (el, userConfig) {
2237 Note that we don't pass the user config in here yet because we
2238 only want it executed once, at the lowest subclass level
2241 Overlay.superclass.init.call(this, el/*, userConfig*/);
2243 this.beforeInitEvent.fire(Overlay);
2245 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2248 this.cfg.applyConfig(userConfig, true);
2251 if (this.platform == "mac" && UA.gecko) {
2253 if (! Config.alreadySubscribed(this.showEvent,
2254 this.showMacGeckoScrollbars, this)) {
2256 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2261 if (! Config.alreadySubscribed(this.hideEvent,
2262 this.hideMacGeckoScrollbars, this)) {
2264 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2270 this.initEvent.fire(Overlay);
2274 * Initializes the custom events for Overlay which are fired
2275 * automatically at appropriate times by the Overlay class.
2276 * @method initEvents
2278 initEvents: function () {
2280 Overlay.superclass.initEvents.call(this);
2282 var SIGNATURE = CustomEvent.LIST;
2285 * CustomEvent fired before the Overlay is moved.
2286 * @event beforeMoveEvent
2287 * @param {Number} x x coordinate
2288 * @param {Number} y y coordinate
2290 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2291 this.beforeMoveEvent.signature = SIGNATURE;
2294 * CustomEvent fired after the Overlay is moved.
2296 * @param {Number} x x coordinate
2297 * @param {Number} y y coordinate
2299 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2300 this.moveEvent.signature = SIGNATURE;
2305 * Initializes the class's configurable properties which can be changed
2306 * using the Overlay's Config object (cfg).
2307 * @method initDefaultConfig
2309 initDefaultConfig: function () {
2311 Overlay.superclass.initDefaultConfig.call(this);
2315 // Add overlay config properties //
2318 * The absolute x-coordinate position of the Overlay
2323 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2325 handler: this.configX,
2326 validator: DEFAULT_CONFIG.X.validator,
2327 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2328 supercedes: DEFAULT_CONFIG.X.supercedes
2333 * The absolute y-coordinate position of the Overlay
2338 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2340 handler: this.configY,
2341 validator: DEFAULT_CONFIG.Y.validator,
2342 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2343 supercedes: DEFAULT_CONFIG.Y.supercedes
2348 * An array with the absolute x and y positions of the Overlay
2353 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2354 handler: this.configXY,
2355 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2356 supercedes: DEFAULT_CONFIG.XY.supercedes
2361 * The array of context arguments for context-sensitive positioning.
2365 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional)]</code>, the
2366 * the 4 array elements described in detail below:
2370 * <dt>contextElementOrId <String|HTMLElement></dt>
2371 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2372 * <dt>overlayCorner <String></dt>
2373 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2374 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2375 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2376 * <dt>contextCorner <String></dt>
2377 * <dd>The corner of the context element which is to be used for alignment. Supported string values are the same ones listed for the "overlayCorner" entry above.</dd>
2378 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2381 * By default, context alignment is a one time operation, aligning the Overlay to the context element when context configuration property is set, or when the <a href="#method_align">align</a>
2382 * method is invoked. However, you can use the optional "arrayOfTriggerEvents" entry to define the list of events which should force the overlay to re-align itself with the context element.
2383 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2386 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2387 * 3 static container event types are also currently supported : <code>"windowResize", "windowScroll", "textResize"</code> (defined in <a href="#property__TRIGGER_MAP">_TRIGGER_MAP</a> private property).
2393 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2394 * align the Overlay's top left corner to the bottom left corner of the
2395 * context element with id "img1".
2398 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"]]</code>,
2399 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2406 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2407 handler: this.configContext,
2408 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2409 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2413 * Determines whether or not the Overlay should be anchored
2414 * to the center of the viewport.
2416 * <p>This property can be set to:</p>
2421 * To enable fixed center positioning
2423 * When enabled, the overlay will
2424 * be positioned in the center of viewport when initially displayed, and
2425 * will remain in the center of the viewport whenever the window is
2426 * scrolled or resized.
2429 * If the overlay is too big for the viewport,
2430 * it's top left corner will be aligned with the top left corner of the viewport.
2435 * To disable fixed center positioning.
2436 * <p>In this case the overlay can still be
2437 * centered as a one-off operation, by invoking the <code>center()</code> method,
2438 * however it will not remain centered when the window is scrolled/resized.
2440 * <dt>"contained"<dt>
2441 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2442 * <p>However, unlike setting the property to <code>true</code>,
2443 * when the property is set to <code>"contained"</code>, if the overlay is
2444 * too big for the viewport, it will not get automatically centered when the
2445 * user scrolls or resizes the window (until the window is large enough to contain the
2446 * overlay). This is useful in cases where the Overlay has both header and footer
2447 * UI controls which the user may need to access.
2452 * @config fixedcenter
2453 * @type Boolean | String
2456 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2457 handler: this.configFixedCenter,
2458 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2459 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2460 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2464 * CSS width of the Overlay.
2469 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2470 handler: this.configWidth,
2471 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2472 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2476 * CSS height of the Overlay.
2481 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2482 handler: this.configHeight,
2483 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2484 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2488 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2489 * Supported values are "header", "body", "footer".
2491 * @config autofillheight
2495 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2496 handler: this.configAutoFillHeight,
2497 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2498 validator : this._validateAutoFill,
2499 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2503 * CSS z-index of the Overlay.
2508 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2509 handler: this.configzIndex,
2510 value: DEFAULT_CONFIG.ZINDEX.value
2514 * True if the Overlay should be prevented from being positioned
2515 * out of the viewport.
2516 * @config constraintoviewport
2520 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2522 handler: this.configConstrainToViewport,
2523 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2524 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2525 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2531 * @description Boolean indicating whether or not the Overlay should
2532 * have an IFRAME shim; used to prevent SELECT elements from
2533 * poking through an Overlay instance in IE6. When set to "true",
2534 * the iframe shim is created when the Overlay instance is intially
2537 * @default true for IE6 and below, false for all other browsers.
2539 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2541 handler: this.configIframe,
2542 value: DEFAULT_CONFIG.IFRAME.value,
2543 validator: DEFAULT_CONFIG.IFRAME.validator,
2544 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2549 * @config preventcontextoverlap
2550 * @description Boolean indicating whether or not the Overlay should overlap its
2551 * context element (defined using the "context" configuration property) when the
2552 * "constraintoviewport" configuration property is set to "true".
2556 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2558 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2559 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2560 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2567 * Moves the Overlay to the specified position. This function is
2568 * identical to calling this.cfg.setProperty("xy", [x,y]);
2570 * @param {Number} x The Overlay's new x position
2571 * @param {Number} y The Overlay's new y position
2573 moveTo: function (x, y) {
2574 this.cfg.setProperty("xy", [x, y]);
2578 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2579 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2580 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2581 * @method hideMacGeckoScrollbars
2583 hideMacGeckoScrollbars: function () {
2584 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2588 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2589 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2590 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2591 * @method showMacGeckoScrollbars
2593 showMacGeckoScrollbars: function () {
2594 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2598 * Internal implementation to set the visibility of the overlay in the DOM.
2600 * @method _setDomVisibility
2601 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2604 _setDomVisibility : function(show) {
2605 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2608 Dom.removeClass(this.element, "yui-overlay-hidden");
2610 Dom.addClass(this.element, "yui-overlay-hidden");
2614 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2616 * The default event handler fired when the "visible" property is
2617 * changed. This method is responsible for firing showEvent
2619 * @method configVisible
2620 * @param {String} type The CustomEvent type (usually the property name)
2621 * @param {Object[]} args The CustomEvent arguments. For configuration
2622 * handlers, args[0] will equal the newly applied value for the property.
2623 * @param {Object} obj The scope object. For configuration handlers,
2624 * this will usually equal the owner.
2626 configVisible: function (type, args, obj) {
2628 var visible = args[0],
2629 currentVis = Dom.getStyle(this.element, "visibility"),
2630 effect = this.cfg.getProperty("effect"),
2631 effectInstances = [],
2632 isMacGecko = (this.platform == "mac" && UA.gecko),
2633 alreadySubscribed = Config.alreadySubscribed,
2634 eff, ei, e, i, j, k, h,
2638 if (currentVis == "inherit") {
2639 e = this.element.parentNode;
2641 while (e.nodeType != 9 && e.nodeType != 11) {
2642 currentVis = Dom.getStyle(e, "visibility");
2644 if (currentVis != "inherit") {
2651 if (currentVis == "inherit") {
2652 currentVis = "visible";
2657 if (effect instanceof Array) {
2658 nEffects = effect.length;
2660 for (i = 0; i < nEffects; i++) {
2662 effectInstances[effectInstances.length] =
2663 eff.effect(this, eff.duration);
2667 effectInstances[effectInstances.length] =
2668 effect.effect(this, effect.duration);
2672 if (visible) { // Show
2674 this.showMacGeckoScrollbars();
2677 if (effect) { // Animate in
2678 if (visible) { // Animate in if not showing
2679 if (currentVis != "visible" || currentVis === "") {
2680 this.beforeShowEvent.fire();
2681 nEffectInstances = effectInstances.length;
2683 for (j = 0; j < nEffectInstances; j++) {
2684 ei = effectInstances[j];
2685 if (j === 0 && !alreadySubscribed(
2686 ei.animateInCompleteEvent,
2687 this.showEvent.fire, this.showEvent)) {
2690 Delegate showEvent until end
2691 of animateInComplete
2694 ei.animateInCompleteEvent.subscribe(
2695 this.showEvent.fire, this.showEvent, true);
2702 if (currentVis != "visible" || currentVis === "") {
2703 this.beforeShowEvent.fire();
2705 this._setDomVisibility(true);
2707 this.cfg.refireEvent("iframe");
2708 this.showEvent.fire();
2710 this._setDomVisibility(true);
2716 this.hideMacGeckoScrollbars();
2719 if (effect) { // Animate out if showing
2720 if (currentVis == "visible") {
2721 this.beforeHideEvent.fire();
2723 nEffectInstances = effectInstances.length;
2724 for (k = 0; k < nEffectInstances; k++) {
2725 h = effectInstances[k];
2727 if (k === 0 && !alreadySubscribed(
2728 h.animateOutCompleteEvent, this.hideEvent.fire,
2732 Delegate hideEvent until end
2733 of animateOutComplete
2736 h.animateOutCompleteEvent.subscribe(
2737 this.hideEvent.fire, this.hideEvent, true);
2743 } else if (currentVis === "") {
2744 this._setDomVisibility(false);
2747 } else { // Simple hide
2749 if (currentVis == "visible" || currentVis === "") {
2750 this.beforeHideEvent.fire();
2751 this._setDomVisibility(false);
2752 this.hideEvent.fire();
2754 this._setDomVisibility(false);
2761 * Fixed center event handler used for centering on scroll/resize, but only if
2762 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2763 * the overlay fits within the viewport.
2765 * @method doCenterOnDOMEvent
2767 doCenterOnDOMEvent: function () {
2769 fc = cfg.getProperty("fixedcenter");
2771 if (cfg.getProperty("visible")) {
2772 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2779 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2780 * will fit entirely inside the viewport, in both dimensions - width and height.
2782 * @method fitsInViewport
2783 * @return boolean true if the Overlay will fit, false if not
2785 fitsInViewport : function() {
2786 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2787 element = this.element,
2788 elementWidth = element.offsetWidth,
2789 elementHeight = element.offsetHeight,
2790 viewportWidth = Dom.getViewportWidth(),
2791 viewportHeight = Dom.getViewportHeight();
2793 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2797 * The default event handler fired when the "fixedcenter" property
2799 * @method configFixedCenter
2800 * @param {String} type The CustomEvent type (usually the property name)
2801 * @param {Object[]} args The CustomEvent arguments. For configuration
2802 * handlers, args[0] will equal the newly applied value for the property.
2803 * @param {Object} obj The scope object. For configuration handlers,
2804 * this will usually equal the owner.
2806 configFixedCenter: function (type, args, obj) {
2809 alreadySubscribed = Config.alreadySubscribed,
2810 windowResizeEvent = Overlay.windowResizeEvent,
2811 windowScrollEvent = Overlay.windowScrollEvent;
2816 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2817 this.beforeShowEvent.subscribe(this.center);
2820 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2821 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2824 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2825 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2829 this.beforeShowEvent.unsubscribe(this.center);
2831 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2832 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2837 * The default event handler fired when the "height" property is changed.
2838 * @method configHeight
2839 * @param {String} type The CustomEvent type (usually the property name)
2840 * @param {Object[]} args The CustomEvent arguments. For configuration
2841 * handlers, args[0] will equal the newly applied value for the property.
2842 * @param {Object} obj The scope object. For configuration handlers,
2843 * this will usually equal the owner.
2845 configHeight: function (type, args, obj) {
2847 var height = args[0],
2850 Dom.setStyle(el, "height", height);
2851 this.cfg.refireEvent("iframe");
2855 * The default event handler fired when the "autofillheight" property is changed.
2856 * @method configAutoFillHeight
2858 * @param {String} type The CustomEvent type (usually the property name)
2859 * @param {Object[]} args The CustomEvent arguments. For configuration
2860 * handlers, args[0] will equal the newly applied value for the property.
2861 * @param {Object} obj The scope object. For configuration handlers,
2862 * this will usually equal the owner.
2864 configAutoFillHeight: function (type, args, obj) {
2865 var fillEl = args[0],
2867 autoFillHeight = "autofillheight",
2869 currEl = cfg.getProperty(autoFillHeight),
2870 autoFill = this._autoFillOnHeightChange;
2872 cfg.unsubscribeFromConfigEvent(height, autoFill);
2873 Module.textResizeEvent.unsubscribe(autoFill);
2874 this.changeContentEvent.unsubscribe(autoFill);
2876 if (currEl && fillEl !== currEl && this[currEl]) {
2877 Dom.setStyle(this[currEl], height, "");
2881 fillEl = Lang.trim(fillEl.toLowerCase());
2883 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
2884 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
2885 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
2887 cfg.setProperty(autoFillHeight, fillEl, true);
2892 * The default event handler fired when the "width" property is changed.
2893 * @method configWidth
2894 * @param {String} type The CustomEvent type (usually the property name)
2895 * @param {Object[]} args The CustomEvent arguments. For configuration
2896 * handlers, args[0] will equal the newly applied value for the property.
2897 * @param {Object} obj The scope object. For configuration handlers,
2898 * this will usually equal the owner.
2900 configWidth: function (type, args, obj) {
2902 var width = args[0],
2905 Dom.setStyle(el, "width", width);
2906 this.cfg.refireEvent("iframe");
2910 * The default event handler fired when the "zIndex" property is changed.
2911 * @method configzIndex
2912 * @param {String} type The CustomEvent type (usually the property name)
2913 * @param {Object[]} args The CustomEvent arguments. For configuration
2914 * handlers, args[0] will equal the newly applied value for the property.
2915 * @param {Object} obj The scope object. For configuration handlers,
2916 * this will usually equal the owner.
2918 configzIndex: function (type, args, obj) {
2920 var zIndex = args[0],
2924 zIndex = Dom.getStyle(el, "zIndex");
2925 if (! zIndex || isNaN(zIndex)) {
2930 if (this.iframe || this.cfg.getProperty("iframe") === true) {
2936 Dom.setStyle(el, "zIndex", zIndex);
2937 this.cfg.setProperty("zIndex", zIndex, true);
2945 * The default event handler fired when the "xy" property is changed.
2947 * @param {String} type The CustomEvent type (usually the property name)
2948 * @param {Object[]} args The CustomEvent arguments. For configuration
2949 * handlers, args[0] will equal the newly applied value for the property.
2950 * @param {Object} obj The scope object. For configuration handlers,
2951 * this will usually equal the owner.
2953 configXY: function (type, args, obj) {
2959 this.cfg.setProperty("x", x);
2960 this.cfg.setProperty("y", y);
2962 this.beforeMoveEvent.fire([x, y]);
2964 x = this.cfg.getProperty("x");
2965 y = this.cfg.getProperty("y");
2967 YAHOO.log(("xy: " + [x, y]), "iframe");
2969 this.cfg.refireEvent("iframe");
2970 this.moveEvent.fire([x, y]);
2974 * The default event handler fired when the "x" property is changed.
2976 * @param {String} type The CustomEvent type (usually the property name)
2977 * @param {Object[]} args The CustomEvent arguments. For configuration
2978 * handlers, args[0] will equal the newly applied value for the property.
2979 * @param {Object} obj The scope object. For configuration handlers,
2980 * this will usually equal the owner.
2982 configX: function (type, args, obj) {
2985 y = this.cfg.getProperty("y");
2987 this.cfg.setProperty("x", x, true);
2988 this.cfg.setProperty("y", y, true);
2990 this.beforeMoveEvent.fire([x, y]);
2992 x = this.cfg.getProperty("x");
2993 y = this.cfg.getProperty("y");
2995 Dom.setX(this.element, x, true);
2997 this.cfg.setProperty("xy", [x, y], true);
2999 this.cfg.refireEvent("iframe");
3000 this.moveEvent.fire([x, y]);
3004 * The default event handler fired when the "y" property is changed.
3006 * @param {String} type The CustomEvent type (usually the property name)
3007 * @param {Object[]} args The CustomEvent arguments. For configuration
3008 * handlers, args[0] will equal the newly applied value for the property.
3009 * @param {Object} obj The scope object. For configuration handlers,
3010 * this will usually equal the owner.
3012 configY: function (type, args, obj) {
3014 var x = this.cfg.getProperty("x"),
3017 this.cfg.setProperty("x", x, true);
3018 this.cfg.setProperty("y", y, true);
3020 this.beforeMoveEvent.fire([x, y]);
3022 x = this.cfg.getProperty("x");
3023 y = this.cfg.getProperty("y");
3025 Dom.setY(this.element, y, true);
3027 this.cfg.setProperty("xy", [x, y], true);
3029 this.cfg.refireEvent("iframe");
3030 this.moveEvent.fire([x, y]);
3034 * Shows the iframe shim, if it has been enabled.
3035 * @method showIframe
3037 showIframe: function () {
3039 var oIFrame = this.iframe,
3043 oParentNode = this.element.parentNode;
3045 if (oParentNode != oIFrame.parentNode) {
3046 this._addToParent(oParentNode, oIFrame);
3048 oIFrame.style.display = "block";
3053 * Hides the iframe shim, if it has been enabled.
3054 * @method hideIframe
3056 hideIframe: function () {
3058 this.iframe.style.display = "none";
3063 * Syncronizes the size and position of iframe shim to that of its
3064 * corresponding Overlay instance.
3065 * @method syncIframe
3067 syncIframe: function () {
3069 var oIFrame = this.iframe,
3070 oElement = this.element,
3071 nOffset = Overlay.IFRAME_OFFSET,
3072 nDimensionOffset = (nOffset * 2),
3077 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3078 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3080 // Position <iframe>
3081 aXY = this.cfg.getProperty("xy");
3083 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3084 this.syncPosition();
3085 aXY = this.cfg.getProperty("xy");
3087 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3092 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3093 * the Overlay element. The zindex of the iframe is set to be one less
3094 * than the Overlay element's zindex.
3096 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3097 * to ensure that the iframe shim has a non-negative zindex.
3098 * If you require the iframe zindex to be 0 or higher, the zindex of
3099 * the Overlay element should be set to a value greater than 0, before
3100 * this method is called.
3102 * @method stackIframe
3104 stackIframe: function () {
3106 var overlayZ = Dom.getStyle(this.element, "zIndex");
3107 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3108 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3114 * The default event handler fired when the "iframe" property is changed.
3115 * @method configIframe
3116 * @param {String} type The CustomEvent type (usually the property name)
3117 * @param {Object[]} args The CustomEvent arguments. For configuration
3118 * handlers, args[0] will equal the newly applied value for the property.
3119 * @param {Object} obj The scope object. For configuration handlers,
3120 * this will usually equal the owner.
3122 configIframe: function (type, args, obj) {
3124 var bIFrame = args[0];
3126 function createIFrame() {
3128 var oIFrame = this.iframe,
3129 oElement = this.element,
3133 if (!m_oIFrameTemplate) {
3134 m_oIFrameTemplate = document.createElement("iframe");
3136 if (this.isSecure) {
3137 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3141 Set the opacity of the <iframe> to 0 so that it
3142 doesn't modify the opacity of any transparent
3143 elements that may be on top of it (like a shadow).
3146 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3148 Need to set the "frameBorder" property to 0
3149 supress the default <iframe> border in IE.
3150 Setting the CSS "border" property alone
3153 m_oIFrameTemplate.frameBorder = 0;
3156 m_oIFrameTemplate.style.opacity = "0";
3159 m_oIFrameTemplate.style.position = "absolute";
3160 m_oIFrameTemplate.style.border = "none";
3161 m_oIFrameTemplate.style.margin = "0";
3162 m_oIFrameTemplate.style.padding = "0";
3163 m_oIFrameTemplate.style.display = "none";
3164 m_oIFrameTemplate.tabIndex = -1;
3167 oIFrame = m_oIFrameTemplate.cloneNode(false);
3168 oParent = oElement.parentNode;
3170 var parentNode = oParent || document.body;
3172 this._addToParent(parentNode, oIFrame);
3173 this.iframe = oIFrame;
3177 Show the <iframe> before positioning it since the "setXY"
3178 method of DOM requires the element be in the document
3184 Syncronize the size and position of the <iframe> to that
3190 // Add event listeners to update the <iframe> when necessary
3191 if (!this._hasIframeEventListeners) {
3192 this.showEvent.subscribe(this.showIframe);
3193 this.hideEvent.subscribe(this.hideIframe);
3194 this.changeContentEvent.subscribe(this.syncIframe);
3196 this._hasIframeEventListeners = true;
3200 function onBeforeShow() {
3201 createIFrame.call(this);
3202 this.beforeShowEvent.unsubscribe(onBeforeShow);
3203 this._iframeDeferred = false;
3206 if (bIFrame) { // <iframe> shim is enabled
3208 if (this.cfg.getProperty("visible")) {
3209 createIFrame.call(this);
3211 if (!this._iframeDeferred) {
3212 this.beforeShowEvent.subscribe(onBeforeShow);
3213 this._iframeDeferred = true;
3217 } else { // <iframe> shim is disabled
3220 if (this._hasIframeEventListeners) {
3221 this.showEvent.unsubscribe(this.showIframe);
3222 this.hideEvent.unsubscribe(this.hideIframe);
3223 this.changeContentEvent.unsubscribe(this.syncIframe);
3225 this._hasIframeEventListeners = false;
3231 * Set's the container's XY value from DOM if not already set.
3233 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3234 * not already set. The method also refire's the XY config property event, so any
3235 * beforeMove, Move event listeners are invoked.
3237 * @method _primeXYFromDOM
3240 _primeXYFromDOM : function() {
3241 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3242 // Set CFG XY based on DOM XY
3243 this.syncPosition();
3244 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3245 this.cfg.refireEvent("xy");
3246 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3251 * The default event handler fired when the "constraintoviewport"
3252 * property is changed.
3253 * @method configConstrainToViewport
3254 * @param {String} type The CustomEvent type (usually the property name)
3255 * @param {Object[]} args The CustomEvent arguments. For configuration
3256 * handlers, args[0] will equal the newly applied value for
3258 * @param {Object} obj The scope object. For configuration handlers,
3259 * this will usually equal the owner.
3261 configConstrainToViewport: function (type, args, obj) {
3265 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3266 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3268 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3269 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3272 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3273 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3278 * The default event handler fired when the "context" property
3281 * @method configContext
3282 * @param {String} type The CustomEvent type (usually the property name)
3283 * @param {Object[]} args The CustomEvent arguments. For configuration
3284 * handlers, args[0] will equal the newly applied value for the property.
3285 * @param {Object} obj The scope object. For configuration handlers,
3286 * this will usually equal the owner.
3288 configContext: function (type, args, obj) {
3290 var contextArgs = args[0],
3292 elementMagnetCorner,
3293 contextMagnetCorner,
3295 defTriggers = this.CONTEXT_TRIGGERS;
3299 contextEl = contextArgs[0];
3300 elementMagnetCorner = contextArgs[1];
3301 contextMagnetCorner = contextArgs[2];
3302 triggers = contextArgs[3];
3304 if (defTriggers && defTriggers.length > 0) {
3305 triggers = (triggers || []).concat(defTriggers);
3309 if (typeof contextEl == "string") {
3310 this.cfg.setProperty("context", [
3311 document.getElementById(contextEl),
3312 elementMagnetCorner,
3313 contextMagnetCorner,
3318 if (elementMagnetCorner && contextMagnetCorner) {
3319 this.align(elementMagnetCorner, contextMagnetCorner);
3322 if (this._contextTriggers) {
3323 // Unsubscribe Old Set
3324 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3328 // Subscribe New Set
3329 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3330 this._contextTriggers = triggers;
3337 * Custom Event handler for context alignment triggers. Invokes the align method
3339 * @method _alignOnTrigger
3342 * @param {String} type The event type (not used by the default implementation)
3343 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3345 _alignOnTrigger: function(type, args) {
3350 * Helper method to locate the custom event instance for the event name string
3351 * passed in. As a convenience measure, any custom events passed in are returned.
3353 * @method _findTriggerCE
3356 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3357 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3359 _findTriggerCE : function(t) {
3361 if (t instanceof CustomEvent) {
3363 } else if (Overlay._TRIGGER_MAP[t]) {
3364 tce = Overlay._TRIGGER_MAP[t];
3370 * Utility method that subscribes or unsubscribes the given
3371 * function from the list of trigger events provided.
3373 * @method _processTriggers
3376 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3377 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3378 * subscribed/unsubscribed respectively.
3380 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3381 * we are subscribing or unsubscribing trigger listeners
3383 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3384 * Context is always set to the overlay instance, and no additional object argument
3385 * get passed to the subscribed function.
3387 _processTriggers : function(triggers, mode, fn) {
3390 for (var i = 0, l = triggers.length; i < l; ++i) {
3392 tce = this._findTriggerCE(t);
3394 tce[mode](fn, this, true);
3401 // END BUILT-IN PROPERTY EVENT HANDLERS //
3403 * Aligns the Overlay to its context element using the specified corner
3404 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3407 * @param {String} elementAlign The String representing the corner of
3408 * the Overlay that should be aligned to the context element
3409 * @param {String} contextAlign The corner of the context element
3410 * that the elementAlign corner should stick to.
3412 align: function (elementAlign, contextAlign) {
3414 var contextArgs = this.cfg.getProperty("context"),
3420 function doAlign(v, h) {
3422 switch (elementAlign) {
3424 case Overlay.TOP_LEFT:
3428 case Overlay.TOP_RIGHT:
3429 me.moveTo((h - element.offsetWidth), v);
3432 case Overlay.BOTTOM_LEFT:
3433 me.moveTo(h, (v - element.offsetHeight));
3436 case Overlay.BOTTOM_RIGHT:
3437 me.moveTo((h - element.offsetWidth),
3438 (v - element.offsetHeight));
3446 context = contextArgs[0];
3447 element = this.element;
3450 if (! elementAlign) {
3451 elementAlign = contextArgs[1];
3454 if (! contextAlign) {
3455 contextAlign = contextArgs[2];
3458 if (element && context) {
3459 contextRegion = Dom.getRegion(context);
3461 switch (contextAlign) {
3463 case Overlay.TOP_LEFT:
3464 doAlign(contextRegion.top, contextRegion.left);
3467 case Overlay.TOP_RIGHT:
3468 doAlign(contextRegion.top, contextRegion.right);
3471 case Overlay.BOTTOM_LEFT:
3472 doAlign(contextRegion.bottom, contextRegion.left);
3475 case Overlay.BOTTOM_RIGHT:
3476 doAlign(contextRegion.bottom, contextRegion.right);
3487 * The default event handler executed when the moveEvent is fired, if the
3488 * "constraintoviewport" is set to true.
3489 * @method enforceConstraints
3490 * @param {String} type The CustomEvent type (usually the property name)
3491 * @param {Object[]} args The CustomEvent arguments. For configuration
3492 * handlers, args[0] will equal the newly applied value for the property.
3493 * @param {Object} obj The scope object. For configuration handlers,
3494 * this will usually equal the owner.
3496 enforceConstraints: function (type, args, obj) {
3499 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3500 this.cfg.setProperty("x", cXY[0], true);
3501 this.cfg.setProperty("y", cXY[1], true);
3502 this.cfg.setProperty("xy", cXY, true);
3507 * Given x coordinate value, returns the calculated x coordinate required to
3508 * position the Overlay if it is to be constrained to the viewport, based on the
3509 * current element size, viewport dimensions and scroll values.
3511 * @param {Number} x The X coordinate value to be constrained
3512 * @return {Number} The constrained x coordinate
3514 getConstrainedX: function (x) {
3516 var oOverlay = this,
3517 oOverlayEl = oOverlay.element,
3518 nOverlayOffsetWidth = oOverlayEl.offsetWidth,
3520 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3521 viewPortWidth = Dom.getViewportWidth(),
3522 scrollX = Dom.getDocumentScrollLeft(),
3524 bCanConstrain = (nOverlayOffsetWidth + nViewportOffset < viewPortWidth),
3526 aContext = this.cfg.getProperty("context"),
3536 leftConstraint = scrollX + nViewportOffset,
3537 rightConstraint = scrollX + viewPortWidth - nOverlayOffsetWidth - nViewportOffset,
3541 oOverlapPositions = {
3551 var flipHorizontal = function () {
3555 if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
3556 nNewX = (nContextElX - nOverlayOffsetWidth);
3559 nNewX = (nContextElX + nContextElWidth);
3563 oOverlay.cfg.setProperty("x", (nNewX + scrollX), true);
3572 Uses the context element's position to calculate the availble width
3573 to the right and left of it to display its corresponding Overlay.
3576 var getDisplayRegionWidth = function () {
3578 // The Overlay is to the right of the context element
3580 if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
3581 return (nRightRegionWidth - nViewportOffset);
3583 else { // The Overlay is to the left of the context element
3584 return (nLeftRegionWidth - nViewportOffset);
3591 Positions the Overlay to the left or right of the context element so that it remains
3592 inside the viewport.
3595 var setHorizontalPosition = function () {
3597 var nDisplayRegionWidth = getDisplayRegionWidth(),
3600 if (nOverlayOffsetWidth > nDisplayRegionWidth) {
3605 All possible positions and values have been
3606 tried, but none were successful, so fall back
3607 to the original size and position.
3619 fnReturnVal = setHorizontalPosition();
3629 // Determine if the current value for the Overlay's "x" configuration property will
3630 // result in the Overlay being positioned outside the boundaries of the viewport
3632 if (x < leftConstraint || x > rightConstraint) {
3634 // The current value for the Overlay's "x" configuration property WILL
3635 // result in the Overlay being positioned outside the boundaries of the viewport
3637 if (bCanConstrain) {
3639 // If the "preventcontextoverlap" configuration property is set to "true",
3640 // try to flip the Overlay to both keep it inside the boundaries of the
3641 // viewport AND from overlaping its context element.
3643 if (this.cfg.getProperty("preventcontextoverlap") && aContext &&
3644 oOverlapPositions[(aContext[1] + aContext[2])]) {
3646 oContextEl = aContext[0];
3647 nContextElX = Dom.getX(oContextEl) - scrollX;
3648 nContextElWidth = oContextEl.offsetWidth;
3649 nLeftRegionWidth = nContextElX;
3650 nRightRegionWidth = (viewPortWidth - (nContextElX + nContextElWidth));
3652 setHorizontalPosition();
3654 xNew = this.cfg.getProperty("x");
3659 if (x < leftConstraint) {
3660 xNew = leftConstraint;
3661 } else if (x > rightConstraint) {
3662 xNew = rightConstraint;
3668 // The "x" configuration property cannot be set to a value that will keep
3669 // entire Overlay inside the boundary of the viewport. Therefore, set
3670 // the "x" configuration property to scrollY to keep as much of the
3671 // Overlay inside the viewport as possible.
3672 xNew = nViewportOffset + scrollX;
3683 * Given y coordinate value, returns the calculated y coordinate required to
3684 * position the Overlay if it is to be constrained to the viewport, based on the
3685 * current element size, viewport dimensions and scroll values.
3687 * @param {Number} y The Y coordinate value to be constrained
3688 * @return {Number} The constrained y coordinate
3690 getConstrainedY: function (y) {
3692 var oOverlay = this,
3693 oOverlayEl = oOverlay.element,
3694 nOverlayOffsetHeight = oOverlayEl.offsetHeight,
3696 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3697 viewPortHeight = Dom.getViewportHeight(),
3698 scrollY = Dom.getDocumentScrollTop(),
3700 bCanConstrain = (nOverlayOffsetHeight + nViewportOffset < viewPortHeight),
3702 aContext = this.cfg.getProperty("context"),
3710 nBottomRegionHeight,
3712 topConstraint = scrollY + nViewportOffset,
3713 bottomConstraint = scrollY + viewPortHeight - nOverlayOffsetHeight - nViewportOffset,
3717 oOverlapPositions = {
3725 var flipVertical = function () {
3729 // The Overlay is below the context element, flip it above
3730 if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
3731 nNewY = (nContextElY - nOverlayOffsetHeight);
3733 else { // The Overlay is above the context element, flip it below
3734 nNewY = (nContextElY + nContextElHeight);
3737 oOverlay.cfg.setProperty("y", (nNewY + scrollY), true);
3745 Uses the context element's position to calculate the availble height
3746 above and below it to display its corresponding Overlay.
3749 var getDisplayRegionHeight = function () {
3751 // The Overlay is below the context element
3752 if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
3753 return (nBottomRegionHeight - nViewportOffset);
3755 else { // The Overlay is above the context element
3756 return (nTopRegionHeight - nViewportOffset);
3763 Trys to place the Overlay in the best possible position (either above or
3764 below its corresponding context element).
3767 var setVerticalPosition = function () {
3769 var nDisplayRegionHeight = getDisplayRegionHeight(),
3773 if (nOverlayOffsetHeight > nDisplayRegionHeight) {
3778 All possible positions and values for the
3779 "maxheight" configuration property have been
3780 tried, but none were successful, so fall back
3781 to the original size and position.
3793 fnReturnVal = setVerticalPosition();
3804 // Determine if the current value for the Overlay's "y" configuration property will
3805 // result in the Overlay being positioned outside the boundaries of the viewport
3807 if (y < topConstraint || y > bottomConstraint) {
3809 // The current value for the Overlay's "y" configuration property WILL
3810 // result in the Overlay being positioned outside the boundaries of the viewport
3812 if (bCanConstrain) {
3814 // If the "preventcontextoverlap" configuration property is set to "true",
3815 // try to flip the Overlay to both keep it inside the boundaries of the
3816 // viewport AND from overlaping its context element.
3818 if (this.cfg.getProperty("preventcontextoverlap") && aContext &&
3819 oOverlapPositions[(aContext[1] + aContext[2])]) {
3821 oContextEl = aContext[0];
3822 nContextElHeight = oContextEl.offsetHeight;
3823 nContextElY = (Dom.getY(oContextEl) - scrollY);
3825 nTopRegionHeight = nContextElY;
3826 nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
3828 setVerticalPosition();
3830 yNew = oOverlay.cfg.getProperty("y");
3835 if (y < topConstraint) {
3836 yNew = topConstraint;
3837 } else if (y > bottomConstraint) {
3838 yNew = bottomConstraint;
3846 // The "y" configuration property cannot be set to a value that will keep
3847 // entire Overlay inside the boundary of the viewport. Therefore, set
3848 // the "y" configuration property to scrollY to keep as much of the
3849 // Overlay inside the viewport as possible.
3851 yNew = nViewportOffset + scrollY;
3861 * Given x, y coordinate values, returns the calculated coordinates required to
3862 * position the Overlay if it is to be constrained to the viewport, based on the
3863 * current element size, viewport dimensions and scroll values.
3865 * @param {Number} x The X coordinate value to be constrained
3866 * @param {Number} y The Y coordinate value to be constrained
3867 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3869 getConstrainedXY: function(x, y) {
3870 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3874 * Centers the container in the viewport.
3877 center: function () {
3879 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3880 elementWidth = this.element.offsetWidth,
3881 elementHeight = this.element.offsetHeight,
3882 viewPortWidth = Dom.getViewportWidth(),
3883 viewPortHeight = Dom.getViewportHeight(),
3887 if (elementWidth < viewPortWidth) {
3888 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3890 x = nViewportOffset + Dom.getDocumentScrollLeft();
3893 if (elementHeight < viewPortHeight) {
3894 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3896 y = nViewportOffset + Dom.getDocumentScrollTop();
3899 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3900 this.cfg.refireEvent("iframe");
3903 this.forceContainerRedraw();
3908 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3909 * Panel's position in the DOM. This is primarily used to update
3910 * position information during drag & drop.
3911 * @method syncPosition
3913 syncPosition: function () {
3915 var pos = Dom.getXY(this.element);
3917 this.cfg.setProperty("x", pos[0], true);
3918 this.cfg.setProperty("y", pos[1], true);
3919 this.cfg.setProperty("xy", pos, true);
3924 * Event handler fired when the resize monitor element is resized.
3925 * @method onDomResize
3926 * @param {DOMEvent} e The resize DOM event
3927 * @param {Object} obj The scope object
3929 onDomResize: function (e, obj) {
3933 Overlay.superclass.onDomResize.call(this, e, obj);
3935 setTimeout(function () {
3937 me.cfg.refireEvent("iframe");
3938 me.cfg.refireEvent("context");
3943 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3945 * @method _getComputedHeight
3947 * @param {HTMLElement} el The element for which the content height needs to be determined
3948 * @return {Number} The content box height of the given element, or null if it could not be determined.
3950 _getComputedHeight : (function() {
3952 if (document.defaultView && document.defaultView.getComputedStyle) {
3953 return function(el) {
3955 if (el.ownerDocument && el.ownerDocument.defaultView) {
3956 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3958 height = parseInt(computed.height, 10);
3961 return (Lang.isNumber(height)) ? height : null;
3964 return function(el) {
3966 if (el.style.pixelHeight) {
3967 height = el.style.pixelHeight;
3969 return (Lang.isNumber(height)) ? height : null;
3975 * autofillheight validator. Verifies that the autofill value is either null
3976 * or one of the strings : "body", "header" or "footer".
3978 * @method _validateAutoFillHeight
3980 * @param {String} val
3981 * @return true, if valid, false otherwise
3983 _validateAutoFillHeight : function(val) {
3984 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3988 * The default custom event handler executed when the overlay's height is changed,
3989 * if the autofillheight property has been set.
3991 * @method _autoFillOnHeightChange
3993 * @param {String} type The event type
3994 * @param {Array} args The array of arguments passed to event subscribers
3995 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3996 * out the containers height
3998 _autoFillOnHeightChange : function(type, args, el) {
3999 var height = this.cfg.getProperty("height");
4000 if ((height && height !== "auto") || (height === 0)) {
4001 this.fillHeight(el);
4006 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
4007 * otherwise returns the offsetHeight
4008 * @method _getPreciseHeight
4010 * @param {HTMLElement} el
4011 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
4013 _getPreciseHeight : function(el) {
4014 var height = el.offsetHeight;
4016 if (el.getBoundingClientRect) {
4017 var rect = el.getBoundingClientRect();
4018 height = rect.bottom - rect.top;
4026 * Sets the height on the provided header, body or footer element to
4027 * fill out the height of the container. It determines the height of the
4028 * containers content box, based on it's configured height value, and
4029 * sets the height of the autofillheight element to fill out any
4030 * space remaining after the other standard module element heights
4031 * have been accounted for.
4033 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
4034 * height has not been set on the container, since for an "auto" height container,
4035 * the heights of the header/body/footer will drive the height of the container.</p>
4037 * @method fillHeight
4038 * @param {HTMLElement} el The element which should be resized to fill out the height
4039 * of the container element.
4041 fillHeight : function(el) {
4043 var container = this.innerElement || this.element,
4044 containerEls = [this.header, this.body, this.footer],
4051 for (var i = 0, l = containerEls.length; i < l; i++) {
4052 containerEl = containerEls[i];
4054 if (el !== containerEl) {
4055 filled += this._getPreciseHeight(containerEl);
4064 if (UA.ie || UA.opera) {
4065 // Need to set height to 0, to allow height to be reduced
4066 Dom.setStyle(el, 'height', 0 + 'px');
4069 total = this._getComputedHeight(container);
4071 // Fallback, if we can't get computed value for content height
4072 if (total === null) {
4073 Dom.addClass(container, "yui-override-padding");
4074 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4075 Dom.removeClass(container, "yui-override-padding");
4078 remaining = Math.max(total - filled, 0);
4080 Dom.setStyle(el, "height", remaining + "px");
4082 // Re-adjust height if required, to account for el padding and border
4083 if (el.offsetHeight != remaining) {
4084 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4086 Dom.setStyle(el, "height", remaining + "px");
4092 * Places the Overlay on top of all other instances of
4093 * YAHOO.widget.Overlay.
4094 * @method bringToTop
4096 bringToTop: function () {
4099 oElement = this.element;
4101 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4103 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4104 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4106 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4107 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4109 if (nZIndex1 > nZIndex2) {
4111 } else if (nZIndex1 < nZIndex2) {
4118 function isOverlayElement(p_oElement) {
4120 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4121 Panel = YAHOO.widget.Panel;
4123 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4124 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4125 aOverlays[aOverlays.length] = p_oElement.parentNode;
4127 aOverlays[aOverlays.length] = p_oElement;
4132 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
4134 aOverlays.sort(compareZIndexDesc);
4136 var oTopOverlay = aOverlays[0],
4140 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4142 if (!isNaN(nTopZIndex)) {
4143 var bRequiresBump = false;
4145 if (oTopOverlay != oElement) {
4146 bRequiresBump = true;
4147 } else if (aOverlays.length > 1) {
4148 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4149 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4150 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4151 bRequiresBump = true;
4154 if (bRequiresBump) {
4155 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4162 * Removes the Overlay element from the DOM and sets all child
4166 destroy: function () {
4169 this.iframe.parentNode.removeChild(this.iframe);
4174 Overlay.windowResizeEvent.unsubscribe(
4175 this.doCenterOnDOMEvent, this);
4177 Overlay.windowScrollEvent.unsubscribe(
4178 this.doCenterOnDOMEvent, this);
4180 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4182 Overlay.superclass.destroy.call(this);
4186 * Can be used to force the container to repaint/redraw it's contents.
4188 * By default applies and then removes a 1px bottom margin through the
4189 * application/removal of a "yui-force-redraw" class.
4192 * It is currently used by Overlay to force a repaint for webkit
4193 * browsers, when centering.
4195 * @method forceContainerRedraw
4197 forceContainerRedraw : function() {
4199 Dom.addClass(c.element, "yui-force-redraw");
4200 setTimeout(function() {
4201 Dom.removeClass(c.element, "yui-force-redraw");
4206 * Returns a String representation of the object.
4208 * @return {String} The string representation of the Overlay.
4210 toString: function () {
4211 return "Overlay " + this.id;
4220 * OverlayManager is used for maintaining the focus status of
4221 * multiple Overlays.
4222 * @namespace YAHOO.widget
4223 * @namespace YAHOO.widget
4224 * @class OverlayManager
4226 * @param {Array} overlays Optional. A collection of Overlays to register
4228 * @param {Object} userConfig The object literal representing the user
4229 * configuration of the OverlayManager
4231 YAHOO.widget.OverlayManager = function (userConfig) {
4232 this.init(userConfig);
4235 var Overlay = YAHOO.widget.Overlay,
4236 Event = YAHOO.util.Event,
4237 Dom = YAHOO.util.Dom,
4238 Config = YAHOO.util.Config,
4239 CustomEvent = YAHOO.util.CustomEvent,
4240 OverlayManager = YAHOO.widget.OverlayManager;
4243 * The CSS class representing a focused Overlay
4244 * @property OverlayManager.CSS_FOCUSED
4249 OverlayManager.CSS_FOCUSED = "focused";
4251 OverlayManager.prototype = {
4254 * The class's constructor function
4255 * @property contructor
4258 constructor: OverlayManager,
4261 * The array of Overlays that are currently registered
4262 * @property overlays
4263 * @type YAHOO.widget.Overlay[]
4268 * Initializes the default configuration of the OverlayManager
4269 * @method initDefaultConfig
4271 initDefaultConfig: function () {
4273 * The collection of registered Overlays in use by
4274 * the OverlayManager
4276 * @type YAHOO.widget.Overlay[]
4279 this.cfg.addProperty("overlays", { suppressEvent: true } );
4282 * The default DOM event that should be used to focus an Overlay
4283 * @config focusevent
4285 * @default "mousedown"
4287 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4291 * Initializes the OverlayManager
4293 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4294 * register with the manager.
4295 * @param {Object} userConfig The object literal representing the user
4296 * configuration of the OverlayManager
4298 init: function (userConfig) {
4301 * The OverlayManager's Config object used for monitoring
4302 * configuration properties.
4306 this.cfg = new Config(this);
4308 this.initDefaultConfig();
4311 this.cfg.applyConfig(userConfig, true);
4313 this.cfg.fireQueue();
4316 * The currently activated Overlay
4317 * @property activeOverlay
4319 * @type YAHOO.widget.Overlay
4321 var activeOverlay = null;
4324 * Returns the currently focused Overlay
4326 * @return {Overlay} The currently focused Overlay
4328 this.getActive = function () {
4329 return activeOverlay;
4333 * Focuses the specified Overlay
4335 * @param {Overlay} overlay The Overlay to focus
4336 * @param {String} overlay The id of the Overlay to focus
4338 this.focus = function (overlay) {
4339 var o = this.find(overlay);
4346 * Removes the specified Overlay from the manager
4348 * @param {Overlay} overlay The Overlay to remove
4349 * @param {String} overlay The id of the Overlay to remove
4351 this.remove = function (overlay) {
4353 var o = this.find(overlay),
4357 if (activeOverlay == o) {
4358 activeOverlay = null;
4361 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4364 // Set it's zindex so that it's sorted to the end.
4365 originalZ = Dom.getStyle(o.element, "zIndex");
4366 o.cfg.setProperty("zIndex", -1000, true);
4369 this.overlays.sort(this.compareZIndexDesc);
4370 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4372 o.hideEvent.unsubscribe(o.blur);
4373 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4374 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4375 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4378 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4379 o.cfg.setProperty("zIndex", originalZ, true);
4380 o.cfg.setProperty("manager", null);
4383 /* _managed Flag for custom or existing. Don't want to remove existing */
4384 if (o.focusEvent._managed) { o.focusEvent = null; }
4385 if (o.blurEvent._managed) { o.blurEvent = null; }
4387 if (o.focus._managed) { o.focus = null; }
4388 if (o.blur._managed) { o.blur = null; }
4393 * Removes focus from all registered Overlays in the manager
4396 this.blurAll = function () {
4398 var nOverlays = this.overlays.length,
4401 if (nOverlays > 0) {
4404 this.overlays[i].blur();
4411 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4414 * @method _manageBlur
4415 * @param {Overlay} overlay The overlay instance which got blurred.
4418 this._manageBlur = function (overlay) {
4419 var changed = false;
4420 if (activeOverlay == overlay) {
4421 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4422 activeOverlay = null;
4429 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4432 * @method _manageFocus
4433 * @param {Overlay} overlay The overlay instance which got focus.
4436 this._manageFocus = function(overlay) {
4437 var changed = false;
4438 if (activeOverlay != overlay) {
4439 if (activeOverlay) {
4440 activeOverlay.blur();
4442 activeOverlay = overlay;
4443 this.bringToTop(activeOverlay);
4444 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4450 var overlays = this.cfg.getProperty("overlays");
4452 if (! this.overlays) {
4457 this.register(overlays);
4458 this.overlays.sort(this.compareZIndexDesc);
4463 * @method _onOverlayElementFocus
4464 * @description Event handler for the DOM event that is used to focus
4465 * the Overlay instance as specified by the "focusevent"
4466 * configuration property.
4468 * @param {Event} p_oEvent Object representing the DOM event
4469 * object passed back by the event utility (Event).
4471 _onOverlayElementFocus: function (p_oEvent) {
4473 var oTarget = Event.getTarget(p_oEvent),
4474 oClose = this.close;
4476 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4484 * @method _onOverlayDestroy
4485 * @description "destroy" event handler for the Overlay.
4487 * @param {String} p_sType String representing the name of the event
4489 * @param {Array} p_aArgs Array of arguments sent when the event
4491 * @param {Overlay} p_oOverlay Object representing the overlay that
4494 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4495 this.remove(p_oOverlay);
4499 * @method _onOverlayFocusHandler
4501 * focusEvent Handler, used to delegate to _manageFocus with the
4502 * correct arguments.
4505 * @param {String} p_sType String representing the name of the event
4507 * @param {Array} p_aArgs Array of arguments sent when the event
4509 * @param {Overlay} p_oOverlay Object representing the overlay that
4512 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4513 this._manageFocus(p_oOverlay);
4517 * @method _onOverlayBlurHandler
4519 * blurEvent Handler, used to delegate to _manageBlur with the
4520 * correct arguments.
4523 * @param {String} p_sType String representing the name of the event
4525 * @param {Array} p_aArgs Array of arguments sent when the event
4527 * @param {Overlay} p_oOverlay Object representing the overlay that
4530 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4531 this._manageBlur(p_oOverlay);
4535 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4536 * monitor focus state.
4538 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4539 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4540 * on the instance, the _bindFocus method will add them, and the focus method will
4541 * update the OverlayManager's state directly.
4543 * @method _bindFocus
4544 * @param {Overlay} overlay The overlay for which focus needs to be managed
4547 _bindFocus : function(overlay) {
4550 if (!overlay.focusEvent) {
4551 overlay.focusEvent = overlay.createEvent("focus");
4552 overlay.focusEvent.signature = CustomEvent.LIST;
4553 overlay.focusEvent._managed = true;
4555 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4558 if (!overlay.focus) {
4559 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4560 overlay.focus = function () {
4561 if (mgr._manageFocus(this)) {
4563 if (this.cfg.getProperty("visible") && this.focusFirst) {
4566 this.focusEvent.fire();
4569 overlay.focus._managed = true;
4574 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4575 * monitor blur state.
4577 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4578 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4579 * on the instance, the _bindBlur method will add them, and the blur method
4580 * update the OverlayManager's state directly.
4583 * @param {Overlay} overlay The overlay for which blur needs to be managed
4586 _bindBlur : function(overlay) {
4589 if (!overlay.blurEvent) {
4590 overlay.blurEvent = overlay.createEvent("blur");
4591 overlay.blurEvent.signature = CustomEvent.LIST;
4592 overlay.focusEvent._managed = true;
4594 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4597 if (!overlay.blur) {
4598 overlay.blur = function () {
4599 if (mgr._manageBlur(this)) {
4600 this.blurEvent.fire();
4603 overlay.blur._managed = true;
4606 overlay.hideEvent.subscribe(overlay.blur);
4610 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4611 * to be removed for the OverlayManager when destroyed.
4613 * @method _bindDestroy
4614 * @param {Overlay} overlay The overlay instance being managed
4617 _bindDestroy : function(overlay) {
4619 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4623 * Ensures the zIndex configuration property on the managed overlay based instance
4624 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4626 * @method _syncZIndex
4627 * @param {Overlay} overlay The overlay instance being managed
4630 _syncZIndex : function(overlay) {
4631 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4632 if (!isNaN(zIndex)) {
4633 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4635 overlay.cfg.setProperty("zIndex", 0);
4640 * Registers an Overlay or an array of Overlays with the manager. Upon
4641 * registration, the Overlay receives functions for focus and blur,
4642 * along with CustomEvents for each.
4645 * @param {Overlay} overlay An Overlay to register with the manager.
4646 * @param {Overlay[]} overlay An array of Overlays to register with
4648 * @return {boolean} true if any Overlays are registered.
4650 register: function (overlay) {
4652 var registered = false,
4656 if (overlay instanceof Overlay) {
4658 overlay.cfg.addProperty("manager", { value: this } );
4660 this._bindFocus(overlay);
4661 this._bindBlur(overlay);
4662 this._bindDestroy(overlay);
4663 this._syncZIndex(overlay);
4665 this.overlays.push(overlay);
4666 this.bringToTop(overlay);
4670 } else if (overlay instanceof Array) {
4672 for (i = 0, n = overlay.length; i < n; i++) {
4673 registered = this.register(overlay[i]) || registered;
4682 * Places the specified Overlay instance on top of all other
4683 * Overlay instances.
4684 * @method bringToTop
4685 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4687 * @param {String} p_oOverlay String representing the id of an
4690 bringToTop: function (p_oOverlay) {
4692 var oOverlay = this.find(p_oOverlay),
4699 aOverlays = this.overlays;
4700 aOverlays.sort(this.compareZIndexDesc);
4702 oTopOverlay = aOverlays[0];
4705 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4707 if (!isNaN(nTopZIndex)) {
4709 var bRequiresBump = false;
4711 if (oTopOverlay !== oOverlay) {
4712 bRequiresBump = true;
4713 } else if (aOverlays.length > 1) {
4714 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4715 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4716 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4717 bRequiresBump = true;
4721 if (bRequiresBump) {
4722 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4725 aOverlays.sort(this.compareZIndexDesc);
4731 * Attempts to locate an Overlay by instance or ID.
4733 * @param {Overlay} overlay An Overlay to locate within the manager
4734 * @param {String} overlay An Overlay id to locate within the manager
4735 * @return {Overlay} The requested Overlay, if found, or null if it
4736 * cannot be located.
4738 find: function (overlay) {
4740 var isInstance = overlay instanceof Overlay,
4741 overlays = this.overlays,
4742 n = overlays.length,
4747 if (isInstance || typeof overlay == "string") {
4748 for (i = n-1; i >= 0; i--) {
4750 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4761 * Used for sorting the manager's Overlays by z-index.
4762 * @method compareZIndexDesc
4764 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4765 * fall in the stacking order.
4767 compareZIndexDesc: function (o1, o2) {
4769 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4770 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4772 if (zIndex1 === null && zIndex2 === null) {
4774 } else if (zIndex1 === null){
4776 } else if (zIndex2 === null) {
4778 } else if (zIndex1 > zIndex2) {
4780 } else if (zIndex1 < zIndex2) {
4788 * Shows all Overlays in the manager.
4791 showAll: function () {
4792 var overlays = this.overlays,
4793 n = overlays.length,
4796 for (i = n - 1; i >= 0; i--) {
4802 * Hides all Overlays in the manager.
4805 hideAll: function () {
4806 var overlays = this.overlays,
4807 n = overlays.length,
4810 for (i = n - 1; i >= 0; i--) {
4816 * Returns a string representation of the object.
4818 * @return {String} The string representation of the OverlayManager
4820 toString: function () {
4821 return "OverlayManager";
4829 * Tooltip is an implementation of Overlay that behaves like an OS tooltip,
4830 * displaying when the user mouses over a particular element, and
4831 * disappearing on mouse out.
4832 * @namespace YAHOO.widget
4834 * @extends YAHOO.widget.Overlay
4836 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4837 * @param {HTMLElement} el The element representing the Tooltip
4838 * @param {Object} userConfig The configuration object literal containing
4839 * the configuration that should be set for this Overlay. See configuration
4840 * documentation for more details.
4842 YAHOO.widget.Tooltip = function (el, userConfig) {
4843 YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4846 var Lang = YAHOO.lang,
4847 Event = YAHOO.util.Event,
4848 CustomEvent = YAHOO.util.CustomEvent,
4849 Dom = YAHOO.util.Dom,
4850 Tooltip = YAHOO.widget.Tooltip,
4852 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
4857 * Constant representing the Tooltip's configuration properties
4858 * @property DEFAULT_CONFIG
4865 "PREVENT_OVERLAP": {
4866 key: "preventoverlap",
4868 validator: Lang.isBoolean,
4869 supercedes: ["x", "y", "xy"]
4875 validator: Lang.isNumber
4878 "AUTO_DISMISS_DELAY": {
4879 key: "autodismissdelay",
4881 validator: Lang.isNumber
4887 validator: Lang.isNumber
4907 * Constant representing the name of the Tooltip's events
4908 * @property EVENT_TYPES
4914 "CONTEXT_MOUSE_OVER": "contextMouseOver",
4915 "CONTEXT_MOUSE_OUT": "contextMouseOut",
4916 "CONTEXT_TRIGGER": "contextTrigger"
4920 * Constant representing the Tooltip CSS class
4921 * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4926 Tooltip.CSS_TOOLTIP = "yui-tt";
4928 function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
4930 var oConfig = this.cfg,
4931 sCurrentWidth = oConfig.getProperty("width");
4933 if (sCurrentWidth == sForcedWidth) {
4934 oConfig.setProperty("width", sOriginalWidth);
4939 changeContent event handler that sets a Tooltip instance's "width"
4940 configuration property to the value of its root HTML
4941 elements's offsetWidth if a specific width has not been set.
4944 function setWidthToOffsetWidth(p_sType, p_aArgs) {
4946 if ("_originalWidth" in this) {
4947 restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
4950 var oBody = document.body,
4952 sOriginalWidth = oConfig.getProperty("width"),
4956 if ((!sOriginalWidth || sOriginalWidth == "auto") &&
4957 (oConfig.getProperty("container") != oBody ||
4958 oConfig.getProperty("x") >= Dom.getViewportWidth() ||
4959 oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4961 oClone = this.element.cloneNode(true);
4962 oClone.style.visibility = "hidden";
4963 oClone.style.top = "0px";
4964 oClone.style.left = "0px";
4966 oBody.appendChild(oClone);
4968 sNewWidth = (oClone.offsetWidth + "px");
4970 oBody.removeChild(oClone);
4973 oConfig.setProperty("width", sNewWidth);
4974 oConfig.refireEvent("xy");
4976 this._originalWidth = sOriginalWidth || "";
4977 this._forcedWidth = sNewWidth;
4981 // "onDOMReady" that renders the ToolTip
4983 function onDOMReady(p_sType, p_aArgs, p_oObject) {
4984 this.render(p_oObject);
4987 // "init" event handler that automatically renders the Tooltip
4990 Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4993 YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
4996 * The Tooltip initialization method. This method is automatically
4997 * called by the constructor. A Tooltip is automatically rendered by
4998 * the init method, and it also is set to be invisible by default,
4999 * and constrained to viewport by default as well.
5001 * @param {String} el The element ID representing the Tooltip <em>OR</em>
5002 * @param {HTMLElement} el The element representing the Tooltip
5003 * @param {Object} userConfig The configuration object literal
5004 * containing the configuration that should be set for this Tooltip.
5005 * See configuration documentation for more details.
5007 init: function (el, userConfig) {
5009 this.logger = new YAHOO.widget.LogWriter(this.toString());
5011 Tooltip.superclass.init.call(this, el);
5013 this.beforeInitEvent.fire(Tooltip);
5015 Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
5018 this.cfg.applyConfig(userConfig, true);
5021 this.cfg.queueProperty("visible", false);
5022 this.cfg.queueProperty("constraintoviewport", true);
5026 this.subscribe("changeContent", setWidthToOffsetWidth);
5027 this.subscribe("init", onInit);
5028 this.subscribe("render", this.onRender);
5030 this.initEvent.fire(Tooltip);
5034 * Initializes the custom events for Tooltip
5035 * @method initEvents
5037 initEvents: function () {
5039 Tooltip.superclass.initEvents.call(this);
5040 var SIGNATURE = CustomEvent.LIST;
5043 * CustomEvent fired when user mouses over a context element. Returning false from
5044 * a subscriber to this event will prevent the tooltip from being displayed for
5045 * the current context element.
5047 * @event contextMouseOverEvent
5048 * @param {HTMLElement} context The context element which the user just moused over
5049 * @param {DOMEvent} e The DOM event object, associated with the mouse over
5051 this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
5052 this.contextMouseOverEvent.signature = SIGNATURE;
5055 * CustomEvent fired when the user mouses out of a context element.
5057 * @event contextMouseOutEvent
5058 * @param {HTMLElement} context The context element which the user just moused out of
5059 * @param {DOMEvent} e The DOM event object, associated with the mouse out
5061 this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
5062 this.contextMouseOutEvent.signature = SIGNATURE;
5065 * CustomEvent fired just before the tooltip is displayed for the current context.
5067 * You can subscribe to this event if you need to set up the text for the
5068 * tooltip based on the context element for which it is about to be displayed.
5070 * <p>This event differs from the beforeShow event in following respects:</p>
5073 * When moving from one context element to another, if the tooltip is not
5074 * hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
5075 * be fired when the tooltip is displayed for the new context since it is already visible.
5076 * However the contextTrigger event is always fired before displaying the tooltip for
5080 * The trigger event provides access to the context element, allowing you to
5081 * set the text of the tooltip based on context element for which the tooltip is
5086 * It is not possible to prevent the tooltip from being displayed
5087 * using this event. You can use the contextMouseOverEvent if you need to prevent
5088 * the tooltip from being displayed.
5090 * @event contextTriggerEvent
5091 * @param {HTMLElement} context The context element for which the tooltip is triggered
5093 this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
5094 this.contextTriggerEvent.signature = SIGNATURE;
5098 * Initializes the class's configurable properties which can be
5099 * changed using the Overlay's Config object (cfg).
5100 * @method initDefaultConfig
5102 initDefaultConfig: function () {
5104 Tooltip.superclass.initDefaultConfig.call(this);
5107 * Specifies whether the Tooltip should be kept from overlapping
5108 * its context element.
5109 * @config preventoverlap
5113 this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
5114 value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
5115 validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
5116 supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
5120 * The number of milliseconds to wait before showing a Tooltip
5126 this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
5127 handler: this.configShowDelay,
5129 validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5133 * The number of milliseconds to wait before automatically
5134 * dismissing a Tooltip after the mouse has been resting on the
5136 * @config autodismissdelay
5140 this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
5141 handler: this.configAutoDismissDelay,
5142 value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
5143 validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
5147 * The number of milliseconds to wait before hiding a Tooltip
5153 this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
5154 handler: this.configHideDelay,
5155 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5156 validator: DEFAULT_CONFIG.HIDE_DELAY.validator
5160 * Specifies the Tooltip's text.
5165 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
5166 handler: this.configText,
5167 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
5171 * Specifies the container element that the Tooltip's markup
5172 * should be rendered into.
5174 * @type HTMLElement/String
5175 * @default document.body
5177 this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
5178 handler: this.configContainer,
5179 value: document.body
5183 * Specifies whether or not the tooltip is disabled. Disabled tooltips
5184 * will not be displayed. If the tooltip is driven by the title attribute
5185 * of the context element, the title attribute will still be removed for
5186 * disabled tooltips, to prevent default tooltip behavior.
5192 this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
5193 handler: this.configContainer,
5194 value: DEFAULT_CONFIG.DISABLED.value,
5195 supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5199 * Specifies the element or elements that the Tooltip should be
5200 * anchored to on mouseover.
5202 * @type HTMLElement[]/String[]
5207 * String representing the width of the Tooltip. <em>Please note:
5208 * </em> As of version 2.3 if either no value or a value of "auto"
5209 * is specified, and the Toolip's "container" configuration property
5210 * is set to something other than <code>document.body</code> or
5211 * its "context" element resides outside the immediately visible
5212 * portion of the document, the width of the Tooltip will be
5213 * calculated based on the offsetWidth of its root HTML and set just
5214 * before it is made visible. The original value will be
5215 * restored when the Tooltip is hidden. This ensures the Tooltip is
5216 * rendered at a usable width. For more information see
5217 * SourceForge bug #1685496 and SourceForge
5226 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5229 * The default event handler fired when the "text" property is changed.
5230 * @method configText
5231 * @param {String} type The CustomEvent type (usually the property name)
5232 * @param {Object[]} args The CustomEvent arguments. For configuration
5233 * handlers, args[0] will equal the newly applied value for the property.
5234 * @param {Object} obj The scope object. For configuration handlers,
5235 * this will usually equal the owner.
5237 configText: function (type, args, obj) {
5245 * The default event handler fired when the "container" property
5247 * @method configContainer
5248 * @param {String} type The CustomEvent type (usually the property name)
5249 * @param {Object[]} args The CustomEvent arguments. For
5250 * configuration handlers, args[0] will equal the newly applied value
5252 * @param {Object} obj The scope object. For configuration handlers,
5253 * this will usually equal the owner.
5255 configContainer: function (type, args, obj) {
5256 var container = args[0];
5258 if (typeof container == 'string') {
5259 this.cfg.setProperty("container", document.getElementById(container), true);
5264 * @method _removeEventListeners
5265 * @description Removes all of the DOM event handlers from the HTML
5266 * element(s) that trigger the display of the tooltip.
5269 _removeEventListeners: function () {
5271 var aElements = this._context,
5277 nElements = aElements.length;
5278 if (nElements > 0) {
5281 oElement = aElements[i];
5282 Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
5283 Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
5284 Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
5292 * The default event handler fired when the "context" property
5294 * @method configContext
5295 * @param {String} type The CustomEvent type (usually the property name)
5296 * @param {Object[]} args The CustomEvent arguments. For configuration
5297 * handlers, args[0] will equal the newly applied value for the property.
5298 * @param {Object} obj The scope object. For configuration handlers,
5299 * this will usually equal the owner.
5301 configContext: function (type, args, obj) {
5303 var context = args[0],
5311 // Normalize parameter into an array
5312 if (! (context instanceof Array)) {
5313 if (typeof context == "string") {
5314 this.cfg.setProperty("context", [document.getElementById(context)], true);
5315 } else { // Assuming this is an element
5316 this.cfg.setProperty("context", [context], true);
5318 context = this.cfg.getProperty("context");
5321 // Remove any existing mouseover/mouseout listeners
5322 this._removeEventListeners();
5324 // Add mouseover/mouseout listeners to context elements
5325 this._context = context;
5327 aElements = this._context;
5330 nElements = aElements.length;
5331 if (nElements > 0) {
5334 oElement = aElements[i];
5335 Event.on(oElement, "mouseover", this.onContextMouseOver, this);
5336 Event.on(oElement, "mousemove", this.onContextMouseMove, this);
5337 Event.on(oElement, "mouseout", this.onContextMouseOut, this);
5345 // END BUILT-IN PROPERTY EVENT HANDLERS //
5347 // BEGIN BUILT-IN DOM EVENT HANDLERS //
5350 * The default event handler fired when the user moves the mouse while
5351 * over the context element.
5352 * @method onContextMouseMove
5353 * @param {DOMEvent} e The current DOM event
5354 * @param {Object} obj The object argument
5356 onContextMouseMove: function (e, obj) {
5357 obj.pageX = Event.getPageX(e);
5358 obj.pageY = Event.getPageY(e);
5362 * The default event handler fired when the user mouses over the
5364 * @method onContextMouseOver
5365 * @param {DOMEvent} e The current DOM event
5366 * @param {Object} obj The object argument
5368 onContextMouseOver: function (e, obj) {
5371 if (context.title) {
5372 obj._tempTitle = context.title;
5376 // Fire first, to honor disabled set in the listner
5377 if (obj.fireEvent("contextMouseOver", context, e) !== false
5378 && !obj.cfg.getProperty("disabled")) {
5380 // Stop the tooltip from being hidden (set on last mouseout)
5381 if (obj.hideProcId) {
5382 clearTimeout(obj.hideProcId);
5383 obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
5384 obj.hideProcId = null;
5387 Event.on(context, "mousemove", obj.onContextMouseMove, obj);
5390 * The unique process ID associated with the thread responsible
5391 * for showing the Tooltip.
5394 obj.showProcId = obj.doShow(e, context);
5395 obj.logger.log("Setting show tooltip timeout: " + obj.showProcId, "time");
5400 * The default event handler fired when the user mouses out of
5401 * the context element.
5402 * @method onContextMouseOut
5403 * @param {DOMEvent} e The current DOM event
5404 * @param {Object} obj The object argument
5406 onContextMouseOut: function (e, obj) {
5409 if (obj._tempTitle) {
5410 el.title = obj._tempTitle;
5411 obj._tempTitle = null;
5414 if (obj.showProcId) {
5415 clearTimeout(obj.showProcId);
5416 obj.logger.log("Clearing show timer: " + obj.showProcId, "time");
5417 obj.showProcId = null;
5420 if (obj.hideProcId) {
5421 clearTimeout(obj.hideProcId);
5422 obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
5423 obj.hideProcId = null;
5426 obj.fireEvent("contextMouseOut", el, e);
5428 obj.hideProcId = setTimeout(function () {
5430 }, obj.cfg.getProperty("hidedelay"));
5433 // END BUILT-IN DOM EVENT HANDLERS //
5436 * Processes the showing of the Tooltip by setting the timeout delay
5437 * and offset of the Tooltip.
5439 * @param {DOMEvent} e The current DOM event
5440 * @param {HTMLElement} context The current context element
5441 * @return {Number} The process ID of the timeout function associated
5444 doShow: function (e, context) {
5449 if (UA.opera && context.tagName &&
5450 context.tagName.toUpperCase() == "A") {
5454 return setTimeout(function () {
5456 var txt = me.cfg.getProperty("text");
5458 // title does not over-ride text
5459 if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
5460 me.setBody(me._tempTitle);
5462 me.cfg.refireEvent("text");
5465 me.logger.log("Show tooltip", "time");
5466 me.moveTo(me.pageX, me.pageY + yOffset);
5468 if (me.cfg.getProperty("preventoverlap")) {
5469 me.preventOverlap(me.pageX, me.pageY);
5472 Event.removeListener(context, "mousemove", me.onContextMouseMove);
5474 me.contextTriggerEvent.fire(context);
5478 me.hideProcId = me.doHide();
5479 me.logger.log("Hide tooltip time active: " + me.hideProcId, "time");
5481 }, this.cfg.getProperty("showdelay"));
5485 * Sets the timeout for the auto-dismiss delay, which by default is 5
5486 * seconds, meaning that a tooltip will automatically dismiss itself
5487 * after 5 seconds of being displayed.
5490 doHide: function () {
5494 me.logger.log("Setting hide tooltip timeout", "time");
5496 return setTimeout(function () {
5498 me.logger.log("Hide tooltip", "time");
5501 }, this.cfg.getProperty("autodismissdelay"));
5506 * Fired when the Tooltip is moved, this event handler is used to
5507 * prevent the Tooltip from overlapping with its context element.
5508 * @method preventOverlay
5509 * @param {Number} pageX The x coordinate position of the mouse pointer
5510 * @param {Number} pageY The y coordinate position of the mouse pointer
5512 preventOverlap: function (pageX, pageY) {
5514 var height = this.element.offsetHeight,
5515 mousePoint = new YAHOO.util.Point(pageX, pageY),
5516 elementRegion = Dom.getRegion(this.element);
5518 elementRegion.top -= 5;
5519 elementRegion.left -= 5;
5520 elementRegion.right += 5;
5521 elementRegion.bottom += 5;
5523 this.logger.log("context " + elementRegion, "ttip");
5524 this.logger.log("mouse " + mousePoint, "ttip");
5526 if (elementRegion.contains(mousePoint)) {
5527 this.logger.log("OVERLAP", "warn");
5528 this.cfg.setProperty("y", (pageY - height - 5));
5535 * @description "render" event handler for the Tooltip.
5536 * @param {String} p_sType String representing the name of the event
5538 * @param {Array} p_aArgs Array of arguments sent when the event
5541 onRender: function (p_sType, p_aArgs) {
5543 function sizeShadow() {
5545 var oElement = this.element,
5546 oShadow = this.underlay;
5549 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
5550 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
5555 function addShadowVisibleClass() {
5556 Dom.addClass(this.underlay, "yui-tt-shadow-visible");
5559 this.forceUnderlayRedraw();
5563 function removeShadowVisibleClass() {
5564 Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
5567 function createShadow() {
5569 var oShadow = this.underlay,
5577 oElement = this.element;
5578 Module = YAHOO.widget.Module;
5582 if (!m_oShadowTemplate) {
5583 m_oShadowTemplate = document.createElement("div");
5584 m_oShadowTemplate.className = "yui-tt-shadow";
5587 oShadow = m_oShadowTemplate.cloneNode(false);
5589 oElement.appendChild(oShadow);
5591 this.underlay = oShadow;
5593 // Backward compatibility, even though it's probably
5594 // intended to be "private", it isn't marked as such in the api docs
5595 this._shadow = this.underlay;
5597 addShadowVisibleClass.call(this);
5599 this.subscribe("beforeShow", addShadowVisibleClass);
5600 this.subscribe("hide", removeShadowVisibleClass);
5603 window.setTimeout(function () {
5604 sizeShadow.call(me);
5607 this.cfg.subscribeToConfigEvent("width", sizeShadow);
5608 this.cfg.subscribeToConfigEvent("height", sizeShadow);
5609 this.subscribe("changeContent", sizeShadow);
5611 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5612 this.subscribe("destroy", function () {
5613 Module.textResizeEvent.unsubscribe(sizeShadow, this);
5619 function onBeforeShow() {
5620 createShadow.call(this);
5621 this.unsubscribe("beforeShow", onBeforeShow);
5624 if (this.cfg.getProperty("visible")) {
5625 createShadow.call(this);
5627 this.subscribe("beforeShow", onBeforeShow);
5633 * Forces the underlay element to be repainted, through the application/removal
5634 * of a yui-force-redraw class to the underlay element.
5636 * @method forceUnderlayRedraw
5638 forceUnderlayRedraw : function() {
5640 Dom.addClass(tt.underlay, "yui-force-redraw");
5641 setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
5645 * Removes the Tooltip element from the DOM and sets all child
5649 destroy: function () {
5651 // Remove any existing mouseover/mouseout listeners
5652 this._removeEventListeners();
5654 Tooltip.superclass.destroy.call(this);
5659 * Returns a string representation of the object.
5661 * @return {String} The string representation of the Tooltip
5663 toString: function () {
5664 return "Tooltip " + this.id;
5674 * Panel is an implementation of Overlay that behaves like an OS window,
5675 * with a draggable header and an optional close icon at the top right.
5676 * @namespace YAHOO.widget
5678 * @extends YAHOO.widget.Overlay
5680 * @param {String} el The element ID representing the Panel <em>OR</em>
5681 * @param {HTMLElement} el The element representing the Panel
5682 * @param {Object} userConfig The configuration object literal containing
5683 * the configuration that should be set for this Panel. See configuration
5684 * documentation for more details.
5686 YAHOO.widget.Panel = function (el, userConfig) {
5687 YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5690 var _currentModal = null;
5692 var Lang = YAHOO.lang,
5696 CustomEvent = Util.CustomEvent,
5697 KeyListener = YAHOO.util.KeyListener,
5698 Config = Util.Config,
5699 Overlay = YAHOO.widget.Overlay,
5700 Panel = YAHOO.widget.Panel,
5703 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
5706 m_oUnderlayTemplate,
5707 m_oCloseIconTemplate,
5710 * Constant representing the name of the Panel's events
5711 * @property EVENT_TYPES
5717 "SHOW_MASK": "showMask",
5718 "HIDE_MASK": "hideMask",
5723 * Constant representing the Panel's configuration properties
5724 * @property DEFAULT_CONFIG
5734 validator: Lang.isBoolean,
5735 supercedes: ["visible"]
5740 value: (Util.DD ? true : false),
5741 validator: Lang.isBoolean,
5742 supercedes: ["visible"]
5748 validator: Lang.isBoolean,
5749 supercedes: ["draggable"]
5755 supercedes: ["visible"]
5761 validator: Lang.isBoolean,
5762 supercedes: ["visible", "zindex"]
5766 key: "keylisteners",
5767 suppressEvent: true,
5768 supercedes: ["visible"]
5773 supercedes: ["close"],
5774 validator: Lang.isObject,
5782 * Constant representing the default CSS class used for a Panel
5783 * @property YAHOO.widget.Panel.CSS_PANEL
5788 Panel.CSS_PANEL = "yui-panel";
5791 * Constant representing the default CSS class used for a Panel's
5792 * wrapping container
5793 * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5798 Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5801 * Constant representing the default set of focusable elements
5802 * on the pagewhich Modal Panels will prevent access to, when
5803 * the modal mask is displayed
5805 * @property YAHOO.widget.Panel.FOCUSABLE
5818 // Private CustomEvent listeners
5821 "beforeRender" event handler that creates an empty header for a Panel
5822 instance if its "draggable" configuration property is set to "true"
5823 and no header has been created.
5826 function createHeader(p_sType, p_aArgs) {
5827 if (!this.header && this.cfg.getProperty("draggable")) {
5828 this.setHeader(" ");
5833 "hide" event handler that sets a Panel instance's "width"
5834 configuration property back to its original value before
5835 "setWidthToOffsetWidth" was called.
5838 function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5840 var sOriginalWidth = p_oObject[0],
5841 sNewWidth = p_oObject[1],
5843 sCurrentWidth = oConfig.getProperty("width");
5845 if (sCurrentWidth == sNewWidth) {
5846 oConfig.setProperty("width", sOriginalWidth);
5849 this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5853 "beforeShow" event handler that sets a Panel instance's "width"
5854 configuration property to the value of its root HTML
5855 elements's offsetWidth
5858 function setWidthToOffsetWidth(p_sType, p_aArgs) {
5867 sOriginalWidth = oConfig.getProperty("width");
5869 if (!sOriginalWidth || sOriginalWidth == "auto") {
5871 sNewWidth = (this.element.offsetWidth + "px");
5873 oConfig.setProperty("width", sNewWidth);
5875 this.subscribe("hide", restoreOriginalWidth,
5876 [(sOriginalWidth || ""), sNewWidth]);
5882 YAHOO.extend(Panel, Overlay, {
5885 * The Overlay initialization method, which is executed for Overlay and
5886 * all of its subclasses. This method is automatically called by the
5887 * constructor, and sets up all DOM references for pre-existing markup,
5888 * and creates required markup if it is not already present.
5890 * @param {String} el The element ID representing the Overlay <em>OR</em>
5891 * @param {HTMLElement} el The element representing the Overlay
5892 * @param {Object} userConfig The configuration object literal
5893 * containing the configuration that should be set for this Overlay.
5894 * See configuration documentation for more details.
5896 init: function (el, userConfig) {
5898 Note that we don't pass the user config in here yet because
5899 we only want it executed once, at the lowest subclass level
5902 Panel.superclass.init.call(this, el/*, userConfig*/);
5904 this.beforeInitEvent.fire(Panel);
5906 Dom.addClass(this.element, Panel.CSS_PANEL);
5908 this.buildWrapper();
5911 this.cfg.applyConfig(userConfig, true);
5914 this.subscribe("showMask", this._addFocusHandlers);
5915 this.subscribe("hideMask", this._removeFocusHandlers);
5916 this.subscribe("beforeRender", createHeader);
5918 this.subscribe("render", function() {
5919 this.setFirstLastFocusable();
5920 this.subscribe("changeContent", this.setFirstLastFocusable);
5923 this.subscribe("show", this.focusFirst);
5925 this.initEvent.fire(Panel);
5929 * @method _onElementFocus
5932 * "focus" event handler for a focuable element. Used to automatically
5933 * blur the element when it receives focus to ensure that a Panel
5934 * instance's modality is not compromised.
5936 * @param {Event} e The DOM event object
5938 _onElementFocus : function(e){
5940 if(_currentModal === this) {
5942 var target = Event.getTarget(e),
5943 doc = document.documentElement,
5944 insideDoc = (target !== doc && target !== window);
5946 // mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on
5947 // the documentElement, when the document scrollbars are clicked on
5948 if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
5950 if (this.firstElement) {
5951 this.firstElement.focus();
5953 if (this._modalFocus) {
5954 this._modalFocus.focus();
5956 this.innerElement.focus();
5960 // Just in case we fail to focus
5962 if (insideDoc && target !== document.body) {
5972 * @method _addFocusHandlers
5975 * "showMask" event handler that adds a "focus" event handler to all
5976 * focusable elements in the document to enforce a Panel instance's
5977 * modality from being compromised.
5979 * @param p_sType {String} Custom event type
5980 * @param p_aArgs {Array} Custom event arguments
5982 _addFocusHandlers: function(p_sType, p_aArgs) {
5983 if (!this.firstElement) {
5984 if (UA.webkit || UA.opera) {
5985 if (!this._modalFocus) {
5986 this._createHiddenFocusElement();
5989 this.innerElement.tabIndex = 0;
5992 this.setTabLoop(this.firstElement, this.lastElement);
5993 Event.onFocus(document.documentElement, this._onElementFocus, this, true);
5994 _currentModal = this;
5998 * Creates a hidden focusable element, used to focus on,
5999 * to enforce modality for browsers in which focus cannot
6000 * be applied to the container box.
6002 * @method _createHiddenFocusElement
6005 _createHiddenFocusElement : function() {
6006 var e = document.createElement("button");
6007 e.style.height = "1px";
6008 e.style.width = "1px";
6009 e.style.position = "absolute";
6010 e.style.left = "-10000em";
6011 e.style.opacity = 0;
6013 this.innerElement.appendChild(e);
6014 this._modalFocus = e;
6018 * @method _removeFocusHandlers
6021 * "hideMask" event handler that removes all "focus" event handlers added
6022 * by the "addFocusEventHandlers" method.
6024 * @param p_sType {String} Event type
6025 * @param p_aArgs {Array} Event Arguments
6027 _removeFocusHandlers: function(p_sType, p_aArgs) {
6028 Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
6030 if (_currentModal == this) {
6031 _currentModal = null;
6036 * Sets focus to the first element in the Panel.
6038 * @method focusFirst
6040 focusFirst: function (type, args, obj) {
6041 var el = this.firstElement;
6043 if (args && args[1]) {
6044 Event.stopEvent(args[1]);
6057 * Sets focus to the last element in the Panel.
6061 focusLast: function (type, args, obj) {
6062 var el = this.lastElement;
6064 if (args && args[1]) {
6065 Event.stopEvent(args[1]);
6078 * Sets up a tab, shift-tab loop between the first and last elements
6079 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
6080 * instance properties, which are reset everytime this method is invoked.
6082 * @method setTabLoop
6083 * @param {HTMLElement} firstElement
6084 * @param {HTMLElement} lastElement
6087 setTabLoop : function(firstElement, lastElement) {
6089 var backTab = this.preventBackTab, tab = this.preventTabOut,
6090 showEvent = this.showEvent, hideEvent = this.hideEvent;
6094 showEvent.unsubscribe(backTab.enable, backTab);
6095 hideEvent.unsubscribe(backTab.disable, backTab);
6096 backTab = this.preventBackTab = null;
6101 showEvent.unsubscribe(tab.enable, tab);
6102 hideEvent.unsubscribe(tab.disable,tab);
6103 tab = this.preventTabOut = null;
6107 this.preventBackTab = new KeyListener(firstElement,
6108 {shift:true, keys:9},
6109 {fn:this.focusLast, scope:this, correctScope:true}
6111 backTab = this.preventBackTab;
6113 showEvent.subscribe(backTab.enable, backTab, true);
6114 hideEvent.subscribe(backTab.disable,backTab, true);
6118 this.preventTabOut = new KeyListener(lastElement,
6119 {shift:false, keys:9},
6120 {fn:this.focusFirst, scope:this, correctScope:true}
6122 tab = this.preventTabOut;
6124 showEvent.subscribe(tab.enable, tab, true);
6125 hideEvent.subscribe(tab.disable,tab, true);
6130 * Returns an array of the currently focusable items which reside within
6131 * Panel. The set of focusable elements the method looks for are defined
6132 * in the Panel.FOCUSABLE static property
6134 * @method getFocusableElements
6135 * @param {HTMLElement} root element to start from.
6137 getFocusableElements : function(root) {
6139 root = root || this.innerElement;
6142 for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
6143 focusable[Panel.FOCUSABLE[i]] = true;
6146 function isFocusable(el) {
6147 if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
6153 // Not looking by Tag, since we want elements in DOM order
6154 return Dom.getElementsBy(isFocusable, null, root);
6158 * Sets the firstElement and lastElement instance properties
6159 * to the first and last focusable elements in the Panel.
6161 * @method setFirstLastFocusable
6163 setFirstLastFocusable : function() {
6165 this.firstElement = null;
6166 this.lastElement = null;
6168 var elements = this.getFocusableElements();
6169 this.focusableElements = elements;
6171 if (elements.length > 0) {
6172 this.firstElement = elements[0];
6173 this.lastElement = elements[elements.length - 1];
6176 if (this.cfg.getProperty("modal")) {
6177 this.setTabLoop(this.firstElement, this.lastElement);
6182 * Initializes the custom events for Module which are fired
6183 * automatically at appropriate times by the Module class.
6185 initEvents: function () {
6186 Panel.superclass.initEvents.call(this);
6188 var SIGNATURE = CustomEvent.LIST;
6191 * CustomEvent fired after the modality mask is shown
6192 * @event showMaskEvent
6194 this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
6195 this.showMaskEvent.signature = SIGNATURE;
6198 * CustomEvent fired after the modality mask is hidden
6199 * @event hideMaskEvent
6201 this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
6202 this.hideMaskEvent.signature = SIGNATURE;
6205 * CustomEvent when the Panel is dragged
6208 this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
6209 this.dragEvent.signature = SIGNATURE;
6213 * Initializes the class's configurable properties which can be changed
6214 * using the Panel's Config object (cfg).
6215 * @method initDefaultConfig
6217 initDefaultConfig: function () {
6218 Panel.superclass.initDefaultConfig.call(this);
6220 // Add panel config properties //
6223 * True if the Panel should display a "close" button
6228 this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
6229 handler: this.configClose,
6230 value: DEFAULT_CONFIG.CLOSE.value,
6231 validator: DEFAULT_CONFIG.CLOSE.validator,
6232 supercedes: DEFAULT_CONFIG.CLOSE.supercedes
6236 * Boolean specifying if the Panel should be draggable. The default
6237 * value is "true" if the Drag and Drop utility is included,
6238 * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
6239 * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
6240 * (Quirks Mode) where Panels that either don't have a value set for
6241 * their "width" configuration property, or their "width"
6242 * configuration property is set to "auto" will only be draggable by
6243 * placing the mouse on the text of the Panel's header element.
6244 * To fix this bug, draggable Panels missing a value for their
6245 * "width" configuration property, or whose "width" configuration
6246 * property is set to "auto" will have it set to the value of
6247 * their root HTML element's offsetWidth before they are made
6248 * visible. The calculated width is then removed when the Panel is
6249 * hidden. <em>This fix is only applied to draggable Panels in IE 6
6250 * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
6251 * more information on this issue see:
6252 * SourceForge bugs #1726972 and #1589210.
6257 this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
6258 handler: this.configDraggable,
6259 value: (Util.DD) ? true : false,
6260 validator: DEFAULT_CONFIG.DRAGGABLE.validator,
6261 supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
6265 * Boolean specifying if the draggable Panel should be drag only, not interacting with drop
6266 * targets on the page.
6268 * When set to true, draggable Panels will not check to see if they are over drop targets,
6269 * or fire the DragDrop events required to support drop target interaction (onDragEnter,
6270 * onDragOver, onDragOut, onDragDrop etc.).
6271 * If the Panel is not designed to be dropped on any target elements on the page, then this
6272 * flag can be set to true to improve performance.
6275 * When set to false, all drop target related events will be fired.
6278 * The property is set to false by default to maintain backwards compatibility but should be
6279 * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
6285 this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, {
6286 value: DEFAULT_CONFIG.DRAG_ONLY.value,
6287 validator: DEFAULT_CONFIG.DRAG_ONLY.validator,
6288 supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes
6292 * Sets the type of underlay to display for the Panel. Valid values
6293 * are "shadow," "matte," and "none". <strong>PLEASE NOTE:</strong>
6294 * The creation of the underlay element is deferred until the Panel
6295 * is initially made visible. For Gecko-based browsers on Mac
6296 * OS X the underlay elment is always created as it is used as a
6297 * shim to prevent Aqua scrollbars below a Panel instance from poking
6298 * through it (See SourceForge bug #836476).
6303 this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
6304 handler: this.configUnderlay,
6305 value: DEFAULT_CONFIG.UNDERLAY.value,
6306 supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
6310 * True if the Panel should be displayed in a modal fashion,
6311 * automatically creating a transparent mask over the document that
6312 * will not be removed until the Panel is dismissed.
6317 this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
6318 handler: this.configModal,
6319 value: DEFAULT_CONFIG.MODAL.value,
6320 validator: DEFAULT_CONFIG.MODAL.validator,
6321 supercedes: DEFAULT_CONFIG.MODAL.supercedes
6325 * A KeyListener (or array of KeyListeners) that will be enabled
6326 * when the Panel is shown, and disabled when the Panel is hidden.
6327 * @config keylisteners
6328 * @type YAHOO.util.KeyListener[]
6331 this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
6332 handler: this.configKeyListeners,
6333 suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
6334 supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
6338 * UI Strings used by the Panel
6342 * @default An object literal with the properties shown below:
6344 * <dt>close</dt><dd><em>String</em> : The string to use for the close icon. Defaults to "Close".</dd>
6347 this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, {
6348 value:DEFAULT_CONFIG.STRINGS.value,
6349 handler:this.configStrings,
6350 validator:DEFAULT_CONFIG.STRINGS.validator,
6351 supercedes:DEFAULT_CONFIG.STRINGS.supercedes
6355 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6358 * The default event handler fired when the "close" property is changed.
6359 * The method controls the appending or hiding of the close icon at the
6360 * top right of the Panel.
6361 * @method configClose
6362 * @param {String} type The CustomEvent type (usually the property name)
6363 * @param {Object[]} args The CustomEvent arguments. For configuration
6364 * handlers, args[0] will equal the newly applied value for the property.
6365 * @param {Object} obj The scope object. For configuration handlers,
6366 * this will usually equal the owner.
6368 configClose: function (type, args, obj) {
6371 oClose = this.close,
6372 strings = this.cfg.getProperty("strings");
6377 if (!m_oCloseIconTemplate) {
6378 m_oCloseIconTemplate = document.createElement("a");
6379 m_oCloseIconTemplate.className = "container-close";
6380 m_oCloseIconTemplate.href = "#";
6383 oClose = m_oCloseIconTemplate.cloneNode(true);
6384 this.innerElement.appendChild(oClose);
6386 oClose.innerHTML = (strings && strings.close) ? strings.close : " ";
6388 Event.on(oClose, "click", this._doClose, this, true);
6390 this.close = oClose;
6393 oClose.style.display = "block";
6398 oClose.style.display = "none";
6405 * Event handler for the close icon
6410 * @param {DOMEvent} e
6412 _doClose : function (e) {
6413 Event.preventDefault(e);
6418 * The default event handler fired when the "draggable" property
6420 * @method configDraggable
6421 * @param {String} type The CustomEvent type (usually the property name)
6422 * @param {Object[]} args The CustomEvent arguments. For configuration
6423 * handlers, args[0] will equal the newly applied value for the property.
6424 * @param {Object} obj The scope object. For configuration handlers,
6425 * this will usually equal the owner.
6427 configDraggable: function (type, args, obj) {
6432 YAHOO.log("DD dependency not met.", "error");
6433 this.cfg.setProperty("draggable", false);
6438 Dom.setStyle(this.header, "cursor", "move");
6439 this.registerDragDrop();
6442 this.subscribe("beforeShow", setWidthToOffsetWidth);
6451 Dom.setStyle(this.header,"cursor","auto");
6454 this.unsubscribe("beforeShow", setWidthToOffsetWidth);
6459 * The default event handler fired when the "underlay" property
6461 * @method configUnderlay
6462 * @param {String} type The CustomEvent type (usually the property name)
6463 * @param {Object[]} args The CustomEvent arguments. For configuration
6464 * handlers, args[0] will equal the newly applied value for the property.
6465 * @param {Object} obj The scope object. For configuration handlers,
6466 * this will usually equal the owner.
6468 configUnderlay: function (type, args, obj) {
6470 var bMacGecko = (this.platform == "mac" && UA.gecko),
6471 sUnderlay = args[0].toLowerCase(),
6472 oUnderlay = this.underlay,
6473 oElement = this.element;
6475 function createUnderlay() {
6477 if (!oUnderlay) { // create if not already in DOM
6479 if (!m_oUnderlayTemplate) {
6480 m_oUnderlayTemplate = document.createElement("div");
6481 m_oUnderlayTemplate.className = "underlay";
6484 oUnderlay = m_oUnderlayTemplate.cloneNode(false);
6485 this.element.appendChild(oUnderlay);
6487 this.underlay = oUnderlay;
6490 this.sizeUnderlay();
6491 this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
6492 this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
6494 this.changeContentEvent.subscribe(this.sizeUnderlay);
6495 YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
6498 if (UA.webkit && UA.webkit < 420) {
6499 this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
6506 function onBeforeShow() {
6507 var bNew = createUnderlay.call(this);
6508 if (!bNew && bIEQuirks) {
6509 this.sizeUnderlay();
6511 this._underlayDeferred = false;
6512 this.beforeShowEvent.unsubscribe(onBeforeShow);
6515 function destroyUnderlay() {
6516 if (this._underlayDeferred) {
6517 this.beforeShowEvent.unsubscribe(onBeforeShow);
6518 this._underlayDeferred = false;
6522 this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
6523 this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
6524 this.changeContentEvent.unsubscribe(this.sizeUnderlay);
6525 this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
6526 YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
6528 this.element.removeChild(oUnderlay);
6530 this.underlay = null;
6534 switch (sUnderlay) {
6536 Dom.removeClass(oElement, "matte");
6537 Dom.addClass(oElement, "shadow");
6541 destroyUnderlay.call(this);
6543 Dom.removeClass(oElement, "shadow");
6544 Dom.addClass(oElement, "matte");
6548 destroyUnderlay.call(this);
6550 Dom.removeClass(oElement, "shadow");
6551 Dom.removeClass(oElement, "matte");
6555 if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
6556 if (this.cfg.getProperty("visible")) {
6557 var bNew = createUnderlay.call(this);
6558 if (!bNew && bIEQuirks) {
6559 this.sizeUnderlay();
6562 if (!this._underlayDeferred) {
6563 this.beforeShowEvent.subscribe(onBeforeShow);
6564 this._underlayDeferred = true;
6571 * The default event handler fired when the "modal" property is
6572 * changed. This handler subscribes or unsubscribes to the show and hide
6573 * events to handle the display or hide of the modality mask.
6574 * @method configModal
6575 * @param {String} type The CustomEvent type (usually the property name)
6576 * @param {Object[]} args The CustomEvent arguments. For configuration
6577 * handlers, args[0] will equal the newly applied value for the property.
6578 * @param {Object} obj The scope object. For configuration handlers,
6579 * this will usually equal the owner.
6581 configModal: function (type, args, obj) {
6583 var modal = args[0];
6585 if (!this._hasModalityEventListeners) {
6587 this.subscribe("beforeShow", this.buildMask);
6588 this.subscribe("beforeShow", this.bringToTop);
6589 this.subscribe("beforeShow", this.showMask);
6590 this.subscribe("hide", this.hideMask);
6592 Overlay.windowResizeEvent.subscribe(this.sizeMask,
6595 this._hasModalityEventListeners = true;
6598 if (this._hasModalityEventListeners) {
6600 if (this.cfg.getProperty("visible")) {
6605 this.unsubscribe("beforeShow", this.buildMask);
6606 this.unsubscribe("beforeShow", this.bringToTop);
6607 this.unsubscribe("beforeShow", this.showMask);
6608 this.unsubscribe("hide", this.hideMask);
6610 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6612 this._hasModalityEventListeners = false;
6618 * Removes the modality mask.
6619 * @method removeMask
6621 removeMask: function () {
6623 var oMask = this.mask,
6628 Hide the mask before destroying it to ensure that DOM
6629 event handlers on focusable elements get removed.
6633 oParentNode = oMask.parentNode;
6635 oParentNode.removeChild(oMask);
6643 * The default event handler fired when the "keylisteners" property
6645 * @method configKeyListeners
6646 * @param {String} type The CustomEvent type (usually the property name)
6647 * @param {Object[]} args The CustomEvent arguments. For configuration
6648 * handlers, args[0] will equal the newly applied value for the property.
6649 * @param {Object} obj The scope object. For configuration handlers,
6650 * this will usually equal the owner.
6652 configKeyListeners: function (type, args, obj) {
6654 var listeners = args[0],
6661 if (listeners instanceof Array) {
6663 nListeners = listeners.length;
6665 for (i = 0; i < nListeners; i++) {
6667 listener = listeners[i];
6669 if (!Config.alreadySubscribed(this.showEvent,
6670 listener.enable, listener)) {
6672 this.showEvent.subscribe(listener.enable,
6677 if (!Config.alreadySubscribed(this.hideEvent,
6678 listener.disable, listener)) {
6680 this.hideEvent.subscribe(listener.disable,
6683 this.destroyEvent.subscribe(listener.disable,
6690 if (!Config.alreadySubscribed(this.showEvent,
6691 listeners.enable, listeners)) {
6693 this.showEvent.subscribe(listeners.enable,
6697 if (!Config.alreadySubscribed(this.hideEvent,
6698 listeners.disable, listeners)) {
6700 this.hideEvent.subscribe(listeners.disable,
6703 this.destroyEvent.subscribe(listeners.disable,
6715 * The default handler for the "strings" property
6716 * @method configStrings
6718 configStrings : function(type, args, obj) {
6719 var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
6720 this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
6724 * The default event handler fired when the "height" property is changed.
6725 * @method configHeight
6726 * @param {String} type The CustomEvent type (usually the property name)
6727 * @param {Object[]} args The CustomEvent arguments. For configuration
6728 * handlers, args[0] will equal the newly applied value for the property.
6729 * @param {Object} obj The scope object. For configuration handlers,
6730 * this will usually equal the owner.
6732 configHeight: function (type, args, obj) {
6733 var height = args[0],
6734 el = this.innerElement;
6736 Dom.setStyle(el, "height", height);
6737 this.cfg.refireEvent("iframe");
6741 * The default custom event handler executed when the Panel's height is changed,
6742 * if the autofillheight property has been set.
6744 * @method _autoFillOnHeightChange
6746 * @param {String} type The event type
6747 * @param {Array} args The array of arguments passed to event subscribers
6748 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
6749 * out the containers height
6751 _autoFillOnHeightChange : function(type, args, el) {
6752 Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
6755 setTimeout(function() {
6756 panel.sizeUnderlay();
6762 * The default event handler fired when the "width" property is changed.
6763 * @method configWidth
6764 * @param {String} type The CustomEvent type (usually the property name)
6765 * @param {Object[]} args The CustomEvent arguments. For configuration
6766 * handlers, args[0] will equal the newly applied value for the property.
6767 * @param {Object} obj The scope object. For configuration handlers,
6768 * this will usually equal the owner.
6770 configWidth: function (type, args, obj) {
6772 var width = args[0],
6773 el = this.innerElement;
6775 Dom.setStyle(el, "width", width);
6776 this.cfg.refireEvent("iframe");
6781 * The default event handler fired when the "zIndex" property is changed.
6782 * @method configzIndex
6783 * @param {String} type The CustomEvent type (usually the property name)
6784 * @param {Object[]} args The CustomEvent arguments. For configuration
6785 * handlers, args[0] will equal the newly applied value for the property.
6786 * @param {Object} obj The scope object. For configuration handlers,
6787 * this will usually equal the owner.
6789 configzIndex: function (type, args, obj) {
6790 Panel.superclass.configzIndex.call(this, type, args, obj);
6792 if (this.mask || this.cfg.getProperty("modal") === true) {
6793 var panelZ = Dom.getStyle(this.element, "zIndex");
6794 if (!panelZ || isNaN(panelZ)) {
6799 // Recursive call to configzindex (which should be stopped
6800 // from going further because panelZ should no longer === 0)
6801 this.cfg.setProperty("zIndex", 1);
6808 // END BUILT-IN PROPERTY EVENT HANDLERS //
6810 * Builds the wrapping container around the Panel that is used for
6811 * positioning the shadow and matte underlays. The container element is
6812 * assigned to a local instance variable called container, and the
6813 * element is reinserted inside of it.
6814 * @method buildWrapper
6816 buildWrapper: function () {
6818 var elementParent = this.element.parentNode,
6819 originalElement = this.element,
6820 wrapper = document.createElement("div");
6822 wrapper.className = Panel.CSS_PANEL_CONTAINER;
6823 wrapper.id = originalElement.id + "_c";
6825 if (elementParent) {
6826 elementParent.insertBefore(wrapper, originalElement);
6829 wrapper.appendChild(originalElement);
6831 this.element = wrapper;
6832 this.innerElement = originalElement;
6834 Dom.setStyle(this.innerElement, "visibility", "inherit");
6838 * Adjusts the size of the shadow based on the size of the element.
6839 * @method sizeUnderlay
6841 sizeUnderlay: function () {
6842 var oUnderlay = this.underlay,
6846 oElement = this.element;
6847 oUnderlay.style.width = oElement.offsetWidth + "px";
6848 oUnderlay.style.height = oElement.offsetHeight + "px";
6853 * Registers the Panel's header for drag & drop capability.
6854 * @method registerDragDrop
6856 registerDragDrop: function () {
6863 YAHOO.log("DD dependency not met.", "error");
6867 var bDragOnly = (this.cfg.getProperty("dragonly") === true);
6868 this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
6870 if (!this.header.id) {
6871 this.header.id = this.id + "_h";
6874 this.dd.startDrag = function () {
6883 if (YAHOO.env.ua.ie == 6) {
6884 Dom.addClass(me.element,"drag");
6887 if (me.cfg.getProperty("constraintoviewport")) {
6889 var nViewportOffset = Overlay.VIEWPORT_OFFSET;
6891 offsetHeight = me.element.offsetHeight;
6892 offsetWidth = me.element.offsetWidth;
6894 viewPortWidth = Dom.getViewportWidth();
6895 viewPortHeight = Dom.getViewportHeight();
6897 scrollX = Dom.getDocumentScrollLeft();
6898 scrollY = Dom.getDocumentScrollTop();
6900 if (offsetHeight + nViewportOffset < viewPortHeight) {
6901 this.minY = scrollY + nViewportOffset;
6902 this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
6904 this.minY = scrollY + nViewportOffset;
6905 this.maxY = scrollY + nViewportOffset;
6908 if (offsetWidth + nViewportOffset < viewPortWidth) {
6909 this.minX = scrollX + nViewportOffset;
6910 this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
6912 this.minX = scrollX + nViewportOffset;
6913 this.maxX = scrollX + nViewportOffset;
6916 this.constrainX = true;
6917 this.constrainY = true;
6919 this.constrainX = false;
6920 this.constrainY = false;
6923 me.dragEvent.fire("startDrag", arguments);
6926 this.dd.onDrag = function () {
6928 me.cfg.refireEvent("iframe");
6929 if (this.platform == "mac" && YAHOO.env.ua.gecko) {
6930 this.showMacGeckoScrollbars();
6933 me.dragEvent.fire("onDrag", arguments);
6936 this.dd.endDrag = function () {
6938 if (YAHOO.env.ua.ie == 6) {
6939 Dom.removeClass(me.element,"drag");
6942 me.dragEvent.fire("endDrag", arguments);
6943 me.moveEvent.fire(me.cfg.getProperty("xy"));
6947 this.dd.setHandleElId(this.header.id);
6948 this.dd.addInvalidHandleType("INPUT");
6949 this.dd.addInvalidHandleType("SELECT");
6950 this.dd.addInvalidHandleType("TEXTAREA");
6955 * Builds the mask that is laid over the document when the Panel is
6956 * configured to be modal.
6959 buildMask: function () {
6960 var oMask = this.mask;
6962 if (!m_oMaskTemplate) {
6963 m_oMaskTemplate = document.createElement("div");
6964 m_oMaskTemplate.className = "mask";
6965 m_oMaskTemplate.innerHTML = " ";
6967 oMask = m_oMaskTemplate.cloneNode(true);
6968 oMask.id = this.id + "_mask";
6970 document.body.insertBefore(oMask, document.body.firstChild);
6974 if (YAHOO.env.ua.gecko && this.platform == "mac") {
6975 Dom.addClass(this.mask, "block-scrollbars");
6978 // Stack mask based on the element zindex
6984 * Hides the modality mask.
6987 hideMask: function () {
6988 if (this.cfg.getProperty("modal") && this.mask) {
6989 this.mask.style.display = "none";
6990 Dom.removeClass(document.body, "masked");
6991 this.hideMaskEvent.fire();
6996 * Shows the modality mask.
6999 showMask: function () {
7000 if (this.cfg.getProperty("modal") && this.mask) {
7001 Dom.addClass(document.body, "masked");
7003 this.mask.style.display = "block";
7004 this.showMaskEvent.fire();
7009 * Sets the size of the modality mask to cover the entire scrollable
7010 * area of the document
7013 sizeMask: function () {
7016 // Shrink mask first, so it doesn't affect the document size.
7017 var mask = this.mask,
7018 viewWidth = Dom.getViewportWidth(),
7019 viewHeight = Dom.getViewportHeight();
7021 if (mask.offsetHeight > viewHeight) {
7022 mask.style.height = viewHeight + "px";
7025 if (mask.offsetWidth > viewWidth) {
7026 mask.style.width = viewWidth + "px";
7029 // Then size it to the document
7030 mask.style.height = Dom.getDocumentHeight() + "px";
7031 mask.style.width = Dom.getDocumentWidth() + "px";
7036 * Sets the zindex of the mask, if it exists, based on the zindex of
7037 * the Panel element. The zindex of the mask is set to be one less
7038 * than the Panel element's zindex.
7040 * <p>NOTE: This method will not bump up the zindex of the Panel
7041 * to ensure that the mask has a non-negative zindex. If you require the
7042 * mask zindex to be 0 or higher, the zindex of the Panel
7043 * should be set to a value higher than 0, before this method is called.
7047 stackMask: function() {
7049 var panelZ = Dom.getStyle(this.element, "zIndex");
7050 if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
7051 Dom.setStyle(this.mask, "zIndex", panelZ - 1);
7057 * Renders the Panel by inserting the elements that are not already in
7058 * the main Panel into their correct places. Optionally appends the
7059 * Panel to the specified node prior to the render's execution. NOTE:
7060 * For Panels without existing markup, the appendToNode argument is
7061 * REQUIRED. If this argument is ommitted and the current element is
7062 * not present in the document, the function will return false,
7063 * indicating that the render was a failure.
7065 * @param {String} appendToNode The element id to which the Module
7066 * should be appended to prior to rendering <em>OR</em>
7067 * @param {HTMLElement} appendToNode The element to which the Module
7068 * should be appended to prior to rendering
7069 * @return {boolean} Success or failure of the render
7071 render: function (appendToNode) {
7073 return Panel.superclass.render.call(this,
7074 appendToNode, this.innerElement);
7079 * Removes the Panel element from the DOM and sets all child elements
7083 destroy: function () {
7084 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
7087 Event.purgeElement(this.close);
7089 Panel.superclass.destroy.call(this);
7093 * Forces the underlay element to be repainted through the application/removal
7094 * of a yui-force-redraw class to the underlay element.
7096 * @method forceUnderlayRedraw
7098 forceUnderlayRedraw : function () {
7099 var u = this.underlay;
7100 Dom.addClass(u, "yui-force-redraw");
7101 setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
7105 * Returns a String representation of the object.
7107 * @return {String} The string representation of the Panel.
7109 toString: function () {
7110 return "Panel " + this.id;
7121 * Dialog is an implementation of Panel that can be used to submit form
7125 * Built-in functionality for buttons with event handlers is included.
7126 * If the optional YUI Button dependancy is included on the page, the buttons
7127 * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
7131 * Forms can be processed in 3 ways -- via an asynchronous Connection utility call,
7132 * a simple form POST or GET, or manually. The YUI Connection utility should be
7133 * included if you're using the default "async" postmethod, but is not required if
7134 * you're using any of the other postmethod values.
7136 * @namespace YAHOO.widget
7138 * @extends YAHOO.widget.Panel
7140 * @param {String} el The element ID representing the Dialog <em>OR</em>
7141 * @param {HTMLElement} el The element representing the Dialog
7142 * @param {Object} userConfig The configuration object literal containing
7143 * the configuration that should be set for this Dialog. See configuration
7144 * documentation for more details.
7146 YAHOO.widget.Dialog = function (el, userConfig) {
7147 YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
7150 var Event = YAHOO.util.Event,
7151 CustomEvent = YAHOO.util.CustomEvent,
7152 Dom = YAHOO.util.Dom,
7153 Dialog = YAHOO.widget.Dialog,
7157 * Constant representing the name of the Dialog's events
7158 * @property EVENT_TYPES
7164 "BEFORE_SUBMIT": "beforeSubmit",
7166 "MANUAL_SUBMIT": "manualSubmit",
7167 "ASYNC_SUBMIT": "asyncSubmit",
7168 "FORM_SUBMIT": "formSubmit",
7173 * Constant representing the Dialog's configuration properties
7174 * @property DEFAULT_CONFIG
7194 supercedes: ["visible"]
7197 "HIDEAFTERSUBMIT" : {
7198 key: "hideaftersubmit",
7205 * Constant representing the default CSS class used for a Dialog
7206 * @property YAHOO.widget.Dialog.CSS_DIALOG
7211 Dialog.CSS_DIALOG = "yui-dialog";
7213 function removeButtonEventHandlers() {
7215 var aButtons = this._aButtons,
7220 if (Lang.isArray(aButtons)) {
7221 nButtons = aButtons.length;
7226 oButton = aButtons[i];
7228 if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
7231 else if (oButton.tagName.toUpperCase() == "BUTTON") {
7232 Event.purgeElement(oButton);
7233 Event.purgeElement(oButton, false);
7241 YAHOO.extend(Dialog, YAHOO.widget.Panel, {
7245 * @description Object reference to the Dialog's
7246 * <code><form></code> element.
7248 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7249 * level-one-html.html#ID-40002357">HTMLFormElement</a>
7254 * Initializes the class's configurable properties which can be changed
7255 * using the Dialog's Config object (cfg).
7256 * @method initDefaultConfig
7258 initDefaultConfig: function () {
7259 Dialog.superclass.initDefaultConfig.call(this);
7262 * The internally maintained callback object for use with the
7263 * Connection utility. The format of the callback object is
7264 * similar to Connection Manager's callback object and is
7265 * simply passed through to Connection Manager when the async
7267 * @property callback
7273 * The function to execute upon success of the
7274 * Connection submission (when the form does not
7275 * contain a file input element).
7277 * @property callback.success
7283 * The function to execute upon failure of the
7284 * Connection submission
7285 * @property callback.failure
7292 * The function to execute upon success of the
7293 * Connection submission, when the form contains
7294 * a file input element.
7297 * <em>NOTE:</em> Connection manager will not
7298 * invoke the success or failure handlers for the file
7299 * upload use case. This will be the only callback
7303 * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
7304 * Connection Manager documenation on file uploads</a>.
7306 * @property callback.upload
7311 * The arbitraty argument or arguments to pass to the Connection
7312 * callback functions
7313 * @property callback.argument
7320 // Add form dialog config properties //
7322 * The method to use for posting the Dialog's form. Possible values
7323 * are "async", "form", and "manual".
7324 * @config postmethod
7328 this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
7329 handler: this.configPostMethod,
7330 value: DEFAULT_CONFIG.POST_METHOD.value,
7331 validator: function (val) {
7332 if (val != "form" && val != "async" && val != "none" &&
7342 * Any additional post data which needs to be sent when using the
7343 * <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
7344 * The format for the post data string is defined by Connection Manager's
7345 * <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a>
7351 this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
7352 value: DEFAULT_CONFIG.POST_DATA.value
7356 * This property is used to configure whether or not the
7357 * dialog should be automatically hidden after submit.
7359 * @config hideaftersubmit
7363 this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
7364 value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
7368 * Array of object literals, each containing a set of properties
7369 * defining a button to be appended into the Dialog's footer.
7371 * <p>Each button object in the buttons array can have three properties:</p>
7375 * The text that will display on the face of the button. The text can
7376 * include HTML, as long as it is compliant with HTML Button specifications.
7379 * <dd>Can be either:
7381 * <li>A reference to a function that should fire when the
7382 * button is clicked. (In this case scope of this function is
7383 * always its Dialog instance.)</li>
7385 * <li>An object literal representing the code to be
7386 * executed when the button is clicked.
7393 * <strong>fn:</strong> Function, //
7394 * The handler to call when the event fires.
7396 * <strong>obj:</strong> Object, //
7397 * An object to pass back to the handler.
7399 * <strong>scope:</strong> Object //
7400 * The object to use for the scope of the handler.
7407 * <dt>isDefault:</dt>
7409 * An optional boolean value that specifies that a button
7410 * should be highlighted and focused by default.
7414 * <em>NOTE:</em>If the YUI Button Widget is included on the page,
7415 * the buttons created will be instances of YAHOO.widget.Button.
7416 * Otherwise, HTML Buttons (<code><BUTTON></code>) will be
7420 * @type {Array|String}
7423 this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
7424 handler: this.configButtons,
7425 value: DEFAULT_CONFIG.BUTTONS.value,
7426 supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
7432 * Initializes the custom events for Dialog which are fired
7433 * automatically at appropriate times by the Dialog class.
7434 * @method initEvents
7436 initEvents: function () {
7437 Dialog.superclass.initEvents.call(this);
7439 var SIGNATURE = CustomEvent.LIST;
7442 * CustomEvent fired prior to submission
7443 * @event beforeSubmitEvent
7445 this.beforeSubmitEvent =
7446 this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
7447 this.beforeSubmitEvent.signature = SIGNATURE;
7450 * CustomEvent fired after submission
7451 * @event submitEvent
7453 this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
7454 this.submitEvent.signature = SIGNATURE;
7457 * CustomEvent fired for manual submission, before the generic submit event is fired
7458 * @event manualSubmitEvent
7460 this.manualSubmitEvent =
7461 this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
7462 this.manualSubmitEvent.signature = SIGNATURE;
7465 * CustomEvent fired after asynchronous submission, before the generic submit event is fired
7467 * @event asyncSubmitEvent
7468 * @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
7470 this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
7471 this.asyncSubmitEvent.signature = SIGNATURE;
7474 * CustomEvent fired after form-based submission, before the generic submit event is fired
7475 * @event formSubmitEvent
7477 this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
7478 this.formSubmitEvent.signature = SIGNATURE;
7481 * CustomEvent fired after cancel
7482 * @event cancelEvent
7484 this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
7485 this.cancelEvent.signature = SIGNATURE;
7490 * The Dialog initialization method, which is executed for Dialog and
7491 * all of its subclasses. This method is automatically called by the
7492 * constructor, and sets up all DOM references for pre-existing markup,
7493 * and creates required markup if it is not already present.
7496 * @param {String} el The element ID representing the Dialog <em>OR</em>
7497 * @param {HTMLElement} el The element representing the Dialog
7498 * @param {Object} userConfig The configuration object literal
7499 * containing the configuration that should be set for this Dialog.
7500 * See configuration documentation for more details.
7502 init: function (el, userConfig) {
7505 Note that we don't pass the user config in here yet because
7506 we only want it executed once, at the lowest subclass level
7509 Dialog.superclass.init.call(this, el/*, userConfig*/);
7511 this.beforeInitEvent.fire(Dialog);
7513 Dom.addClass(this.element, Dialog.CSS_DIALOG);
7515 this.cfg.setProperty("visible", false);
7518 this.cfg.applyConfig(userConfig, true);
7521 this.showEvent.subscribe(this.focusFirst, this, true);
7522 this.beforeHideEvent.subscribe(this.blurButtons, this, true);
7524 this.subscribe("changeBody", this.registerForm);
7526 this.initEvent.fire(Dialog);
7530 * Submits the Dialog's form depending on the value of the
7531 * "postmethod" configuration property. <strong>Please note:
7532 * </strong> As of version 2.3 this method will automatically handle
7533 * asyncronous file uploads should the Dialog instance's form contain
7534 * <code><input type="file"></code> elements. If a Dialog
7535 * instance will be handling asyncronous file uploads, its
7536 * <code>callback</code> property will need to be setup with a
7537 * <code>upload</code> handler rather than the standard
7538 * <code>success</code> and, or <code>failure</code> handlers. For more
7539 * information, see the <a href="http://developer.yahoo.com/yui/
7540 * connection/#file">Connection Manager documenation on file uploads</a>.
7543 doSubmit: function () {
7545 var Connect = YAHOO.util.Connect,
7547 bUseFileUpload = false,
7548 bUseSecureFileUpload = false,
7554 switch (this.cfg.getProperty("postmethod")) {
7557 aElements = oForm.elements;
7558 nElements = aElements.length;
7560 if (nElements > 0) {
7563 if (aElements[i].type == "file") {
7564 bUseFileUpload = true;
7571 if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
7572 bUseSecureFileUpload = true;
7575 formAttrs = this._getFormAttributes(oForm);
7577 Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
7579 var postData = this.cfg.getProperty("postdata");
7580 var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
7582 this.asyncSubmitEvent.fire(c);
7588 this.formSubmitEvent.fire();
7593 this.manualSubmitEvent.fire();
7599 * Retrieves important attributes (currently method and action) from
7600 * the form element, accounting for any elements which may have the same name
7601 * as the attributes. Defaults to "POST" and "" for method and action respectively
7602 * if the attribute cannot be retrieved.
7604 * @method _getFormAttributes
7606 * @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
7607 * @return {Object} Object literal, with method and action String properties.
7609 _getFormAttributes : function(oForm){
7616 if (oForm.getAttributeNode) {
7617 var action = oForm.getAttributeNode("action");
7618 var method = oForm.getAttributeNode("method");
7621 attrs.action = action.value;
7625 attrs.method = method.value;
7629 attrs.action = oForm.getAttribute("action");
7630 attrs.method = oForm.getAttribute("method");
7634 attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
7635 attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
7641 * Prepares the Dialog's internal FORM object, creating one if one is
7642 * not currently present.
7643 * @method registerForm
7645 registerForm: function() {
7647 var form = this.element.getElementsByTagName("form")[0];
7650 if (this.form == form && Dom.isAncestor(this.element, this.form)) {
7653 Event.purgeElement(this.form);
7659 form = document.createElement("form");
7660 form.name = "frm_" + this.id;
7661 this.body.appendChild(form);
7666 Event.on(form, "submit", this._submitHandler, this, true);
7671 * Internal handler for the form submit event
7673 * @method _submitHandler
7675 * @param {DOMEvent} e The DOM Event object
7677 _submitHandler : function(e) {
7684 * Sets up a tab, shift-tab loop between the first and last elements
7685 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
7686 * instance properties, which are reset everytime this method is invoked.
7688 * @method setTabLoop
7689 * @param {HTMLElement} firstElement
7690 * @param {HTMLElement} lastElement
7693 setTabLoop : function(firstElement, lastElement) {
7695 firstElement = firstElement || this.firstButton;
7696 lastElement = this.lastButton || lastElement;
7698 Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
7702 * Configures instance properties, pointing to the
7703 * first and last focusable elements in the Dialog's form.
7705 * @method setFirstLastFocusable
7707 setFirstLastFocusable : function() {
7709 Dialog.superclass.setFirstLastFocusable.call(this);
7711 var i, l, el, elements = this.focusableElements;
7713 this.firstFormElement = null;
7714 this.lastFormElement = null;
7716 if (this.form && elements && elements.length > 0) {
7717 l = elements.length;
7719 for (i = 0; i < l; ++i) {
7721 if (this.form === el.form) {
7722 this.firstFormElement = el;
7727 for (i = l-1; i >= 0; --i) {
7729 if (this.form === el.form) {
7730 this.lastFormElement = el;
7737 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7739 * The default event handler fired when the "close" property is
7740 * changed. The method controls the appending or hiding of the close
7741 * icon at the top right of the Dialog.
7742 * @method configClose
7743 * @param {String} type The CustomEvent type (usually the property name)
7744 * @param {Object[]} args The CustomEvent arguments. For
7745 * configuration handlers, args[0] will equal the newly applied value
7747 * @param {Object} obj The scope object. For configuration handlers,
7748 * this will usually equal the owner.
7750 configClose: function (type, args, obj) {
7751 Dialog.superclass.configClose.apply(this, arguments);
7755 * Event handler for the close icon
7760 * @param {DOMEvent} e
7762 _doClose : function(e) {
7763 Event.preventDefault(e);
7768 * The default event handler for the "buttons" configuration property
7769 * @method configButtons
7770 * @param {String} type The CustomEvent type (usually the property name)
7771 * @param {Object[]} args The CustomEvent arguments. For configuration
7772 * handlers, args[0] will equal the newly applied value for the property.
7773 * @param {Object} obj The scope object. For configuration handlers,
7774 * this will usually equal the owner.
7776 configButtons: function (type, args, obj) {
7778 var Button = YAHOO.widget.Button,
7780 oInnerElement = this.innerElement,
7789 removeButtonEventHandlers.call(this);
7791 this._aButtons = null;
7793 if (Lang.isArray(aButtons)) {
7795 oSpan = document.createElement("span");
7796 oSpan.className = "button-group";
7797 nButtons = aButtons.length;
7799 this._aButtons = [];
7800 this.defaultHtmlButton = null;
7802 for (i = 0; i < nButtons; i++) {
7803 oButton = aButtons[i];
7806 oYUIButton = new Button({ label: oButton.text});
7807 oYUIButton.appendTo(oSpan);
7809 oButtonEl = oYUIButton.get("element");
7811 if (oButton.isDefault) {
7812 oYUIButton.addClass("default");
7813 this.defaultHtmlButton = oButtonEl;
7816 if (Lang.isFunction(oButton.handler)) {
7818 oYUIButton.set("onclick", {
7819 fn: oButton.handler,
7824 } else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
7826 oYUIButton.set("onclick", {
7827 fn: oButton.handler.fn,
7828 obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7829 scope: (oButton.handler.scope || this)
7834 this._aButtons[this._aButtons.length] = oYUIButton;
7838 oButtonEl = document.createElement("button");
7839 oButtonEl.setAttribute("type", "button");
7841 if (oButton.isDefault) {
7842 oButtonEl.className = "default";
7843 this.defaultHtmlButton = oButtonEl;
7846 oButtonEl.innerHTML = oButton.text;
7848 if (Lang.isFunction(oButton.handler)) {
7849 Event.on(oButtonEl, "click", oButton.handler, this, true);
7850 } else if (Lang.isObject(oButton.handler) &&
7851 Lang.isFunction(oButton.handler.fn)) {
7853 Event.on(oButtonEl, "click",
7855 ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7856 (oButton.handler.scope || this));
7859 oSpan.appendChild(oButtonEl);
7860 this._aButtons[this._aButtons.length] = oButtonEl;
7863 oButton.htmlButton = oButtonEl;
7866 this.firstButton = oButtonEl;
7869 if (i == (nButtons - 1)) {
7870 this.lastButton = oButtonEl;
7874 this.setFooter(oSpan);
7876 oFooter = this.footer;
7878 if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
7879 oInnerElement.appendChild(oFooter);
7882 this.buttonSpan = oSpan;
7884 } else { // Do cleanup
7885 oSpan = this.buttonSpan;
7886 oFooter = this.footer;
7887 if (oSpan && oFooter) {
7888 oFooter.removeChild(oSpan);
7889 this.buttonSpan = null;
7890 this.firstButton = null;
7891 this.lastButton = null;
7892 this.defaultHtmlButton = null;
7896 this.changeContentEvent.fire();
7900 * @method getButtons
7901 * @description Returns an array containing each of the Dialog's
7902 * buttons, by default an array of HTML <code><BUTTON></code>
7903 * elements. If the Dialog's buttons were created using the
7904 * YAHOO.widget.Button class (via the inclusion of the optional Button
7905 * dependancy on the page), an array of YAHOO.widget.Button instances
7909 getButtons: function () {
7910 return this._aButtons || null;
7915 * Sets focus to the first focusable element in the Dialog's form if found,
7916 * else, the default button if found, else the first button defined via the
7917 * "buttons" configuration property.
7920 * This method is invoked when the Dialog is made visible.
7922 * @method focusFirst
7924 focusFirst: function (type, args, obj) {
7926 var el = this.firstFormElement;
7928 if (args && args[1]) {
7929 Event.stopEvent(args[1]);
7935 } catch(oException) {
7939 if (this.defaultHtmlButton) {
7940 this.focusDefaultButton();
7942 this.focusFirstButton();
7948 * Sets focus to the last element in the Dialog's form or the last
7949 * button defined via the "buttons" configuration property.
7952 focusLast: function (type, args, obj) {
7954 var aButtons = this.cfg.getProperty("buttons"),
7955 el = this.lastFormElement;
7957 if (args && args[1]) {
7958 Event.stopEvent(args[1]);
7961 if (aButtons && Lang.isArray(aButtons)) {
7962 this.focusLastButton();
7967 } catch(oException) {
7975 * Helper method to normalize button references. It either returns the
7976 * YUI Button instance for the given element if found,
7977 * or the passes back the HTMLElement reference if a corresponding YUI Button
7978 * reference is not found or YAHOO.widget.Button does not exist on the page.
7980 * @method _getButton
7982 * @param {HTMLElement} button
7983 * @return {YAHOO.widget.Button|HTMLElement}
7985 _getButton : function(button) {
7986 var Button = YAHOO.widget.Button;
7988 // If we have an HTML button and YUI Button is on the page,
7989 // get the YUI Button reference if available.
7990 if (Button && button && button.nodeName && button.id) {
7991 button = Button.getButton(button.id) || button;
7998 * Sets the focus to the button that is designated as the default via
7999 * the "buttons" configuration property. By default, this method is
8000 * called when the Dialog is made visible.
8001 * @method focusDefaultButton
8003 focusDefaultButton: function () {
8004 var button = this._getButton(this.defaultHtmlButton);
8007 Place the call to the "focus" method inside a try/catch
8008 block to prevent IE from throwing JavaScript errors if
8009 the element is disabled or hidden.
8013 } catch(oException) {
8019 * Blurs all the buttons defined via the "buttons"
8020 * configuration property.
8021 * @method blurButtons
8023 blurButtons: function () {
8025 var aButtons = this.cfg.getProperty("buttons"),
8031 if (aButtons && Lang.isArray(aButtons)) {
8032 nButtons = aButtons.length;
8036 oButton = aButtons[i];
8038 oElement = this._getButton(oButton.htmlButton);
8041 Place the call to the "blur" method inside
8042 a try/catch block to prevent IE from
8043 throwing JavaScript errors if the element
8044 is disabled or hidden.
8048 } catch(oException) {
8059 * Sets the focus to the first button created via the "buttons"
8060 * configuration property.
8061 * @method focusFirstButton
8063 focusFirstButton: function () {
8065 var aButtons = this.cfg.getProperty("buttons"),
8069 if (aButtons && Lang.isArray(aButtons)) {
8070 oButton = aButtons[0];
8072 oElement = this._getButton(oButton.htmlButton);
8075 Place the call to the "focus" method inside a
8076 try/catch block to prevent IE from throwing
8077 JavaScript errors if the element is disabled
8082 } catch(oException) {
8091 * Sets the focus to the last button created via the "buttons"
8092 * configuration property.
8093 * @method focusLastButton
8095 focusLastButton: function () {
8097 var aButtons = this.cfg.getProperty("buttons"),
8102 if (aButtons && Lang.isArray(aButtons)) {
8103 nButtons = aButtons.length;
8105 oButton = aButtons[(nButtons - 1)];
8108 oElement = this._getButton(oButton.htmlButton);
8111 Place the call to the "focus" method inside a
8112 try/catch block to prevent IE from throwing
8113 JavaScript errors if the element is disabled
8119 } catch(oException) {
8129 * The default event handler for the "postmethod" configuration property
8130 * @method configPostMethod
8131 * @param {String} type The CustomEvent type (usually the property name)
8132 * @param {Object[]} args The CustomEvent arguments. For
8133 * configuration handlers, args[0] will equal the newly applied value
8135 * @param {Object} obj The scope object. For configuration handlers,
8136 * this will usually equal the owner.
8138 configPostMethod: function (type, args, obj) {
8139 this.registerForm();
8142 // END BUILT-IN PROPERTY EVENT HANDLERS //
8145 * Built-in function hook for writing a validation function that will
8146 * be checked for a "true" value prior to a submit. This function, as
8147 * implemented by default, always returns true, so it should be
8148 * overridden if validation is necessary.
8151 validate: function () {
8156 * Executes a submit of the Dialog if validation
8157 * is successful. By default the Dialog is hidden
8158 * after submission, but you can set the "hideaftersubmit"
8159 * configuration property to false, to prevent the Dialog
8160 * from being hidden.
8164 submit: function () {
8165 if (this.validate()) {
8166 this.beforeSubmitEvent.fire();
8168 this.submitEvent.fire();
8170 if (this.cfg.getProperty("hideaftersubmit")) {
8181 * Executes the cancel of the Dialog followed by a hide.
8184 cancel: function () {
8185 this.cancelEvent.fire();
8190 * Returns a JSON-compatible data structure representing the data
8191 * currently contained in the form.
8193 * @return {Object} A JSON object reprsenting the data of the
8196 getData: function () {
8198 var oForm = this.form,
8217 function isFormElement(p_oElement) {
8218 var sTag = p_oElement.tagName.toUpperCase();
8219 return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
8220 sTag == "SELECT") && p_oElement.name == sName);
8225 aElements = oForm.elements;
8226 nTotalElements = aElements.length;
8229 for (i = 0; i < nTotalElements; i++) {
8230 sName = aElements[i].name;
8233 Using "Dom.getElementsBy" to safeguard user from JS
8234 errors that result from giving a form field (or set of
8235 fields) the same name as a native method of a form
8236 (like "submit") or a DOM collection (such as the "item"
8237 method). Originally tried accessing fields via the
8238 "namedItem" method of the "element" collection, but
8239 discovered that it won't return a collection of fields
8243 oElement = Dom.getElementsBy(isFormElement, "*", oForm);
8244 nElements = oElement.length;
8246 if (nElements > 0) {
8247 if (nElements == 1) {
8248 oElement = oElement[0];
8250 sType = oElement.type;
8251 sTagName = oElement.tagName.toUpperCase();
8255 if (sType == "checkbox") {
8256 oData[sName] = oElement.checked;
8257 } else if (sType != "radio") {
8258 oData[sName] = oElement.value;
8263 oData[sName] = oElement.value;
8267 aOptions = oElement.options;
8268 nOptions = aOptions.length;
8271 for (n = 0; n < nOptions; n++) {
8272 oOption = aOptions[n];
8274 if (oOption.selected) {
8275 sValue = oOption.value;
8276 if (!sValue || sValue === "") {
8277 sValue = oOption.text;
8279 aValues[aValues.length] = sValue;
8282 oData[sName] = aValues;
8287 sType = oElement[0].type;
8290 for (n = 0; n < nElements; n++) {
8291 oRadio = oElement[n];
8292 if (oRadio.checked) {
8293 oData[sName] = oRadio.value;
8301 for (n = 0; n < nElements; n++) {
8302 oCheckbox = oElement[n];
8303 if (oCheckbox.checked) {
8304 aValues[aValues.length] = oCheckbox.value;
8307 oData[sName] = aValues;
8319 * Removes the Panel element from the DOM and sets all child elements
8323 destroy: function () {
8324 removeButtonEventHandlers.call(this);
8326 this._aButtons = null;
8328 var aForms = this.element.getElementsByTagName("form"),
8331 if (aForms.length > 0) {
8335 Event.purgeElement(oForm);
8336 if (oForm.parentNode) {
8337 oForm.parentNode.removeChild(oForm);
8342 Dialog.superclass.destroy.call(this);
8346 * Returns a string representation of the object.
8348 * @return {String} The string representation of the Dialog
8350 toString: function () {
8351 return "Dialog " + this.id;
8361 * SimpleDialog is a simple implementation of Dialog that can be used to
8362 * submit a single value. Forms can be processed in 3 ways -- via an
8363 * asynchronous Connection utility call, a simple form POST or GET,
8365 * @namespace YAHOO.widget
8366 * @class SimpleDialog
8367 * @extends YAHOO.widget.Dialog
8369 * @param {String} el The element ID representing the SimpleDialog
8371 * @param {HTMLElement} el The element representing the SimpleDialog
8372 * @param {Object} userConfig The configuration object literal containing
8373 * the configuration that should be set for this SimpleDialog. See
8374 * configuration documentation for more details.
8376 YAHOO.widget.SimpleDialog = function (el, userConfig) {
8378 YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
8383 var Dom = YAHOO.util.Dom,
8384 SimpleDialog = YAHOO.widget.SimpleDialog,
8387 * Constant representing the SimpleDialog's configuration properties
8388 * @property DEFAULT_CONFIG
8404 suppressEvent: true,
8405 supercedes: ["icon"]
8411 * Constant for the standard network icon for a blocking action
8412 * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
8417 SimpleDialog.ICON_BLOCK = "blckicon";
8420 * Constant for the standard network icon for alarm
8421 * @property YAHOO.widget.SimpleDialog.ICON_ALARM
8426 SimpleDialog.ICON_ALARM = "alrticon";
8429 * Constant for the standard network icon for help
8430 * @property YAHOO.widget.SimpleDialog.ICON_HELP
8435 SimpleDialog.ICON_HELP = "hlpicon";
8438 * Constant for the standard network icon for info
8439 * @property YAHOO.widget.SimpleDialog.ICON_INFO
8444 SimpleDialog.ICON_INFO = "infoicon";
8447 * Constant for the standard network icon for warn
8448 * @property YAHOO.widget.SimpleDialog.ICON_WARN
8453 SimpleDialog.ICON_WARN = "warnicon";
8456 * Constant for the standard network icon for a tip
8457 * @property YAHOO.widget.SimpleDialog.ICON_TIP
8462 SimpleDialog.ICON_TIP = "tipicon";
8465 * Constant representing the name of the CSS class applied to the element
8466 * created by the "icon" configuration property.
8467 * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
8472 SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
8475 * Constant representing the default CSS class used for a SimpleDialog
8476 * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
8481 SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
8484 YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
8487 * Initializes the class's configurable properties which can be changed
8488 * using the SimpleDialog's Config object (cfg).
8489 * @method initDefaultConfig
8491 initDefaultConfig: function () {
8493 SimpleDialog.superclass.initDefaultConfig.call(this);
8495 // Add dialog config properties //
8498 * Sets the informational icon for the SimpleDialog
8503 this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
8504 handler: this.configIcon,
8505 value: DEFAULT_CONFIG.ICON.value,
8506 suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
8510 * Sets the text for the SimpleDialog
8515 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
8516 handler: this.configText,
8517 value: DEFAULT_CONFIG.TEXT.value,
8518 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
8519 supercedes: DEFAULT_CONFIG.TEXT.supercedes
8526 * The SimpleDialog initialization method, which is executed for
8527 * SimpleDialog and all of its subclasses. This method is automatically
8528 * called by the constructor, and sets up all DOM references for
8529 * pre-existing markup, and creates required markup if it is not
8532 * @param {String} el The element ID representing the SimpleDialog
8534 * @param {HTMLElement} el The element representing the SimpleDialog
8535 * @param {Object} userConfig The configuration object literal
8536 * containing the configuration that should be set for this
8537 * SimpleDialog. See configuration documentation for more details.
8539 init: function (el, userConfig) {
8542 Note that we don't pass the user config in here yet because we
8543 only want it executed once, at the lowest subclass level
8546 SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
8548 this.beforeInitEvent.fire(SimpleDialog);
8550 Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
8552 this.cfg.queueProperty("postmethod", "manual");
8555 this.cfg.applyConfig(userConfig, true);
8558 this.beforeRenderEvent.subscribe(function () {
8564 this.initEvent.fire(SimpleDialog);
8569 * Prepares the SimpleDialog's internal FORM object, creating one if one
8570 * is not currently present, and adding the value hidden field.
8571 * @method registerForm
8573 registerForm: function () {
8575 SimpleDialog.superclass.registerForm.call(this);
8577 this.form.innerHTML += "<input type=\"hidden\" name=\"" +
8578 this.id + "\" value=\"\"/>";
8582 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
8585 * Fired when the "icon" property is set.
8586 * @method configIcon
8587 * @param {String} type The CustomEvent type (usually the property name)
8588 * @param {Object[]} args The CustomEvent arguments. For configuration
8589 * handlers, args[0] will equal the newly applied value for the property.
8590 * @param {Object} obj The scope object. For configuration handlers,
8591 * this will usually equal the owner.
8593 configIcon: function (type,args,obj) {
8595 var sIcon = args[0],
8597 sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
8601 if (sIcon && sIcon != "none") {
8603 oIcon = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
8607 oIconParent = oIcon.parentNode;
8611 oIconParent.removeChild(oIcon);
8620 if (sIcon.indexOf(".") == -1) {
8622 oIcon = document.createElement("span");
8623 oIcon.className = (sCSSClass + " " + sIcon);
8624 oIcon.innerHTML = " ";
8628 oIcon = document.createElement("img");
8629 oIcon.src = (this.imageRoot + sIcon);
8630 oIcon.className = sCSSClass;
8637 oBody.insertBefore(oIcon, oBody.firstChild);
8646 * Fired when the "text" property is set.
8647 * @method configText
8648 * @param {String} type The CustomEvent type (usually the property name)
8649 * @param {Object[]} args The CustomEvent arguments. For configuration
8650 * handlers, args[0] will equal the newly applied value for the property.
8651 * @param {Object} obj The scope object. For configuration handlers,
8652 * this will usually equal the owner.
8654 configText: function (type,args,obj) {
8658 this.cfg.refireEvent("icon");
8662 // END BUILT-IN PROPERTY EVENT HANDLERS //
8665 * Returns a string representation of the object.
8667 * @return {String} The string representation of the SimpleDialog
8669 toString: function () {
8670 return "SimpleDialog " + this.id;
8675 * Sets the SimpleDialog's body content to the HTML specified.
8676 * If no body is present, one will be automatically created.
8677 * An empty string can be passed to the method to clear the contents of the body.
8679 * <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
8680 * and <a href="#config_icon">icon</a> configuration properties to set the contents
8681 * of it's body element in accordance with the UI design for a SimpleDialog (an
8682 * icon and message text). Calling setBody on the SimpleDialog will not enforce this
8683 * UI design constraint and will replace the entire contents of the SimpleDialog body.
8684 * It should only be used if you wish the replace the default icon/text body structure
8685 * of a SimpleDialog with your own custom markup.</p>
8688 * @param {String} bodyContent The HTML used to set the body.
8689 * As a convenience, non HTMLElement objects can also be passed into
8690 * the method, and will be treated as strings, with the body innerHTML
8691 * set to their default toString implementations.
8693 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
8695 * @param {DocumentFragment} bodyContent The document fragment
8696 * containing elements which are to be added to the body
8705 * ContainerEffect encapsulates animation transitions that are executed when
8706 * an Overlay is shown or hidden.
8707 * @namespace YAHOO.widget
8708 * @class ContainerEffect
8710 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
8711 * should be associated with
8712 * @param {Object} attrIn The object literal representing the animation
8713 * arguments to be used for the animate-in transition. The arguments for
8714 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8715 * duration(Number), and method(i.e. Easing.easeIn).
8716 * @param {Object} attrOut The object literal representing the animation
8717 * arguments to be used for the animate-out transition. The arguments for
8718 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8719 * duration(Number), and method(i.e. Easing.easeIn).
8720 * @param {HTMLElement} targetElement Optional. The target element that
8721 * should be animated during the transition. Defaults to overlay.element.
8722 * @param {class} Optional. The animation class to instantiate. Defaults to
8723 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
8725 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
8728 animClass = YAHOO.util.Anim;
8732 * The overlay to animate
8734 * @type YAHOO.widget.Overlay
8736 this.overlay = overlay;
8739 * The animation attributes to use when transitioning into view
8743 this.attrIn = attrIn;
8746 * The animation attributes to use when transitioning out of view
8750 this.attrOut = attrOut;
8753 * The target element to be animated
8754 * @property targetElement
8757 this.targetElement = targetElement || overlay.element;
8760 * The animation class to use for animating the overlay
8761 * @property animClass
8764 this.animClass = animClass;
8769 var Dom = YAHOO.util.Dom,
8770 CustomEvent = YAHOO.util.CustomEvent,
8771 ContainerEffect = YAHOO.widget.ContainerEffect;
8775 * A pre-configured ContainerEffect instance that can be used for fading
8776 * an overlay in and out.
8779 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8780 * @param {Number} dur The duration of the animation
8781 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8783 ContainerEffect.FADE = function (overlay, dur) {
8785 var Easing = YAHOO.util.Easing,
8787 attributes: {opacity:{from:0, to:1}},
8789 method: Easing.easeIn
8792 attributes: {opacity:{to:0}},
8794 method: Easing.easeOut
8796 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
8798 fade.handleUnderlayStart = function() {
8799 var underlay = this.overlay.underlay;
8800 if (underlay && YAHOO.env.ua.ie) {
8801 var hasFilters = (underlay.filters && underlay.filters.length > 0);
8803 Dom.addClass(overlay.element, "yui-effect-fade");
8808 fade.handleUnderlayComplete = function() {
8809 var underlay = this.overlay.underlay;
8810 if (underlay && YAHOO.env.ua.ie) {
8811 Dom.removeClass(overlay.element, "yui-effect-fade");
8815 fade.handleStartAnimateIn = function (type, args, obj) {
8816 Dom.addClass(obj.overlay.element, "hide-select");
8818 if (!obj.overlay.underlay) {
8819 obj.overlay.cfg.refireEvent("underlay");
8822 obj.handleUnderlayStart();
8824 obj.overlay._setDomVisibility(true);
8825 Dom.setStyle(obj.overlay.element, "opacity", 0);
8828 fade.handleCompleteAnimateIn = function (type,args,obj) {
8829 Dom.removeClass(obj.overlay.element, "hide-select");
8831 if (obj.overlay.element.style.filter) {
8832 obj.overlay.element.style.filter = null;
8835 obj.handleUnderlayComplete();
8837 obj.overlay.cfg.refireEvent("iframe");
8838 obj.animateInCompleteEvent.fire();
8841 fade.handleStartAnimateOut = function (type, args, obj) {
8842 Dom.addClass(obj.overlay.element, "hide-select");
8843 obj.handleUnderlayStart();
8846 fade.handleCompleteAnimateOut = function (type, args, obj) {
8847 Dom.removeClass(obj.overlay.element, "hide-select");
8848 if (obj.overlay.element.style.filter) {
8849 obj.overlay.element.style.filter = null;
8851 obj.overlay._setDomVisibility(false);
8852 Dom.setStyle(obj.overlay.element, "opacity", 1);
8854 obj.handleUnderlayComplete();
8856 obj.overlay.cfg.refireEvent("iframe");
8857 obj.animateOutCompleteEvent.fire();
8866 * A pre-configured ContainerEffect instance that can be used for sliding an
8867 * overlay in and out.
8870 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8871 * @param {Number} dur The duration of the animation
8872 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8874 ContainerEffect.SLIDE = function (overlay, dur) {
8875 var Easing = YAHOO.util.Easing,
8877 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
8878 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
8879 clientWidth = Dom.getClientWidth(),
8880 offsetWidth = overlay.element.offsetWidth,
8883 attributes: { points: { to: [x, y] } },
8885 method: Easing.easeIn
8889 attributes: { points: { to: [(clientWidth + 25), y] } },
8891 method: Easing.easeOut
8894 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
8896 slide.handleStartAnimateIn = function (type,args,obj) {
8897 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
8898 obj.overlay.element.style.top = y + "px";
8901 slide.handleTweenAnimateIn = function (type, args, obj) {
8903 var pos = Dom.getXY(obj.overlay.element),
8907 if (Dom.getStyle(obj.overlay.element, "visibility") ==
8908 "hidden" && currentX < x) {
8910 obj.overlay._setDomVisibility(true);
8914 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
8915 obj.overlay.cfg.refireEvent("iframe");
8918 slide.handleCompleteAnimateIn = function (type, args, obj) {
8919 obj.overlay.cfg.setProperty("xy", [x, y], true);
8922 obj.overlay.cfg.refireEvent("iframe");
8923 obj.animateInCompleteEvent.fire();
8926 slide.handleStartAnimateOut = function (type, args, obj) {
8928 var vw = Dom.getViewportWidth(),
8929 pos = Dom.getXY(obj.overlay.element),
8932 obj.animOut.attributes.points.to = [(vw + 25), yso];
8935 slide.handleTweenAnimateOut = function (type, args, obj) {
8937 var pos = Dom.getXY(obj.overlay.element),
8941 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
8942 obj.overlay.cfg.refireEvent("iframe");
8945 slide.handleCompleteAnimateOut = function (type, args, obj) {
8946 obj.overlay._setDomVisibility(false);
8948 obj.overlay.cfg.setProperty("xy", [x, y]);
8949 obj.animateOutCompleteEvent.fire();
8956 ContainerEffect.prototype = {
8959 * Initializes the animation classes and events.
8964 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
8965 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
8967 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
8968 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
8970 this.animateInCompleteEvent = this.createEvent("animateInComplete");
8971 this.animateInCompleteEvent.signature = CustomEvent.LIST;
8973 this.animateOutCompleteEvent =
8974 this.createEvent("animateOutComplete");
8975 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
8977 this.animIn = new this.animClass(this.targetElement,
8978 this.attrIn.attributes, this.attrIn.duration,
8979 this.attrIn.method);
8981 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
8982 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
8984 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
8987 this.animOut = new this.animClass(this.targetElement,
8988 this.attrOut.attributes, this.attrOut.duration,
8989 this.attrOut.method);
8991 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
8992 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
8993 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
8999 * Triggers the in-animation.
9002 animateIn: function () {
9003 this.beforeAnimateInEvent.fire();
9004 this.animIn.animate();
9008 * Triggers the out-animation.
9009 * @method animateOut
9011 animateOut: function () {
9012 this.beforeAnimateOutEvent.fire();
9013 this.animOut.animate();
9017 * The default onStart handler for the in-animation.
9018 * @method handleStartAnimateIn
9019 * @param {String} type The CustomEvent type
9020 * @param {Object[]} args The CustomEvent arguments
9021 * @param {Object} obj The scope object
9023 handleStartAnimateIn: function (type, args, obj) { },
9026 * The default onTween handler for the in-animation.
9027 * @method handleTweenAnimateIn
9028 * @param {String} type The CustomEvent type
9029 * @param {Object[]} args The CustomEvent arguments
9030 * @param {Object} obj The scope object
9032 handleTweenAnimateIn: function (type, args, obj) { },
9035 * The default onComplete handler for the in-animation.
9036 * @method handleCompleteAnimateIn
9037 * @param {String} type The CustomEvent type
9038 * @param {Object[]} args The CustomEvent arguments
9039 * @param {Object} obj The scope object
9041 handleCompleteAnimateIn: function (type, args, obj) { },
9044 * The default onStart handler for the out-animation.
9045 * @method handleStartAnimateOut
9046 * @param {String} type The CustomEvent type
9047 * @param {Object[]} args The CustomEvent arguments
9048 * @param {Object} obj The scope object
9050 handleStartAnimateOut: function (type, args, obj) { },
9053 * The default onTween handler for the out-animation.
9054 * @method handleTweenAnimateOut
9055 * @param {String} type The CustomEvent type
9056 * @param {Object[]} args The CustomEvent arguments
9057 * @param {Object} obj The scope object
9059 handleTweenAnimateOut: function (type, args, obj) { },
9062 * The default onComplete handler for the out-animation.
9063 * @method handleCompleteAnimateOut
9064 * @param {String} type The CustomEvent type
9065 * @param {Object[]} args The CustomEvent arguments
9066 * @param {Object} obj The scope object
9068 handleCompleteAnimateOut: function (type, args, obj) { },
9071 * Returns a string representation of the object.
9073 * @return {String} The string representation of the ContainerEffect
9075 toString: function () {
9076 var output = "ContainerEffect";
9078 output += " [" + this.overlay.toString() + "]";
9084 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
9088 YAHOO.register("container", YAHOO.widget.Module, {version: "2.7.0", build: "1799"});