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} overrideContext Optional. If true, will override
547 * "this" within the handler to map to the scope Object passed into the
549 * @return {Boolean} True, if the subscription was successful,
552 subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
554 var property = this.config[key.toLowerCase()];
556 if (property && property.event) {
557 if (!Config.alreadySubscribed(property.event, handler, obj)) {
558 property.event.subscribe(handler, obj, overrideContext);
568 * Unsubscribes an external handler from the change event for any
570 * @method unsubscribeFromConfigEvent
571 * @param {String} key The property name
572 * @param {Function} handler The handler function to use subscribe to
573 * the property's event
574 * @param {Object} obj The Object to use for scoping the event
575 * handler (see CustomEvent documentation)
576 * @return {Boolean} True, if the unsubscription was successful,
579 unsubscribeFromConfigEvent: function (key, handler, obj) {
580 var property = this.config[key.toLowerCase()];
581 if (property && property.event) {
582 return property.event.unsubscribe(handler, obj);
589 * Returns a string representation of the Config object
591 * @return {String} The Config object in string format.
593 toString: function () {
594 var output = "Config";
596 output += " [" + this.owner.toString() + "]";
602 * Returns a string representation of the Config object's current
604 * @method outputEventQueue
605 * @return {String} The string list of CustomEvents currently queued
608 outputEventQueue: function () {
613 nQueue = this.eventQueue.length;
615 for (q = 0; q < nQueue; q++) {
616 queueItem = this.eventQueue[q];
618 output += queueItem[0] + "=" + queueItem[1] + ", ";
625 * Sets all properties to null, unsubscribes all listeners from each
626 * property's change event and all listeners from the configChangedEvent.
629 destroy: function () {
631 var oConfig = this.config,
636 for (sProperty in oConfig) {
638 if (Lang.hasOwnProperty(oConfig, sProperty)) {
640 oProperty = oConfig[sProperty];
642 oProperty.event.unsubscribeAll();
643 oProperty.event = null;
649 this.configChangedEvent.unsubscribeAll();
651 this.configChangedEvent = null;
654 this.initialConfig = null;
655 this.eventQueue = null;
664 * Checks to determine if a particular function/Object pair are already
665 * subscribed to the specified CustomEvent
666 * @method YAHOO.util.Config.alreadySubscribed
668 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
670 * @param {Function} fn The function to look for in the subscribers list
671 * @param {Object} obj The execution scope Object for the subscription
672 * @return {Boolean} true, if the function/Object pair is already subscribed
673 * to the CustomEvent passed in
675 Config.alreadySubscribed = function (evt, fn, obj) {
677 var nSubscribers = evt.subscribers.length,
681 if (nSubscribers > 0) {
682 i = nSubscribers - 1;
684 subsc = evt.subscribers[i];
685 if (subsc && subsc.obj == obj && subsc.fn == fn) {
696 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 "DESTROY": "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.DESTROY);
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 YUILibrary 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 // Setting the background color fixes an issue with IE6/IE7, where
1418 // elements in the DOM, with -ve margin-top which positioned them
1419 // offscreen (so they would be overlapped by the iframe and its -ve top
1420 // setting), would have their -ve margin-top ignored, when the iframe
1422 oIFrame.style.backgroundColor = "transparent";
1424 oIFrame.style.borderWidth = "0";
1425 oIFrame.style.width = "2em";
1426 oIFrame.style.height = "2em";
1427 oIFrame.style.left = "0";
1428 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1429 oIFrame.style.visibility = "visible";
1432 Don't open/close the document for Gecko like we used to, since it
1433 leads to duplicate cookies. (See YUILibrary bug #1721755)
1436 oDoc = oIFrame.contentWindow.document;
1442 if (oIFrame && oIFrame.contentWindow) {
1443 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1445 if (!Module.textResizeInitialized) {
1446 if (supportsCWResize) {
1447 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1449 This will fail in IE if document.domain has
1450 changed, so we must change the listener to
1451 use the oIFrame element instead
1453 Event.on(oIFrame, "resize", fireTextResize);
1456 Module.textResizeInitialized = true;
1458 this.resizeMonitor = oIFrame;
1464 * Text resize monitor helper method.
1465 * Determines if the browser supports resize events on iframe content windows.
1468 * @method _supportsCWResize
1470 _supportsCWResize : function() {
1472 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1473 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1475 We don't want to start sniffing for patch versions, so fire textResize the same
1476 way on all FF2 flavors
1478 var bSupported = true;
1479 if (UA.gecko && UA.gecko <= 1.8) {
1486 * Event handler fired when the resize monitor element is resized.
1487 * @method onDomResize
1488 * @param {DOMEvent} e The DOM resize event
1489 * @param {Object} obj The scope object passed to the handler
1491 onDomResize: function (e, obj) {
1493 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1495 this.resizeMonitor.style.top = nTop + "px";
1496 this.resizeMonitor.style.left = "0";
1500 * Sets the Module's header content to the string specified, or appends
1501 * the passed element to the header. If no header is present, one will
1502 * be automatically created. An empty string can be passed to the method
1503 * to clear the contents of the header.
1506 * @param {String} headerContent The string used to set the header.
1507 * As a convenience, non HTMLElement objects can also be passed into
1508 * the method, and will be treated as strings, with the header innerHTML
1509 * set to their default toString implementations.
1511 * @param {HTMLElement} headerContent The HTMLElement to append to
1513 * @param {DocumentFragment} headerContent The document fragment
1514 * containing elements which are to be added to the header
1516 setHeader: function (headerContent) {
1517 var oHeader = this.header || (this.header = createHeader());
1519 if (headerContent.nodeName) {
1520 oHeader.innerHTML = "";
1521 oHeader.appendChild(headerContent);
1523 oHeader.innerHTML = headerContent;
1526 if (this._rendered) {
1527 this._renderHeader();
1530 this.changeHeaderEvent.fire(headerContent);
1531 this.changeContentEvent.fire();
1536 * Appends the passed element to the header. If no header is present,
1537 * one will be automatically created.
1538 * @method appendToHeader
1539 * @param {HTMLElement | DocumentFragment} element The element to
1540 * append to the header. In the case of a document fragment, the
1541 * children of the fragment will be appended to the header.
1543 appendToHeader: function (element) {
1544 var oHeader = this.header || (this.header = createHeader());
1546 oHeader.appendChild(element);
1548 this.changeHeaderEvent.fire(element);
1549 this.changeContentEvent.fire();
1554 * Sets the Module's body content to the HTML specified.
1556 * If no body is present, one will be automatically created.
1558 * An empty string can be passed to the method to clear the contents of the body.
1560 * @param {String} bodyContent The HTML used to set the body.
1561 * As a convenience, non HTMLElement objects can also be passed into
1562 * the method, and will be treated as strings, with the body innerHTML
1563 * set to their default toString implementations.
1565 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1566 * child of the body element.
1568 * @param {DocumentFragment} bodyContent The document fragment
1569 * containing elements which are to be added to the body
1571 setBody: function (bodyContent) {
1572 var oBody = this.body || (this.body = createBody());
1574 if (bodyContent.nodeName) {
1575 oBody.innerHTML = "";
1576 oBody.appendChild(bodyContent);
1578 oBody.innerHTML = bodyContent;
1581 if (this._rendered) {
1585 this.changeBodyEvent.fire(bodyContent);
1586 this.changeContentEvent.fire();
1590 * Appends the passed element to the body. If no body is present, one
1591 * will be automatically created.
1592 * @method appendToBody
1593 * @param {HTMLElement | DocumentFragment} element The element to
1594 * append to the body. In the case of a document fragment, the
1595 * children of the fragment will be appended to the body.
1598 appendToBody: function (element) {
1599 var oBody = this.body || (this.body = createBody());
1601 oBody.appendChild(element);
1603 this.changeBodyEvent.fire(element);
1604 this.changeContentEvent.fire();
1609 * Sets the Module's footer content to the HTML specified, or appends
1610 * the passed element to the footer. If no footer is present, one will
1611 * be automatically created. An empty string can be passed to the method
1612 * to clear the contents of the footer.
1614 * @param {String} footerContent The HTML used to set the footer
1615 * As a convenience, non HTMLElement objects can also be passed into
1616 * the method, and will be treated as strings, with the footer innerHTML
1617 * set to their default toString implementations.
1619 * @param {HTMLElement} footerContent The HTMLElement to append to
1622 * @param {DocumentFragment} footerContent The document fragment containing
1623 * elements which are to be added to the footer
1625 setFooter: function (footerContent) {
1627 var oFooter = this.footer || (this.footer = createFooter());
1629 if (footerContent.nodeName) {
1630 oFooter.innerHTML = "";
1631 oFooter.appendChild(footerContent);
1633 oFooter.innerHTML = footerContent;
1636 if (this._rendered) {
1637 this._renderFooter();
1640 this.changeFooterEvent.fire(footerContent);
1641 this.changeContentEvent.fire();
1645 * Appends the passed element to the footer. If no footer is present,
1646 * one will be automatically created.
1647 * @method appendToFooter
1648 * @param {HTMLElement | DocumentFragment} element The element to
1649 * append to the footer. In the case of a document fragment, the
1650 * children of the fragment will be appended to the footer
1652 appendToFooter: function (element) {
1654 var oFooter = this.footer || (this.footer = createFooter());
1656 oFooter.appendChild(element);
1658 this.changeFooterEvent.fire(element);
1659 this.changeContentEvent.fire();
1664 * Renders the Module by inserting the elements that are not already
1665 * in the main Module into their correct places. Optionally appends
1666 * the Module to the specified node prior to the render's execution.
1668 * For Modules without existing markup, the appendToNode argument
1669 * is REQUIRED. If this argument is ommitted and the current element is
1670 * not present in the document, the function will return false,
1671 * indicating that the render was a failure.
1674 * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1675 * then the module is rendered as the first child of the body element,
1676 * and not appended to it, to avoid Operation Aborted errors in IE when
1677 * rendering the module before window's load event is fired. You can
1678 * use the appendtodocumentbody configuration property to change this
1679 * to append to document.body if required.
1682 * @param {String} appendToNode The element id to which the Module
1683 * should be appended to prior to rendering <em>OR</em>
1684 * @param {HTMLElement} appendToNode The element to which the Module
1685 * should be appended to prior to rendering
1686 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1687 * represents the actual Standard Module container.
1688 * @return {Boolean} Success or failure of the render
1690 render: function (appendToNode, moduleElement) {
1694 function appendTo(parentNode) {
1695 if (typeof parentNode == "string") {
1696 parentNode = document.getElementById(parentNode);
1700 me._addToParent(parentNode, me.element);
1701 me.appendEvent.fire();
1705 this.beforeRenderEvent.fire();
1707 if (! moduleElement) {
1708 moduleElement = this.element;
1712 appendTo(appendToNode);
1714 // No node was passed in. If the element is not already in the Dom, this fails
1715 if (! Dom.inDocument(this.element)) {
1716 YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
1721 this._renderHeader(moduleElement);
1722 this._renderBody(moduleElement);
1723 this._renderFooter(moduleElement);
1725 this._rendered = true;
1727 this.renderEvent.fire();
1732 * Renders the currently set header into it's proper position under the
1733 * module element. If the module element is not provided, "this.element"
1736 * @method _renderHeader
1738 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1740 _renderHeader: function(moduleElement){
1741 moduleElement = moduleElement || this.element;
1743 // Need to get everything into the DOM if it isn't already
1744 if (this.header && !Dom.inDocument(this.header)) {
1745 // There is a header, but it's not in the DOM yet. Need to add it.
1746 var firstChild = moduleElement.firstChild;
1748 moduleElement.insertBefore(this.header, firstChild);
1750 moduleElement.appendChild(this.header);
1756 * Renders the currently set body into it's proper position under the
1757 * module element. If the module element is not provided, "this.element"
1760 * @method _renderBody
1762 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1764 _renderBody: function(moduleElement){
1765 moduleElement = moduleElement || this.element;
1767 if (this.body && !Dom.inDocument(this.body)) {
1768 // There is a body, but it's not in the DOM yet. Need to add it.
1769 if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1770 moduleElement.insertBefore(this.body, this.footer);
1772 moduleElement.appendChild(this.body);
1778 * Renders the currently set footer into it's proper position under the
1779 * module element. If the module element is not provided, "this.element"
1782 * @method _renderFooter
1784 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1786 _renderFooter: function(moduleElement){
1787 moduleElement = moduleElement || this.element;
1789 if (this.footer && !Dom.inDocument(this.footer)) {
1790 // There is a footer, but it's not in the DOM yet. Need to add it.
1791 moduleElement.appendChild(this.footer);
1796 * Removes the Module element from the DOM and sets all child elements
1800 destroy: function () {
1805 Event.purgeElement(this.element, true);
1806 parent = this.element.parentNode;
1810 parent.removeChild(this.element);
1813 this.element = null;
1818 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1823 this.destroyEvent.fire();
1827 * Shows the Module element by setting the visible configuration
1828 * property to true. Also fires two events: beforeShowEvent prior to
1829 * the visibility change, and showEvent after.
1833 this.cfg.setProperty("visible", true);
1837 * Hides the Module element by setting the visible configuration
1838 * property to false. Also fires two events: beforeHideEvent prior to
1839 * the visibility change, and hideEvent after.
1843 this.cfg.setProperty("visible", false);
1846 // BUILT-IN EVENT HANDLERS FOR MODULE //
1848 * Default event handler for changing the visibility property of a
1849 * Module. By default, this is achieved by switching the "display" style
1850 * between "block" and "none".
1851 * This method is responsible for firing showEvent and hideEvent.
1852 * @param {String} type The CustomEvent type (usually the property name)
1853 * @param {Object[]} args The CustomEvent arguments. For configuration
1854 * handlers, args[0] will equal the newly applied value for the property.
1855 * @param {Object} obj The scope object. For configuration handlers,
1856 * this will usually equal the owner.
1857 * @method configVisible
1859 configVisible: function (type, args, obj) {
1860 var visible = args[0];
1862 this.beforeShowEvent.fire();
1863 Dom.setStyle(this.element, "display", "block");
1864 this.showEvent.fire();
1866 this.beforeHideEvent.fire();
1867 Dom.setStyle(this.element, "display", "none");
1868 this.hideEvent.fire();
1873 * Default event handler for the "monitorresize" configuration property
1874 * @param {String} type The CustomEvent type (usually the property name)
1875 * @param {Object[]} args The CustomEvent arguments. For configuration
1876 * handlers, args[0] will equal the newly applied value for the property.
1877 * @param {Object} obj The scope object. For configuration handlers,
1878 * this will usually equal the owner.
1879 * @method configMonitorResize
1881 configMonitorResize: function (type, args, obj) {
1882 var monitor = args[0];
1884 this.initResizeMonitor();
1886 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1887 this.resizeMonitor = null;
1892 * This method is a protected helper, used when constructing the DOM structure for the module
1893 * to account for situations which may cause Operation Aborted errors in IE. It should not
1894 * be used for general DOM construction.
1896 * If the parentNode is not document.body, the element is appended as the last element.
1899 * If the parentNode is document.body the element is added as the first child to help
1900 * prevent Operation Aborted errors in IE.
1903 * @param {parentNode} The HTML element to which the element will be added
1904 * @param {element} The HTML element to be added to parentNode's children
1905 * @method _addToParent
1908 _addToParent: function(parentNode, element) {
1909 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1910 parentNode.insertBefore(element, parentNode.firstChild);
1912 parentNode.appendChild(element);
1917 * Returns a String representation of the Object.
1919 * @return {String} The string representation of the Module
1921 toString: function () {
1922 return "Module " + this.id;
1926 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1932 * Overlay is a Module that is absolutely positioned above the page flow. It
1933 * has convenience methods for positioning and sizing, as well as options for
1934 * controlling zIndex and constraining the Overlay's position to the current
1935 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1936 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1937 * properly rendered above SELECT elements.
1938 * @namespace YAHOO.widget
1940 * @extends YAHOO.widget.Module
1941 * @param {String} el The element ID representing the Overlay <em>OR</em>
1942 * @param {HTMLElement} el The element representing the Overlay
1943 * @param {Object} userConfig The configuration object literal containing
1944 * the configuration that should be set for this Overlay. See configuration
1945 * documentation for more details.
1948 YAHOO.widget.Overlay = function (el, userConfig) {
1949 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1952 var Lang = YAHOO.lang,
1953 CustomEvent = YAHOO.util.CustomEvent,
1954 Module = YAHOO.widget.Module,
1955 Event = YAHOO.util.Event,
1956 Dom = YAHOO.util.Dom,
1957 Config = YAHOO.util.Config,
1959 Overlay = YAHOO.widget.Overlay,
1961 _SUBSCRIBE = "subscribe",
1962 _UNSUBSCRIBE = "unsubscribe",
1963 _CONTAINED = "contained",
1968 * Constant representing the name of the Overlay's events
1969 * @property EVENT_TYPES
1975 "BEFORE_MOVE": "beforeMove",
1980 * Constant representing the Overlay's configuration properties
1981 * @property DEFAULT_CONFIG
1990 validator: Lang.isNumber,
1991 suppressEvent: true,
1992 supercedes: ["iframe"]
1997 validator: Lang.isNumber,
1998 suppressEvent: true,
1999 supercedes: ["iframe"]
2004 suppressEvent: true,
2005 supercedes: ["iframe"]
2010 suppressEvent: true,
2011 supercedes: ["iframe"]
2017 supercedes: ["iframe", "visible"]
2022 suppressEvent: true,
2023 supercedes: ["context", "fixedcenter", "iframe"]
2028 suppressEvent: true,
2029 supercedes: ["context", "fixedcenter", "iframe"]
2032 "AUTO_FILL_HEIGHT" : {
2033 key: "autofillheight",
2034 supercedes: ["height"],
2043 "CONSTRAIN_TO_VIEWPORT": {
2044 key: "constraintoviewport",
2046 validator: Lang.isBoolean,
2047 supercedes: ["iframe", "x", "y", "xy"]
2052 value: (UA.ie == 6 ? true : false),
2053 validator: Lang.isBoolean,
2054 supercedes: ["zindex"]
2057 "PREVENT_CONTEXT_OVERLAP": {
2058 key: "preventcontextoverlap",
2060 validator: Lang.isBoolean,
2061 supercedes: ["constraintoviewport"]
2067 * The URL that will be placed in the iframe
2068 * @property YAHOO.widget.Overlay.IFRAME_SRC
2073 Overlay.IFRAME_SRC = "javascript:false;";
2076 * Number representing how much the iframe shim should be offset from each
2077 * side of an Overlay instance, in pixels.
2078 * @property YAHOO.widget.Overlay.IFRAME_SRC
2084 Overlay.IFRAME_OFFSET = 3;
2087 * Number representing the minimum distance an Overlay instance should be
2088 * positioned relative to the boundaries of the browser's viewport, in pixels.
2089 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2095 Overlay.VIEWPORT_OFFSET = 10;
2098 * Constant representing the top left corner of an element, used for
2099 * configuring the context element alignment
2100 * @property YAHOO.widget.Overlay.TOP_LEFT
2105 Overlay.TOP_LEFT = "tl";
2108 * Constant representing the top right corner of an element, used for
2109 * configuring the context element alignment
2110 * @property YAHOO.widget.Overlay.TOP_RIGHT
2115 Overlay.TOP_RIGHT = "tr";
2118 * Constant representing the top bottom left corner of an element, used for
2119 * configuring the context element alignment
2120 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2125 Overlay.BOTTOM_LEFT = "bl";
2128 * Constant representing the bottom right corner of an element, used for
2129 * configuring the context element alignment
2130 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2135 Overlay.BOTTOM_RIGHT = "br";
2137 Overlay.PREVENT_OVERLAP_X = {
2144 Overlay.PREVENT_OVERLAP_Y = {
2152 * Constant representing the default CSS class used for an Overlay
2153 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2158 Overlay.CSS_OVERLAY = "yui-overlay";
2161 * Constant representing the default hidden CSS class used for an Overlay. This class is
2162 * applied to the overlay's outer DIV whenever it's hidden.
2164 * @property YAHOO.widget.Overlay.CSS_HIDDEN
2169 Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2172 * Constant representing the default CSS class used for an Overlay iframe shim.
2174 * @property YAHOO.widget.Overlay.CSS_IFRAME
2179 Overlay.CSS_IFRAME = "yui-overlay-iframe";
2182 * Constant representing the names of the standard module elements
2183 * used in the overlay.
2184 * @property YAHOO.widget.Overlay.STD_MOD_RE
2189 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2192 * A singleton CustomEvent used for reacting to the DOM event for
2194 * @event YAHOO.widget.Overlay.windowScrollEvent
2196 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2199 * A singleton CustomEvent used for reacting to the DOM event for
2201 * @event YAHOO.widget.Overlay.windowResizeEvent
2203 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2206 * The DOM event handler used to fire the CustomEvent for window scroll
2207 * @method YAHOO.widget.Overlay.windowScrollHandler
2209 * @param {DOMEvent} e The DOM scroll event
2211 Overlay.windowScrollHandler = function (e) {
2212 var t = Event.getTarget(e);
2214 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2215 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2216 // - IE doesn't recognize scroll registered on the document.
2218 // Also, when document view is scrolled, IE doesn't provide a target,
2219 // rest of the browsers set target to window.document, apart from opera
2220 // which sets target to window.
2221 if (!t || t === window || t === window.document) {
2224 if (! window.scrollEnd) {
2225 window.scrollEnd = -1;
2228 clearTimeout(window.scrollEnd);
2230 window.scrollEnd = setTimeout(function () {
2231 Overlay.windowScrollEvent.fire();
2235 Overlay.windowScrollEvent.fire();
2241 * The DOM event handler used to fire the CustomEvent for window resize
2242 * @method YAHOO.widget.Overlay.windowResizeHandler
2244 * @param {DOMEvent} e The DOM resize event
2246 Overlay.windowResizeHandler = function (e) {
2249 if (! window.resizeEnd) {
2250 window.resizeEnd = -1;
2253 clearTimeout(window.resizeEnd);
2255 window.resizeEnd = setTimeout(function () {
2256 Overlay.windowResizeEvent.fire();
2259 Overlay.windowResizeEvent.fire();
2264 * A boolean that indicated whether the window resize and scroll events have
2265 * already been subscribed to.
2266 * @property YAHOO.widget.Overlay._initialized
2270 Overlay._initialized = null;
2272 if (Overlay._initialized === null) {
2273 Event.on(window, "scroll", Overlay.windowScrollHandler);
2274 Event.on(window, "resize", Overlay.windowResizeHandler);
2275 Overlay._initialized = true;
2279 * Internal map of special event types, which are provided
2280 * by the instance. It maps the event type to the custom event
2281 * instance. Contains entries for the "windowScroll", "windowResize" and
2282 * "textResize" static container events.
2284 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2289 Overlay._TRIGGER_MAP = {
2290 "windowScroll" : Overlay.windowScrollEvent,
2291 "windowResize" : Overlay.windowResizeEvent,
2292 "textResize" : Module.textResizeEvent
2295 YAHOO.extend(Overlay, Module, {
2299 * Array of default event types which will trigger
2300 * context alignment for the Overlay class.
2302 * <p>The array is empty by default for Overlay,
2303 * but maybe populated in future releases, so classes extending
2304 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2305 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2306 * value with their own array of values.
2310 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2313 * @property CONTEXT_TRIGGERS
2317 CONTEXT_TRIGGERS : [],
2320 * The Overlay initialization method, which is executed for Overlay and
2321 * all of its subclasses. This method is automatically called by the
2322 * constructor, and sets up all DOM references for pre-existing markup,
2323 * and creates required markup if it is not already present.
2325 * @param {String} el The element ID representing the Overlay <em>OR</em>
2326 * @param {HTMLElement} el The element representing the Overlay
2327 * @param {Object} userConfig The configuration object literal
2328 * containing the configuration that should be set for this Overlay.
2329 * See configuration documentation for more details.
2331 init: function (el, userConfig) {
2334 Note that we don't pass the user config in here yet because we
2335 only want it executed once, at the lowest subclass level
2338 Overlay.superclass.init.call(this, el/*, userConfig*/);
2340 this.beforeInitEvent.fire(Overlay);
2342 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2345 this.cfg.applyConfig(userConfig, true);
2348 if (this.platform == "mac" && UA.gecko) {
2350 if (! Config.alreadySubscribed(this.showEvent,
2351 this.showMacGeckoScrollbars, this)) {
2353 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2358 if (! Config.alreadySubscribed(this.hideEvent,
2359 this.hideMacGeckoScrollbars, this)) {
2361 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2367 this.initEvent.fire(Overlay);
2371 * Initializes the custom events for Overlay which are fired
2372 * automatically at appropriate times by the Overlay class.
2373 * @method initEvents
2375 initEvents: function () {
2377 Overlay.superclass.initEvents.call(this);
2379 var SIGNATURE = CustomEvent.LIST;
2382 * CustomEvent fired before the Overlay is moved.
2383 * @event beforeMoveEvent
2384 * @param {Number} x x coordinate
2385 * @param {Number} y y coordinate
2387 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2388 this.beforeMoveEvent.signature = SIGNATURE;
2391 * CustomEvent fired after the Overlay is moved.
2393 * @param {Number} x x coordinate
2394 * @param {Number} y y coordinate
2396 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2397 this.moveEvent.signature = SIGNATURE;
2402 * Initializes the class's configurable properties which can be changed
2403 * using the Overlay's Config object (cfg).
2404 * @method initDefaultConfig
2406 initDefaultConfig: function () {
2408 Overlay.superclass.initDefaultConfig.call(this);
2412 // Add overlay config properties //
2415 * The absolute x-coordinate position of the Overlay
2420 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2422 handler: this.configX,
2423 validator: DEFAULT_CONFIG.X.validator,
2424 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2425 supercedes: DEFAULT_CONFIG.X.supercedes
2430 * The absolute y-coordinate position of the Overlay
2435 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2437 handler: this.configY,
2438 validator: DEFAULT_CONFIG.Y.validator,
2439 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2440 supercedes: DEFAULT_CONFIG.Y.supercedes
2445 * An array with the absolute x and y positions of the Overlay
2450 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2451 handler: this.configXY,
2452 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2453 supercedes: DEFAULT_CONFIG.XY.supercedes
2458 * The array of context arguments for context-sensitive positioning.
2462 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2463 * the 5 array elements described in detail below:
2467 * <dt>contextElementOrId <String|HTMLElement></dt>
2468 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2469 * <dt>overlayCorner <String></dt>
2470 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2471 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2472 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2473 * <dt>contextCorner <String></dt>
2474 * <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>
2475 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2478 * 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>
2479 * 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.
2480 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2483 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2484 * 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).
2487 * <dt>xyOffset <Number[]></dt>
2489 * A 2 element Array specifying the X and Y pixel amounts by which the Overlay should be offset from the aligned corner. e.g. [5,0] offsets the Overlay 5 pixels to the left, <em>after</em> aligning the given context corners.
2490 * NOTE: If using this property and no triggers need to be defined, the arrayOfTriggerEvents property should be set to null to maintain correct array positions for the arguments.
2495 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2496 * align the Overlay's top left corner to the bottom left corner of the
2497 * context element with id "img1".
2500 * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
2501 * align the Overlay's top left corner to the bottom left corner of the
2502 * context element with id "img1", and then offset it by 5 pixels on the Y axis (providing a 5 pixel gap between the bottom of the context element and top of the overlay).
2505 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2506 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2513 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2514 handler: this.configContext,
2515 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2516 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2520 * Determines whether or not the Overlay should be anchored
2521 * to the center of the viewport.
2523 * <p>This property can be set to:</p>
2528 * To enable fixed center positioning
2530 * When enabled, the overlay will
2531 * be positioned in the center of viewport when initially displayed, and
2532 * will remain in the center of the viewport whenever the window is
2533 * scrolled or resized.
2536 * If the overlay is too big for the viewport,
2537 * it's top left corner will be aligned with the top left corner of the viewport.
2542 * To disable fixed center positioning.
2543 * <p>In this case the overlay can still be
2544 * centered as a one-off operation, by invoking the <code>center()</code> method,
2545 * however it will not remain centered when the window is scrolled/resized.
2547 * <dt>"contained"<dt>
2548 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2549 * <p>However, unlike setting the property to <code>true</code>,
2550 * when the property is set to <code>"contained"</code>, if the overlay is
2551 * too big for the viewport, it will not get automatically centered when the
2552 * user scrolls or resizes the window (until the window is large enough to contain the
2553 * overlay). This is useful in cases where the Overlay has both header and footer
2554 * UI controls which the user may need to access.
2559 * @config fixedcenter
2560 * @type Boolean | String
2563 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2564 handler: this.configFixedCenter,
2565 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2566 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2567 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2571 * CSS width of the Overlay.
2576 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2577 handler: this.configWidth,
2578 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2579 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2583 * CSS height of the Overlay.
2588 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2589 handler: this.configHeight,
2590 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2591 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2595 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2596 * Supported values are "header", "body", "footer".
2598 * @config autofillheight
2602 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2603 handler: this.configAutoFillHeight,
2604 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2605 validator : this._validateAutoFill,
2606 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2610 * CSS z-index of the Overlay.
2615 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2616 handler: this.configzIndex,
2617 value: DEFAULT_CONFIG.ZINDEX.value
2621 * True if the Overlay should be prevented from being positioned
2622 * out of the viewport.
2623 * @config constraintoviewport
2627 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2629 handler: this.configConstrainToViewport,
2630 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2631 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2632 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2638 * @description Boolean indicating whether or not the Overlay should
2639 * have an IFRAME shim; used to prevent SELECT elements from
2640 * poking through an Overlay instance in IE6. When set to "true",
2641 * the iframe shim is created when the Overlay instance is intially
2644 * @default true for IE6 and below, false for all other browsers.
2646 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2648 handler: this.configIframe,
2649 value: DEFAULT_CONFIG.IFRAME.value,
2650 validator: DEFAULT_CONFIG.IFRAME.validator,
2651 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2656 * @config preventcontextoverlap
2657 * @description Boolean indicating whether or not the Overlay should overlap its
2658 * context element (defined using the "context" configuration property) when the
2659 * "constraintoviewport" configuration property is set to "true".
2663 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2664 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2665 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2666 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2671 * Moves the Overlay to the specified position. This function is
2672 * identical to calling this.cfg.setProperty("xy", [x,y]);
2674 * @param {Number} x The Overlay's new x position
2675 * @param {Number} y The Overlay's new y position
2677 moveTo: function (x, y) {
2678 this.cfg.setProperty("xy", [x, y]);
2682 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2683 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2684 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2685 * @method hideMacGeckoScrollbars
2687 hideMacGeckoScrollbars: function () {
2688 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2692 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2693 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2694 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2695 * @method showMacGeckoScrollbars
2697 showMacGeckoScrollbars: function () {
2698 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2702 * Internal implementation to set the visibility of the overlay in the DOM.
2704 * @method _setDomVisibility
2705 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2708 _setDomVisibility : function(show) {
2709 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2710 var hiddenClass = Overlay.CSS_HIDDEN;
2713 Dom.removeClass(this.element, hiddenClass);
2715 Dom.addClass(this.element, hiddenClass);
2719 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2721 * The default event handler fired when the "visible" property is
2722 * changed. This method is responsible for firing showEvent
2724 * @method configVisible
2725 * @param {String} type The CustomEvent type (usually the property name)
2726 * @param {Object[]} args The CustomEvent arguments. For configuration
2727 * handlers, args[0] will equal the newly applied value for the property.
2728 * @param {Object} obj The scope object. For configuration handlers,
2729 * this will usually equal the owner.
2731 configVisible: function (type, args, obj) {
2733 var visible = args[0],
2734 currentVis = Dom.getStyle(this.element, "visibility"),
2735 effect = this.cfg.getProperty("effect"),
2736 effectInstances = [],
2737 isMacGecko = (this.platform == "mac" && UA.gecko),
2738 alreadySubscribed = Config.alreadySubscribed,
2739 eff, ei, e, i, j, k, h,
2743 if (currentVis == "inherit") {
2744 e = this.element.parentNode;
2746 while (e.nodeType != 9 && e.nodeType != 11) {
2747 currentVis = Dom.getStyle(e, "visibility");
2749 if (currentVis != "inherit") {
2756 if (currentVis == "inherit") {
2757 currentVis = "visible";
2762 if (effect instanceof Array) {
2763 nEffects = effect.length;
2765 for (i = 0; i < nEffects; i++) {
2767 effectInstances[effectInstances.length] =
2768 eff.effect(this, eff.duration);
2772 effectInstances[effectInstances.length] =
2773 effect.effect(this, effect.duration);
2777 if (visible) { // Show
2779 this.showMacGeckoScrollbars();
2782 if (effect) { // Animate in
2783 if (visible) { // Animate in if not showing
2784 if (currentVis != "visible" || currentVis === "") {
2785 this.beforeShowEvent.fire();
2786 nEffectInstances = effectInstances.length;
2788 for (j = 0; j < nEffectInstances; j++) {
2789 ei = effectInstances[j];
2790 if (j === 0 && !alreadySubscribed(
2791 ei.animateInCompleteEvent,
2792 this.showEvent.fire, this.showEvent)) {
2795 Delegate showEvent until end
2796 of animateInComplete
2799 ei.animateInCompleteEvent.subscribe(
2800 this.showEvent.fire, this.showEvent, true);
2807 if (currentVis != "visible" || currentVis === "") {
2808 this.beforeShowEvent.fire();
2810 this._setDomVisibility(true);
2812 this.cfg.refireEvent("iframe");
2813 this.showEvent.fire();
2815 this._setDomVisibility(true);
2821 this.hideMacGeckoScrollbars();
2824 if (effect) { // Animate out if showing
2825 if (currentVis == "visible") {
2826 this.beforeHideEvent.fire();
2828 nEffectInstances = effectInstances.length;
2829 for (k = 0; k < nEffectInstances; k++) {
2830 h = effectInstances[k];
2832 if (k === 0 && !alreadySubscribed(
2833 h.animateOutCompleteEvent, this.hideEvent.fire,
2837 Delegate hideEvent until end
2838 of animateOutComplete
2841 h.animateOutCompleteEvent.subscribe(
2842 this.hideEvent.fire, this.hideEvent, true);
2848 } else if (currentVis === "") {
2849 this._setDomVisibility(false);
2852 } else { // Simple hide
2854 if (currentVis == "visible" || currentVis === "") {
2855 this.beforeHideEvent.fire();
2856 this._setDomVisibility(false);
2857 this.hideEvent.fire();
2859 this._setDomVisibility(false);
2866 * Fixed center event handler used for centering on scroll/resize, but only if
2867 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2868 * the overlay fits within the viewport.
2870 * @method doCenterOnDOMEvent
2872 doCenterOnDOMEvent: function () {
2874 fc = cfg.getProperty("fixedcenter");
2876 if (cfg.getProperty("visible")) {
2877 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2884 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2885 * will fit entirely inside the viewport, in both dimensions - width and height.
2887 * @method fitsInViewport
2888 * @return boolean true if the Overlay will fit, false if not
2890 fitsInViewport : function() {
2891 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2892 element = this.element,
2893 elementWidth = element.offsetWidth,
2894 elementHeight = element.offsetHeight,
2895 viewportWidth = Dom.getViewportWidth(),
2896 viewportHeight = Dom.getViewportHeight();
2898 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2902 * The default event handler fired when the "fixedcenter" property
2904 * @method configFixedCenter
2905 * @param {String} type The CustomEvent type (usually the property name)
2906 * @param {Object[]} args The CustomEvent arguments. For configuration
2907 * handlers, args[0] will equal the newly applied value for the property.
2908 * @param {Object} obj The scope object. For configuration handlers,
2909 * this will usually equal the owner.
2911 configFixedCenter: function (type, args, obj) {
2914 alreadySubscribed = Config.alreadySubscribed,
2915 windowResizeEvent = Overlay.windowResizeEvent,
2916 windowScrollEvent = Overlay.windowScrollEvent;
2921 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2922 this.beforeShowEvent.subscribe(this.center);
2925 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2926 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2929 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2930 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2934 this.beforeShowEvent.unsubscribe(this.center);
2936 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2937 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2942 * The default event handler fired when the "height" property is changed.
2943 * @method configHeight
2944 * @param {String} type The CustomEvent type (usually the property name)
2945 * @param {Object[]} args The CustomEvent arguments. For configuration
2946 * handlers, args[0] will equal the newly applied value for the property.
2947 * @param {Object} obj The scope object. For configuration handlers,
2948 * this will usually equal the owner.
2950 configHeight: function (type, args, obj) {
2952 var height = args[0],
2955 Dom.setStyle(el, "height", height);
2956 this.cfg.refireEvent("iframe");
2960 * The default event handler fired when the "autofillheight" property is changed.
2961 * @method configAutoFillHeight
2963 * @param {String} type The CustomEvent type (usually the property name)
2964 * @param {Object[]} args The CustomEvent arguments. For configuration
2965 * handlers, args[0] will equal the newly applied value for the property.
2966 * @param {Object} obj The scope object. For configuration handlers,
2967 * this will usually equal the owner.
2969 configAutoFillHeight: function (type, args, obj) {
2970 var fillEl = args[0],
2972 autoFillHeight = "autofillheight",
2974 currEl = cfg.getProperty(autoFillHeight),
2975 autoFill = this._autoFillOnHeightChange;
2977 cfg.unsubscribeFromConfigEvent(height, autoFill);
2978 Module.textResizeEvent.unsubscribe(autoFill);
2979 this.changeContentEvent.unsubscribe(autoFill);
2981 if (currEl && fillEl !== currEl && this[currEl]) {
2982 Dom.setStyle(this[currEl], height, "");
2986 fillEl = Lang.trim(fillEl.toLowerCase());
2988 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
2989 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
2990 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
2992 cfg.setProperty(autoFillHeight, fillEl, true);
2997 * The default event handler fired when the "width" property is changed.
2998 * @method configWidth
2999 * @param {String} type The CustomEvent type (usually the property name)
3000 * @param {Object[]} args The CustomEvent arguments. For configuration
3001 * handlers, args[0] will equal the newly applied value for the property.
3002 * @param {Object} obj The scope object. For configuration handlers,
3003 * this will usually equal the owner.
3005 configWidth: function (type, args, obj) {
3007 var width = args[0],
3010 Dom.setStyle(el, "width", width);
3011 this.cfg.refireEvent("iframe");
3015 * The default event handler fired when the "zIndex" property is changed.
3016 * @method configzIndex
3017 * @param {String} type The CustomEvent type (usually the property name)
3018 * @param {Object[]} args The CustomEvent arguments. For configuration
3019 * handlers, args[0] will equal the newly applied value for the property.
3020 * @param {Object} obj The scope object. For configuration handlers,
3021 * this will usually equal the owner.
3023 configzIndex: function (type, args, obj) {
3025 var zIndex = args[0],
3029 zIndex = Dom.getStyle(el, "zIndex");
3030 if (! zIndex || isNaN(zIndex)) {
3035 if (this.iframe || this.cfg.getProperty("iframe") === true) {
3041 Dom.setStyle(el, "zIndex", zIndex);
3042 this.cfg.setProperty("zIndex", zIndex, true);
3050 * The default event handler fired when the "xy" property is changed.
3052 * @param {String} type The CustomEvent type (usually the property name)
3053 * @param {Object[]} args The CustomEvent arguments. For configuration
3054 * handlers, args[0] will equal the newly applied value for the property.
3055 * @param {Object} obj The scope object. For configuration handlers,
3056 * this will usually equal the owner.
3058 configXY: function (type, args, obj) {
3064 this.cfg.setProperty("x", x);
3065 this.cfg.setProperty("y", y);
3067 this.beforeMoveEvent.fire([x, y]);
3069 x = this.cfg.getProperty("x");
3070 y = this.cfg.getProperty("y");
3072 YAHOO.log(("xy: " + [x, y]), "iframe");
3074 this.cfg.refireEvent("iframe");
3075 this.moveEvent.fire([x, y]);
3079 * The default event handler fired when the "x" property is changed.
3081 * @param {String} type The CustomEvent type (usually the property name)
3082 * @param {Object[]} args The CustomEvent arguments. For configuration
3083 * handlers, args[0] will equal the newly applied value for the property.
3084 * @param {Object} obj The scope object. For configuration handlers,
3085 * this will usually equal the owner.
3087 configX: function (type, args, obj) {
3090 y = this.cfg.getProperty("y");
3092 this.cfg.setProperty("x", x, true);
3093 this.cfg.setProperty("y", y, true);
3095 this.beforeMoveEvent.fire([x, y]);
3097 x = this.cfg.getProperty("x");
3098 y = this.cfg.getProperty("y");
3100 Dom.setX(this.element, x, true);
3102 this.cfg.setProperty("xy", [x, y], true);
3104 this.cfg.refireEvent("iframe");
3105 this.moveEvent.fire([x, y]);
3109 * The default event handler fired when the "y" property is changed.
3111 * @param {String} type The CustomEvent type (usually the property name)
3112 * @param {Object[]} args The CustomEvent arguments. For configuration
3113 * handlers, args[0] will equal the newly applied value for the property.
3114 * @param {Object} obj The scope object. For configuration handlers,
3115 * this will usually equal the owner.
3117 configY: function (type, args, obj) {
3119 var x = this.cfg.getProperty("x"),
3122 this.cfg.setProperty("x", x, true);
3123 this.cfg.setProperty("y", y, true);
3125 this.beforeMoveEvent.fire([x, y]);
3127 x = this.cfg.getProperty("x");
3128 y = this.cfg.getProperty("y");
3130 Dom.setY(this.element, y, true);
3132 this.cfg.setProperty("xy", [x, y], true);
3134 this.cfg.refireEvent("iframe");
3135 this.moveEvent.fire([x, y]);
3139 * Shows the iframe shim, if it has been enabled.
3140 * @method showIframe
3142 showIframe: function () {
3144 var oIFrame = this.iframe,
3148 oParentNode = this.element.parentNode;
3150 if (oParentNode != oIFrame.parentNode) {
3151 this._addToParent(oParentNode, oIFrame);
3153 oIFrame.style.display = "block";
3158 * Hides the iframe shim, if it has been enabled.
3159 * @method hideIframe
3161 hideIframe: function () {
3163 this.iframe.style.display = "none";
3168 * Syncronizes the size and position of iframe shim to that of its
3169 * corresponding Overlay instance.
3170 * @method syncIframe
3172 syncIframe: function () {
3174 var oIFrame = this.iframe,
3175 oElement = this.element,
3176 nOffset = Overlay.IFRAME_OFFSET,
3177 nDimensionOffset = (nOffset * 2),
3182 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3183 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3185 // Position <iframe>
3186 aXY = this.cfg.getProperty("xy");
3188 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3189 this.syncPosition();
3190 aXY = this.cfg.getProperty("xy");
3192 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3197 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3198 * the Overlay element. The zindex of the iframe is set to be one less
3199 * than the Overlay element's zindex.
3201 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3202 * to ensure that the iframe shim has a non-negative zindex.
3203 * If you require the iframe zindex to be 0 or higher, the zindex of
3204 * the Overlay element should be set to a value greater than 0, before
3205 * this method is called.
3207 * @method stackIframe
3209 stackIframe: function () {
3211 var overlayZ = Dom.getStyle(this.element, "zIndex");
3212 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3213 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3219 * The default event handler fired when the "iframe" property is changed.
3220 * @method configIframe
3221 * @param {String} type The CustomEvent type (usually the property name)
3222 * @param {Object[]} args The CustomEvent arguments. For configuration
3223 * handlers, args[0] will equal the newly applied value for the property.
3224 * @param {Object} obj The scope object. For configuration handlers,
3225 * this will usually equal the owner.
3227 configIframe: function (type, args, obj) {
3229 var bIFrame = args[0];
3231 function createIFrame() {
3233 var oIFrame = this.iframe,
3234 oElement = this.element,
3238 if (!m_oIFrameTemplate) {
3239 m_oIFrameTemplate = document.createElement("iframe");
3241 if (this.isSecure) {
3242 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3246 Set the opacity of the <iframe> to 0 so that it
3247 doesn't modify the opacity of any transparent
3248 elements that may be on top of it (like a shadow).
3251 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3253 Need to set the "frameBorder" property to 0
3254 supress the default <iframe> border in IE.
3255 Setting the CSS "border" property alone
3258 m_oIFrameTemplate.frameBorder = 0;
3261 m_oIFrameTemplate.style.opacity = "0";
3264 m_oIFrameTemplate.style.position = "absolute";
3265 m_oIFrameTemplate.style.border = "none";
3266 m_oIFrameTemplate.style.margin = "0";
3267 m_oIFrameTemplate.style.padding = "0";
3268 m_oIFrameTemplate.style.display = "none";
3269 m_oIFrameTemplate.tabIndex = -1;
3270 m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3273 oIFrame = m_oIFrameTemplate.cloneNode(false);
3274 oIFrame.id = this.id + "_f";
3275 oParent = oElement.parentNode;
3277 var parentNode = oParent || document.body;
3279 this._addToParent(parentNode, oIFrame);
3280 this.iframe = oIFrame;
3284 Show the <iframe> before positioning it since the "setXY"
3285 method of DOM requires the element be in the document
3291 Syncronize the size and position of the <iframe> to that
3297 // Add event listeners to update the <iframe> when necessary
3298 if (!this._hasIframeEventListeners) {
3299 this.showEvent.subscribe(this.showIframe);
3300 this.hideEvent.subscribe(this.hideIframe);
3301 this.changeContentEvent.subscribe(this.syncIframe);
3303 this._hasIframeEventListeners = true;
3307 function onBeforeShow() {
3308 createIFrame.call(this);
3309 this.beforeShowEvent.unsubscribe(onBeforeShow);
3310 this._iframeDeferred = false;
3313 if (bIFrame) { // <iframe> shim is enabled
3315 if (this.cfg.getProperty("visible")) {
3316 createIFrame.call(this);
3318 if (!this._iframeDeferred) {
3319 this.beforeShowEvent.subscribe(onBeforeShow);
3320 this._iframeDeferred = true;
3324 } else { // <iframe> shim is disabled
3327 if (this._hasIframeEventListeners) {
3328 this.showEvent.unsubscribe(this.showIframe);
3329 this.hideEvent.unsubscribe(this.hideIframe);
3330 this.changeContentEvent.unsubscribe(this.syncIframe);
3332 this._hasIframeEventListeners = false;
3338 * Set's the container's XY value from DOM if not already set.
3340 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3341 * not already set. The method also refire's the XY config property event, so any
3342 * beforeMove, Move event listeners are invoked.
3344 * @method _primeXYFromDOM
3347 _primeXYFromDOM : function() {
3348 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3349 // Set CFG XY based on DOM XY
3350 this.syncPosition();
3351 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3352 this.cfg.refireEvent("xy");
3353 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3358 * The default event handler fired when the "constraintoviewport"
3359 * property is changed.
3360 * @method configConstrainToViewport
3361 * @param {String} type The CustomEvent type (usually the property name)
3362 * @param {Object[]} args The CustomEvent arguments. For configuration
3363 * handlers, args[0] will equal the newly applied value for
3365 * @param {Object} obj The scope object. For configuration handlers,
3366 * this will usually equal the owner.
3368 configConstrainToViewport: function (type, args, obj) {
3372 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3373 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3375 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3376 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3379 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3380 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3385 * The default event handler fired when the "context" property
3388 * @method configContext
3389 * @param {String} type The CustomEvent type (usually the property name)
3390 * @param {Object[]} args The CustomEvent arguments. For configuration
3391 * handlers, args[0] will equal the newly applied value for the property.
3392 * @param {Object} obj The scope object. For configuration handlers,
3393 * this will usually equal the owner.
3395 configContext: function (type, args, obj) {
3397 var contextArgs = args[0],
3399 elementMagnetCorner,
3400 contextMagnetCorner,
3403 defTriggers = this.CONTEXT_TRIGGERS;
3407 contextEl = contextArgs[0];
3408 elementMagnetCorner = contextArgs[1];
3409 contextMagnetCorner = contextArgs[2];
3410 triggers = contextArgs[3];
3411 offset = contextArgs[4];
3413 if (defTriggers && defTriggers.length > 0) {
3414 triggers = (triggers || []).concat(defTriggers);
3418 if (typeof contextEl == "string") {
3419 this.cfg.setProperty("context", [
3420 document.getElementById(contextEl),
3421 elementMagnetCorner,
3422 contextMagnetCorner,
3428 if (elementMagnetCorner && contextMagnetCorner) {
3429 this.align(elementMagnetCorner, contextMagnetCorner, offset);
3432 if (this._contextTriggers) {
3433 // Unsubscribe Old Set
3434 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3438 // Subscribe New Set
3439 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3440 this._contextTriggers = triggers;
3447 * Custom Event handler for context alignment triggers. Invokes the align method
3449 * @method _alignOnTrigger
3452 * @param {String} type The event type (not used by the default implementation)
3453 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3455 _alignOnTrigger: function(type, args) {
3460 * Helper method to locate the custom event instance for the event name string
3461 * passed in. As a convenience measure, any custom events passed in are returned.
3463 * @method _findTriggerCE
3466 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3467 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3469 _findTriggerCE : function(t) {
3471 if (t instanceof CustomEvent) {
3473 } else if (Overlay._TRIGGER_MAP[t]) {
3474 tce = Overlay._TRIGGER_MAP[t];
3480 * Utility method that subscribes or unsubscribes the given
3481 * function from the list of trigger events provided.
3483 * @method _processTriggers
3486 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3487 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3488 * subscribed/unsubscribed respectively.
3490 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3491 * we are subscribing or unsubscribing trigger listeners
3493 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3494 * Context is always set to the overlay instance, and no additional object argument
3495 * get passed to the subscribed function.
3497 _processTriggers : function(triggers, mode, fn) {
3500 for (var i = 0, l = triggers.length; i < l; ++i) {
3502 tce = this._findTriggerCE(t);
3504 tce[mode](fn, this, true);
3511 // END BUILT-IN PROPERTY EVENT HANDLERS //
3513 * Aligns the Overlay to its context element using the specified corner
3514 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3517 * @param {String} elementAlign The String representing the corner of
3518 * the Overlay that should be aligned to the context element
3519 * @param {String} contextAlign The corner of the context element
3520 * that the elementAlign corner should stick to.
3521 * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3522 * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
3523 * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3525 align: function (elementAlign, contextAlign, xyOffset) {
3527 var contextArgs = this.cfg.getProperty("context"),
3533 function doAlign(v, h) {
3535 var alignX = null, alignY = null;
3537 switch (elementAlign) {
3539 case Overlay.TOP_LEFT:
3544 case Overlay.TOP_RIGHT:
3545 alignX = h - element.offsetWidth;
3549 case Overlay.BOTTOM_LEFT:
3551 alignY = v - element.offsetHeight;
3554 case Overlay.BOTTOM_RIGHT:
3555 alignX = h - element.offsetWidth;
3556 alignY = v - element.offsetHeight;
3560 if (alignX !== null && alignY !== null) {
3562 alignX += xyOffset[0];
3563 alignY += xyOffset[1];
3565 me.moveTo(alignX, alignY);
3570 context = contextArgs[0];
3571 element = this.element;
3574 if (! elementAlign) {
3575 elementAlign = contextArgs[1];
3578 if (! contextAlign) {
3579 contextAlign = contextArgs[2];
3582 if (!xyOffset && contextArgs[4]) {
3583 xyOffset = contextArgs[4];
3586 if (element && context) {
3587 contextRegion = Dom.getRegion(context);
3589 switch (contextAlign) {
3591 case Overlay.TOP_LEFT:
3592 doAlign(contextRegion.top, contextRegion.left);
3595 case Overlay.TOP_RIGHT:
3596 doAlign(contextRegion.top, contextRegion.right);
3599 case Overlay.BOTTOM_LEFT:
3600 doAlign(contextRegion.bottom, contextRegion.left);
3603 case Overlay.BOTTOM_RIGHT:
3604 doAlign(contextRegion.bottom, contextRegion.right);
3612 * The default event handler executed when the moveEvent is fired, if the
3613 * "constraintoviewport" is set to true.
3614 * @method enforceConstraints
3615 * @param {String} type The CustomEvent type (usually the property name)
3616 * @param {Object[]} args The CustomEvent arguments. For configuration
3617 * handlers, args[0] will equal the newly applied value for the property.
3618 * @param {Object} obj The scope object. For configuration handlers,
3619 * this will usually equal the owner.
3621 enforceConstraints: function (type, args, obj) {
3624 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3625 this.cfg.setProperty("x", cXY[0], true);
3626 this.cfg.setProperty("y", cXY[1], true);
3627 this.cfg.setProperty("xy", cXY, true);
3631 * Shared implementation method for getConstrainedX and getConstrainedY.
3634 * Given a coordinate value, returns the calculated coordinate required to
3635 * position the Overlay if it is to be constrained to the viewport, based on the
3636 * current element size, viewport dimensions, scroll values and preventoverlap
3640 * @method _getConstrainedPos
3642 * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3643 * @param {Number} The coordinate value which needs to be constrained
3644 * @return {Number} The constrained coordinate value
3646 _getConstrainedPos: function(pos, val) {
3648 var overlayEl = this.element,
3650 buffer = Overlay.VIEWPORT_OFFSET,
3654 overlaySize = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3655 viewportSize = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3656 docScroll = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3657 overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3659 context = this.cfg.getProperty("context"),
3661 bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3662 bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3664 minConstraint = docScroll + buffer,
3665 maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3667 constrainedVal = val;
3669 if (val < minConstraint || val > maxConstraint) {
3670 if (bPreventContextOverlap) {
3671 constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3673 if (bOverlayFitsInViewport) {
3674 if (val < minConstraint) {
3675 constrainedVal = minConstraint;
3676 } else if (val > maxConstraint) {
3677 constrainedVal = maxConstraint;
3680 constrainedVal = minConstraint;
3685 return constrainedVal;
3689 * Helper method, used to position the Overlap to prevent overlap with the
3690 * context element (used when preventcontextoverlap is enabled)
3692 * @method _preventOverlap
3694 * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3695 * @param {HTMLElement} contextEl The context element
3696 * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3697 * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3698 * @param {Object} docScroll The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3700 * @return {Number} The new coordinate value which was set to prevent overlap
3702 _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3704 var x = (pos == "x"),
3706 buffer = Overlay.VIEWPORT_OFFSET,
3710 contextElPos = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3711 contextElSize = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3713 minRegionSize = contextElPos - buffer,
3714 maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3718 flip = function () {
3721 if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3722 flippedVal = (contextElPos - overlaySize);
3724 flippedVal = (contextElPos + contextElSize);
3727 overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3732 setPosition = function () {
3734 var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3737 if (overlaySize > displayRegionSize) {
3740 All possible positions and values have been
3741 tried, but none were successful, so fall back
3742 to the original size and position.
3748 position = setPosition();
3757 return this.cfg.getProperty(pos);
3761 * Given x coordinate value, returns the calculated x coordinate required to
3762 * position the Overlay if it is to be constrained to the viewport, based on the
3763 * current element size, viewport dimensions and scroll values.
3765 * @param {Number} x The X coordinate value to be constrained
3766 * @return {Number} The constrained x coordinate
3768 getConstrainedX: function (x) {
3769 return this._getConstrainedPos("x", x);
3773 * Given y coordinate value, returns the calculated y coordinate required to
3774 * position the Overlay if it is to be constrained to the viewport, based on the
3775 * current element size, viewport dimensions and scroll values.
3777 * @param {Number} y The Y coordinate value to be constrained
3778 * @return {Number} The constrained y coordinate
3780 getConstrainedY : function (y) {
3781 return this._getConstrainedPos("y", y);
3785 * Given x, y coordinate values, returns the calculated coordinates required to
3786 * position the Overlay if it is to be constrained to the viewport, based on the
3787 * current element size, viewport dimensions and scroll values.
3789 * @param {Number} x The X coordinate value to be constrained
3790 * @param {Number} y The Y coordinate value to be constrained
3791 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3793 getConstrainedXY: function(x, y) {
3794 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3798 * Centers the container in the viewport.
3801 center: function () {
3803 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3804 elementWidth = this.element.offsetWidth,
3805 elementHeight = this.element.offsetHeight,
3806 viewPortWidth = Dom.getViewportWidth(),
3807 viewPortHeight = Dom.getViewportHeight(),
3811 if (elementWidth < viewPortWidth) {
3812 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3814 x = nViewportOffset + Dom.getDocumentScrollLeft();
3817 if (elementHeight < viewPortHeight) {
3818 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3820 y = nViewportOffset + Dom.getDocumentScrollTop();
3823 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3824 this.cfg.refireEvent("iframe");
3827 this.forceContainerRedraw();
3832 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3833 * Panel's position in the DOM. This is primarily used to update
3834 * position information during drag & drop.
3835 * @method syncPosition
3837 syncPosition: function () {
3839 var pos = Dom.getXY(this.element);
3841 this.cfg.setProperty("x", pos[0], true);
3842 this.cfg.setProperty("y", pos[1], true);
3843 this.cfg.setProperty("xy", pos, true);
3848 * Event handler fired when the resize monitor element is resized.
3849 * @method onDomResize
3850 * @param {DOMEvent} e The resize DOM event
3851 * @param {Object} obj The scope object
3853 onDomResize: function (e, obj) {
3857 Overlay.superclass.onDomResize.call(this, e, obj);
3859 setTimeout(function () {
3861 me.cfg.refireEvent("iframe");
3862 me.cfg.refireEvent("context");
3867 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3869 * @method _getComputedHeight
3871 * @param {HTMLElement} el The element for which the content height needs to be determined
3872 * @return {Number} The content box height of the given element, or null if it could not be determined.
3874 _getComputedHeight : (function() {
3876 if (document.defaultView && document.defaultView.getComputedStyle) {
3877 return function(el) {
3879 if (el.ownerDocument && el.ownerDocument.defaultView) {
3880 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3882 height = parseInt(computed.height, 10);
3885 return (Lang.isNumber(height)) ? height : null;
3888 return function(el) {
3890 if (el.style.pixelHeight) {
3891 height = el.style.pixelHeight;
3893 return (Lang.isNumber(height)) ? height : null;
3899 * autofillheight validator. Verifies that the autofill value is either null
3900 * or one of the strings : "body", "header" or "footer".
3902 * @method _validateAutoFillHeight
3904 * @param {String} val
3905 * @return true, if valid, false otherwise
3907 _validateAutoFillHeight : function(val) {
3908 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3912 * The default custom event handler executed when the overlay's height is changed,
3913 * if the autofillheight property has been set.
3915 * @method _autoFillOnHeightChange
3917 * @param {String} type The event type
3918 * @param {Array} args The array of arguments passed to event subscribers
3919 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3920 * out the containers height
3922 _autoFillOnHeightChange : function(type, args, el) {
3923 var height = this.cfg.getProperty("height");
3924 if ((height && height !== "auto") || (height === 0)) {
3925 this.fillHeight(el);
3930 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3931 * otherwise returns the offsetHeight
3932 * @method _getPreciseHeight
3934 * @param {HTMLElement} el
3935 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3937 _getPreciseHeight : function(el) {
3938 var height = el.offsetHeight;
3940 if (el.getBoundingClientRect) {
3941 var rect = el.getBoundingClientRect();
3942 height = rect.bottom - rect.top;
3950 * Sets the height on the provided header, body or footer element to
3951 * fill out the height of the container. It determines the height of the
3952 * containers content box, based on it's configured height value, and
3953 * sets the height of the autofillheight element to fill out any
3954 * space remaining after the other standard module element heights
3955 * have been accounted for.
3957 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
3958 * height has not been set on the container, since for an "auto" height container,
3959 * the heights of the header/body/footer will drive the height of the container.</p>
3961 * @method fillHeight
3962 * @param {HTMLElement} el The element which should be resized to fill out the height
3963 * of the container element.
3965 fillHeight : function(el) {
3967 var container = this.innerElement || this.element,
3968 containerEls = [this.header, this.body, this.footer],
3975 for (var i = 0, l = containerEls.length; i < l; i++) {
3976 containerEl = containerEls[i];
3978 if (el !== containerEl) {
3979 filled += this._getPreciseHeight(containerEl);
3988 if (UA.ie || UA.opera) {
3989 // Need to set height to 0, to allow height to be reduced
3990 Dom.setStyle(el, 'height', 0 + 'px');
3993 total = this._getComputedHeight(container);
3995 // Fallback, if we can't get computed value for content height
3996 if (total === null) {
3997 Dom.addClass(container, "yui-override-padding");
3998 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
3999 Dom.removeClass(container, "yui-override-padding");
4002 remaining = Math.max(total - filled, 0);
4004 Dom.setStyle(el, "height", remaining + "px");
4006 // Re-adjust height if required, to account for el padding and border
4007 if (el.offsetHeight != remaining) {
4008 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4010 Dom.setStyle(el, "height", remaining + "px");
4016 * Places the Overlay on top of all other instances of
4017 * YAHOO.widget.Overlay.
4018 * @method bringToTop
4020 bringToTop: function () {
4023 oElement = this.element;
4025 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4027 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4028 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4030 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4031 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4033 if (nZIndex1 > nZIndex2) {
4035 } else if (nZIndex1 < nZIndex2) {
4042 function isOverlayElement(p_oElement) {
4044 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4045 Panel = YAHOO.widget.Panel;
4047 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4048 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4049 aOverlays[aOverlays.length] = p_oElement.parentNode;
4051 aOverlays[aOverlays.length] = p_oElement;
4056 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
4058 aOverlays.sort(compareZIndexDesc);
4060 var oTopOverlay = aOverlays[0],
4064 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4066 if (!isNaN(nTopZIndex)) {
4067 var bRequiresBump = false;
4069 if (oTopOverlay != oElement) {
4070 bRequiresBump = true;
4071 } else if (aOverlays.length > 1) {
4072 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4073 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4074 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4075 bRequiresBump = true;
4078 if (bRequiresBump) {
4079 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4086 * Removes the Overlay element from the DOM and sets all child
4090 destroy: function () {
4093 this.iframe.parentNode.removeChild(this.iframe);
4098 Overlay.windowResizeEvent.unsubscribe(
4099 this.doCenterOnDOMEvent, this);
4101 Overlay.windowScrollEvent.unsubscribe(
4102 this.doCenterOnDOMEvent, this);
4104 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4106 if (this._contextTriggers) {
4107 // Unsubscribe context triggers - to cover context triggers which listen for global
4108 // events such as windowResize and windowScroll. Easier just to unsubscribe all
4109 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4112 Overlay.superclass.destroy.call(this);
4116 * Can be used to force the container to repaint/redraw it's contents.
4118 * By default applies and then removes a 1px bottom margin through the
4119 * application/removal of a "yui-force-redraw" class.
4122 * It is currently used by Overlay to force a repaint for webkit
4123 * browsers, when centering.
4125 * @method forceContainerRedraw
4127 forceContainerRedraw : function() {
4129 Dom.addClass(c.element, "yui-force-redraw");
4130 setTimeout(function() {
4131 Dom.removeClass(c.element, "yui-force-redraw");
4136 * Returns a String representation of the object.
4138 * @return {String} The string representation of the Overlay.
4140 toString: function () {
4141 return "Overlay " + this.id;
4149 * OverlayManager is used for maintaining the focus status of
4150 * multiple Overlays.
4151 * @namespace YAHOO.widget
4152 * @namespace YAHOO.widget
4153 * @class OverlayManager
4155 * @param {Array} overlays Optional. A collection of Overlays to register
4157 * @param {Object} userConfig The object literal representing the user
4158 * configuration of the OverlayManager
4160 YAHOO.widget.OverlayManager = function (userConfig) {
4161 this.init(userConfig);
4164 var Overlay = YAHOO.widget.Overlay,
4165 Event = YAHOO.util.Event,
4166 Dom = YAHOO.util.Dom,
4167 Config = YAHOO.util.Config,
4168 CustomEvent = YAHOO.util.CustomEvent,
4169 OverlayManager = YAHOO.widget.OverlayManager;
4172 * The CSS class representing a focused Overlay
4173 * @property OverlayManager.CSS_FOCUSED
4178 OverlayManager.CSS_FOCUSED = "focused";
4180 OverlayManager.prototype = {
4183 * The class's constructor function
4184 * @property contructor
4187 constructor: OverlayManager,
4190 * The array of Overlays that are currently registered
4191 * @property overlays
4192 * @type YAHOO.widget.Overlay[]
4197 * Initializes the default configuration of the OverlayManager
4198 * @method initDefaultConfig
4200 initDefaultConfig: function () {
4202 * The collection of registered Overlays in use by
4203 * the OverlayManager
4205 * @type YAHOO.widget.Overlay[]
4208 this.cfg.addProperty("overlays", { suppressEvent: true } );
4211 * The default DOM event that should be used to focus an Overlay
4212 * @config focusevent
4214 * @default "mousedown"
4216 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4220 * Initializes the OverlayManager
4222 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4223 * register with the manager.
4224 * @param {Object} userConfig The object literal representing the user
4225 * configuration of the OverlayManager
4227 init: function (userConfig) {
4230 * The OverlayManager's Config object used for monitoring
4231 * configuration properties.
4235 this.cfg = new Config(this);
4237 this.initDefaultConfig();
4240 this.cfg.applyConfig(userConfig, true);
4242 this.cfg.fireQueue();
4245 * The currently activated Overlay
4246 * @property activeOverlay
4248 * @type YAHOO.widget.Overlay
4250 var activeOverlay = null;
4253 * Returns the currently focused Overlay
4255 * @return {Overlay} The currently focused Overlay
4257 this.getActive = function () {
4258 return activeOverlay;
4262 * Focuses the specified Overlay
4264 * @param {Overlay} overlay The Overlay to focus
4265 * @param {String} overlay The id of the Overlay to focus
4267 this.focus = function (overlay) {
4268 var o = this.find(overlay);
4275 * Removes the specified Overlay from the manager
4277 * @param {Overlay} overlay The Overlay to remove
4278 * @param {String} overlay The id of the Overlay to remove
4280 this.remove = function (overlay) {
4282 var o = this.find(overlay),
4286 if (activeOverlay == o) {
4287 activeOverlay = null;
4290 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4293 // Set it's zindex so that it's sorted to the end.
4294 originalZ = Dom.getStyle(o.element, "zIndex");
4295 o.cfg.setProperty("zIndex", -1000, true);
4298 this.overlays.sort(this.compareZIndexDesc);
4299 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4301 o.hideEvent.unsubscribe(o.blur);
4302 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4303 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4304 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4307 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4308 o.cfg.setProperty("zIndex", originalZ, true);
4309 o.cfg.setProperty("manager", null);
4312 /* _managed Flag for custom or existing. Don't want to remove existing */
4313 if (o.focusEvent._managed) { o.focusEvent = null; }
4314 if (o.blurEvent._managed) { o.blurEvent = null; }
4316 if (o.focus._managed) { o.focus = null; }
4317 if (o.blur._managed) { o.blur = null; }
4322 * Removes focus from all registered Overlays in the manager
4325 this.blurAll = function () {
4327 var nOverlays = this.overlays.length,
4330 if (nOverlays > 0) {
4333 this.overlays[i].blur();
4340 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4343 * @method _manageBlur
4344 * @param {Overlay} overlay The overlay instance which got blurred.
4347 this._manageBlur = function (overlay) {
4348 var changed = false;
4349 if (activeOverlay == overlay) {
4350 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4351 activeOverlay = null;
4358 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4361 * @method _manageFocus
4362 * @param {Overlay} overlay The overlay instance which got focus.
4365 this._manageFocus = function(overlay) {
4366 var changed = false;
4367 if (activeOverlay != overlay) {
4368 if (activeOverlay) {
4369 activeOverlay.blur();
4371 activeOverlay = overlay;
4372 this.bringToTop(activeOverlay);
4373 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4379 var overlays = this.cfg.getProperty("overlays");
4381 if (! this.overlays) {
4386 this.register(overlays);
4387 this.overlays.sort(this.compareZIndexDesc);
4392 * @method _onOverlayElementFocus
4393 * @description Event handler for the DOM event that is used to focus
4394 * the Overlay instance as specified by the "focusevent"
4395 * configuration property.
4397 * @param {Event} p_oEvent Object representing the DOM event
4398 * object passed back by the event utility (Event).
4400 _onOverlayElementFocus: function (p_oEvent) {
4402 var oTarget = Event.getTarget(p_oEvent),
4403 oClose = this.close;
4405 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4413 * @method _onOverlayDestroy
4414 * @description "destroy" event handler for the Overlay.
4416 * @param {String} p_sType String representing the name of the event
4418 * @param {Array} p_aArgs Array of arguments sent when the event
4420 * @param {Overlay} p_oOverlay Object representing the overlay that
4423 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4424 this.remove(p_oOverlay);
4428 * @method _onOverlayFocusHandler
4430 * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4433 * @param {String} p_sType String representing the name of the event
4435 * @param {Array} p_aArgs Array of arguments sent when the event
4437 * @param {Overlay} p_oOverlay Object representing the overlay that
4440 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4441 this._manageFocus(p_oOverlay);
4445 * @method _onOverlayBlurHandler
4446 * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4449 * @param {String} p_sType String representing the name of the event
4451 * @param {Array} p_aArgs Array of arguments sent when the event
4453 * @param {Overlay} p_oOverlay Object representing the overlay that
4456 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4457 this._manageBlur(p_oOverlay);
4461 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4462 * monitor focus state.
4464 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4465 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4466 * on the instance, the _bindFocus method will add them, and the focus method will
4467 * update the OverlayManager's state directly.
4469 * @method _bindFocus
4470 * @param {Overlay} overlay The overlay for which focus needs to be managed
4473 _bindFocus : function(overlay) {
4476 if (!overlay.focusEvent) {
4477 overlay.focusEvent = overlay.createEvent("focus");
4478 overlay.focusEvent.signature = CustomEvent.LIST;
4479 overlay.focusEvent._managed = true;
4481 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4484 if (!overlay.focus) {
4485 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4486 overlay.focus = function () {
4487 if (mgr._manageFocus(this)) {
4489 if (this.cfg.getProperty("visible") && this.focusFirst) {
4492 this.focusEvent.fire();
4495 overlay.focus._managed = true;
4500 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4501 * monitor blur state.
4503 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4504 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4505 * on the instance, the _bindBlur method will add them, and the blur method
4506 * update the OverlayManager's state directly.
4509 * @param {Overlay} overlay The overlay for which blur needs to be managed
4512 _bindBlur : function(overlay) {
4515 if (!overlay.blurEvent) {
4516 overlay.blurEvent = overlay.createEvent("blur");
4517 overlay.blurEvent.signature = CustomEvent.LIST;
4518 overlay.focusEvent._managed = true;
4520 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4523 if (!overlay.blur) {
4524 overlay.blur = function () {
4525 if (mgr._manageBlur(this)) {
4526 this.blurEvent.fire();
4529 overlay.blur._managed = true;
4532 overlay.hideEvent.subscribe(overlay.blur);
4536 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4537 * to be removed for the OverlayManager when destroyed.
4539 * @method _bindDestroy
4540 * @param {Overlay} overlay The overlay instance being managed
4543 _bindDestroy : function(overlay) {
4545 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4549 * Ensures the zIndex configuration property on the managed overlay based instance
4550 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4552 * @method _syncZIndex
4553 * @param {Overlay} overlay The overlay instance being managed
4556 _syncZIndex : function(overlay) {
4557 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4558 if (!isNaN(zIndex)) {
4559 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4561 overlay.cfg.setProperty("zIndex", 0);
4566 * Registers an Overlay or an array of Overlays with the manager. Upon
4567 * registration, the Overlay receives functions for focus and blur,
4568 * along with CustomEvents for each.
4571 * @param {Overlay} overlay An Overlay to register with the manager.
4572 * @param {Overlay[]} overlay An array of Overlays to register with
4574 * @return {boolean} true if any Overlays are registered.
4576 register: function (overlay) {
4578 var registered = false,
4582 if (overlay instanceof Overlay) {
4584 overlay.cfg.addProperty("manager", { value: this } );
4586 this._bindFocus(overlay);
4587 this._bindBlur(overlay);
4588 this._bindDestroy(overlay);
4589 this._syncZIndex(overlay);
4591 this.overlays.push(overlay);
4592 this.bringToTop(overlay);
4596 } else if (overlay instanceof Array) {
4598 for (i = 0, n = overlay.length; i < n; i++) {
4599 registered = this.register(overlay[i]) || registered;
4608 * Places the specified Overlay instance on top of all other
4609 * Overlay instances.
4610 * @method bringToTop
4611 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4613 * @param {String} p_oOverlay String representing the id of an
4616 bringToTop: function (p_oOverlay) {
4618 var oOverlay = this.find(p_oOverlay),
4625 aOverlays = this.overlays;
4626 aOverlays.sort(this.compareZIndexDesc);
4628 oTopOverlay = aOverlays[0];
4631 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4633 if (!isNaN(nTopZIndex)) {
4635 var bRequiresBump = false;
4637 if (oTopOverlay !== oOverlay) {
4638 bRequiresBump = true;
4639 } else if (aOverlays.length > 1) {
4640 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4641 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4642 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4643 bRequiresBump = true;
4647 if (bRequiresBump) {
4648 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4651 aOverlays.sort(this.compareZIndexDesc);
4657 * Attempts to locate an Overlay by instance or ID.
4659 * @param {Overlay} overlay An Overlay to locate within the manager
4660 * @param {String} overlay An Overlay id to locate within the manager
4661 * @return {Overlay} The requested Overlay, if found, or null if it
4662 * cannot be located.
4664 find: function (overlay) {
4666 var isInstance = overlay instanceof Overlay,
4667 overlays = this.overlays,
4668 n = overlays.length,
4673 if (isInstance || typeof overlay == "string") {
4674 for (i = n-1; i >= 0; i--) {
4676 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4687 * Used for sorting the manager's Overlays by z-index.
4688 * @method compareZIndexDesc
4690 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4691 * fall in the stacking order.
4693 compareZIndexDesc: function (o1, o2) {
4695 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4696 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4698 if (zIndex1 === null && zIndex2 === null) {
4700 } else if (zIndex1 === null){
4702 } else if (zIndex2 === null) {
4704 } else if (zIndex1 > zIndex2) {
4706 } else if (zIndex1 < zIndex2) {
4714 * Shows all Overlays in the manager.
4717 showAll: function () {
4718 var overlays = this.overlays,
4719 n = overlays.length,
4722 for (i = n - 1; i >= 0; i--) {
4728 * Hides all Overlays in the manager.
4731 hideAll: function () {
4732 var overlays = this.overlays,
4733 n = overlays.length,
4736 for (i = n - 1; i >= 0; i--) {
4742 * Returns a string representation of the object.
4744 * @return {String} The string representation of the OverlayManager
4746 toString: function () {
4747 return "OverlayManager";
4754 * Tooltip is an implementation of Overlay that behaves like an OS tooltip,
4755 * displaying when the user mouses over a particular element, and
4756 * disappearing on mouse out.
4757 * @namespace YAHOO.widget
4759 * @extends YAHOO.widget.Overlay
4761 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4762 * @param {HTMLElement} el The element representing the Tooltip
4763 * @param {Object} userConfig The configuration object literal containing
4764 * the configuration that should be set for this Overlay. See configuration
4765 * documentation for more details.
4767 YAHOO.widget.Tooltip = function (el, userConfig) {
4768 YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4771 var Lang = YAHOO.lang,
4772 Event = YAHOO.util.Event,
4773 CustomEvent = YAHOO.util.CustomEvent,
4774 Dom = YAHOO.util.Dom,
4775 Tooltip = YAHOO.widget.Tooltip,
4777 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
4782 * Constant representing the Tooltip's configuration properties
4783 * @property DEFAULT_CONFIG
4790 "PREVENT_OVERLAP": {
4791 key: "preventoverlap",
4793 validator: Lang.isBoolean,
4794 supercedes: ["x", "y", "xy"]
4800 validator: Lang.isNumber
4803 "AUTO_DISMISS_DELAY": {
4804 key: "autodismissdelay",
4806 validator: Lang.isNumber
4812 validator: Lang.isNumber
4838 * Constant representing the name of the Tooltip's events
4839 * @property EVENT_TYPES
4845 "CONTEXT_MOUSE_OVER": "contextMouseOver",
4846 "CONTEXT_MOUSE_OUT": "contextMouseOut",
4847 "CONTEXT_TRIGGER": "contextTrigger"
4851 * Constant representing the Tooltip CSS class
4852 * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4857 Tooltip.CSS_TOOLTIP = "yui-tt";
4859 function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
4861 var oConfig = this.cfg,
4862 sCurrentWidth = oConfig.getProperty("width");
4864 if (sCurrentWidth == sForcedWidth) {
4865 oConfig.setProperty("width", sOriginalWidth);
4870 changeContent event handler that sets a Tooltip instance's "width"
4871 configuration property to the value of its root HTML
4872 elements's offsetWidth if a specific width has not been set.
4875 function setWidthToOffsetWidth(p_sType, p_aArgs) {
4877 if ("_originalWidth" in this) {
4878 restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
4881 var oBody = document.body,
4883 sOriginalWidth = oConfig.getProperty("width"),
4887 if ((!sOriginalWidth || sOriginalWidth == "auto") &&
4888 (oConfig.getProperty("container") != oBody ||
4889 oConfig.getProperty("x") >= Dom.getViewportWidth() ||
4890 oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4892 oClone = this.element.cloneNode(true);
4893 oClone.style.visibility = "hidden";
4894 oClone.style.top = "0px";
4895 oClone.style.left = "0px";
4897 oBody.appendChild(oClone);
4899 sNewWidth = (oClone.offsetWidth + "px");
4901 oBody.removeChild(oClone);
4904 oConfig.setProperty("width", sNewWidth);
4905 oConfig.refireEvent("xy");
4907 this._originalWidth = sOriginalWidth || "";
4908 this._forcedWidth = sNewWidth;
4912 // "onDOMReady" that renders the ToolTip
4914 function onDOMReady(p_sType, p_aArgs, p_oObject) {
4915 this.render(p_oObject);
4918 // "init" event handler that automatically renders the Tooltip
4921 Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4924 YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
4927 * The Tooltip initialization method. This method is automatically
4928 * called by the constructor. A Tooltip is automatically rendered by
4929 * the init method, and it also is set to be invisible by default,
4930 * and constrained to viewport by default as well.
4932 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4933 * @param {HTMLElement} el The element representing the Tooltip
4934 * @param {Object} userConfig The configuration object literal
4935 * containing the configuration that should be set for this Tooltip.
4936 * See configuration documentation for more details.
4938 init: function (el, userConfig) {
4940 this.logger = new YAHOO.widget.LogWriter(this.toString());
4942 Tooltip.superclass.init.call(this, el);
4944 this.beforeInitEvent.fire(Tooltip);
4946 Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
4949 this.cfg.applyConfig(userConfig, true);
4952 this.cfg.queueProperty("visible", false);
4953 this.cfg.queueProperty("constraintoviewport", true);
4957 this.subscribe("changeContent", setWidthToOffsetWidth);
4958 this.subscribe("init", onInit);
4959 this.subscribe("render", this.onRender);
4961 this.initEvent.fire(Tooltip);
4965 * Initializes the custom events for Tooltip
4966 * @method initEvents
4968 initEvents: function () {
4970 Tooltip.superclass.initEvents.call(this);
4971 var SIGNATURE = CustomEvent.LIST;
4974 * CustomEvent fired when user mouses over a context element. Returning false from
4975 * a subscriber to this event will prevent the tooltip from being displayed for
4976 * the current context element.
4978 * @event contextMouseOverEvent
4979 * @param {HTMLElement} context The context element which the user just moused over
4980 * @param {DOMEvent} e The DOM event object, associated with the mouse over
4982 this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
4983 this.contextMouseOverEvent.signature = SIGNATURE;
4986 * CustomEvent fired when the user mouses out of a context element.
4988 * @event contextMouseOutEvent
4989 * @param {HTMLElement} context The context element which the user just moused out of
4990 * @param {DOMEvent} e The DOM event object, associated with the mouse out
4992 this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
4993 this.contextMouseOutEvent.signature = SIGNATURE;
4996 * CustomEvent fired just before the tooltip is displayed for the current context.
4998 * You can subscribe to this event if you need to set up the text for the
4999 * tooltip based on the context element for which it is about to be displayed.
5001 * <p>This event differs from the beforeShow event in following respects:</p>
5004 * When moving from one context element to another, if the tooltip is not
5005 * hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
5006 * be fired when the tooltip is displayed for the new context since it is already visible.
5007 * However the contextTrigger event is always fired before displaying the tooltip for
5011 * The trigger event provides access to the context element, allowing you to
5012 * set the text of the tooltip based on context element for which the tooltip is
5017 * It is not possible to prevent the tooltip from being displayed
5018 * using this event. You can use the contextMouseOverEvent if you need to prevent
5019 * the tooltip from being displayed.
5021 * @event contextTriggerEvent
5022 * @param {HTMLElement} context The context element for which the tooltip is triggered
5024 this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
5025 this.contextTriggerEvent.signature = SIGNATURE;
5029 * Initializes the class's configurable properties which can be
5030 * changed using the Overlay's Config object (cfg).
5031 * @method initDefaultConfig
5033 initDefaultConfig: function () {
5035 Tooltip.superclass.initDefaultConfig.call(this);
5038 * Specifies whether the Tooltip should be kept from overlapping
5039 * its context element.
5040 * @config preventoverlap
5044 this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
5045 value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
5046 validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
5047 supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
5051 * The number of milliseconds to wait before showing a Tooltip
5057 this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
5058 handler: this.configShowDelay,
5060 validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5064 * The number of milliseconds to wait before automatically
5065 * dismissing a Tooltip after the mouse has been resting on the
5067 * @config autodismissdelay
5071 this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
5072 handler: this.configAutoDismissDelay,
5073 value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
5074 validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
5078 * The number of milliseconds to wait before hiding a Tooltip
5084 this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
5085 handler: this.configHideDelay,
5086 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5087 validator: DEFAULT_CONFIG.HIDE_DELAY.validator
5091 * Specifies the Tooltip's text.
5096 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
5097 handler: this.configText,
5098 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
5102 * Specifies the container element that the Tooltip's markup
5103 * should be rendered into.
5105 * @type HTMLElement/String
5106 * @default document.body
5108 this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
5109 handler: this.configContainer,
5110 value: document.body
5114 * Specifies whether or not the tooltip is disabled. Disabled tooltips
5115 * will not be displayed. If the tooltip is driven by the title attribute
5116 * of the context element, the title attribute will still be removed for
5117 * disabled tooltips, to prevent default tooltip behavior.
5123 this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
5124 handler: this.configContainer,
5125 value: DEFAULT_CONFIG.DISABLED.value,
5126 supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5130 * Specifies the XY offset from the mouse position, where the tooltip should be displayed, specified
5131 * as a 2 element array (e.g. [10, 20]);
5137 this.cfg.addProperty(DEFAULT_CONFIG.XY_OFFSET.key, {
5138 value: DEFAULT_CONFIG.XY_OFFSET.value.concat(),
5139 supressEvent: DEFAULT_CONFIG.XY_OFFSET.suppressEvent
5143 * Specifies the element or elements that the Tooltip should be
5144 * anchored to on mouseover.
5146 * @type HTMLElement[]/String[]
5151 * String representing the width of the Tooltip. <em>Please note:
5152 * </em> As of version 2.3 if either no value or a value of "auto"
5153 * is specified, and the Toolip's "container" configuration property
5154 * is set to something other than <code>document.body</code> or
5155 * its "context" element resides outside the immediately visible
5156 * portion of the document, the width of the Tooltip will be
5157 * calculated based on the offsetWidth of its root HTML and set just
5158 * before it is made visible. The original value will be
5159 * restored when the Tooltip is hidden. This ensures the Tooltip is
5160 * rendered at a usable width. For more information see
5161 * YUILibrary bug #1685496 and YUILibrary
5170 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5173 * The default event handler fired when the "text" property is changed.
5174 * @method configText
5175 * @param {String} type The CustomEvent type (usually the property name)
5176 * @param {Object[]} args The CustomEvent arguments. For configuration
5177 * handlers, args[0] will equal the newly applied value for the property.
5178 * @param {Object} obj The scope object. For configuration handlers,
5179 * this will usually equal the owner.
5181 configText: function (type, args, obj) {
5189 * The default event handler fired when the "container" property
5191 * @method configContainer
5192 * @param {String} type The CustomEvent type (usually the property name)
5193 * @param {Object[]} args The CustomEvent arguments. For
5194 * configuration handlers, args[0] will equal the newly applied value
5196 * @param {Object} obj The scope object. For configuration handlers,
5197 * this will usually equal the owner.
5199 configContainer: function (type, args, obj) {
5200 var container = args[0];
5202 if (typeof container == 'string') {
5203 this.cfg.setProperty("container", document.getElementById(container), true);
5208 * @method _removeEventListeners
5209 * @description Removes all of the DOM event handlers from the HTML
5210 * element(s) that trigger the display of the tooltip.
5213 _removeEventListeners: function () {
5215 var aElements = this._context,
5221 nElements = aElements.length;
5222 if (nElements > 0) {
5225 oElement = aElements[i];
5226 Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
5227 Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
5228 Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
5236 * The default event handler fired when the "context" property
5238 * @method configContext
5239 * @param {String} type The CustomEvent type (usually the property name)
5240 * @param {Object[]} args The CustomEvent arguments. For configuration
5241 * handlers, args[0] will equal the newly applied value for the property.
5242 * @param {Object} obj The scope object. For configuration handlers,
5243 * this will usually equal the owner.
5245 configContext: function (type, args, obj) {
5247 var context = args[0],
5255 // Normalize parameter into an array
5256 if (! (context instanceof Array)) {
5257 if (typeof context == "string") {
5258 this.cfg.setProperty("context", [document.getElementById(context)], true);
5259 } else { // Assuming this is an element
5260 this.cfg.setProperty("context", [context], true);
5262 context = this.cfg.getProperty("context");
5265 // Remove any existing mouseover/mouseout listeners
5266 this._removeEventListeners();
5268 // Add mouseover/mouseout listeners to context elements
5269 this._context = context;
5271 aElements = this._context;
5274 nElements = aElements.length;
5275 if (nElements > 0) {
5278 oElement = aElements[i];
5279 Event.on(oElement, "mouseover", this.onContextMouseOver, this);
5280 Event.on(oElement, "mousemove", this.onContextMouseMove, this);
5281 Event.on(oElement, "mouseout", this.onContextMouseOut, this);
5289 // END BUILT-IN PROPERTY EVENT HANDLERS //
5291 // BEGIN BUILT-IN DOM EVENT HANDLERS //
5294 * The default event handler fired when the user moves the mouse while
5295 * over the context element.
5296 * @method onContextMouseMove
5297 * @param {DOMEvent} e The current DOM event
5298 * @param {Object} obj The object argument
5300 onContextMouseMove: function (e, obj) {
5301 obj.pageX = Event.getPageX(e);
5302 obj.pageY = Event.getPageY(e);
5306 * The default event handler fired when the user mouses over the
5308 * @method onContextMouseOver
5309 * @param {DOMEvent} e The current DOM event
5310 * @param {Object} obj The object argument
5312 onContextMouseOver: function (e, obj) {
5315 if (context.title) {
5316 obj._tempTitle = context.title;
5320 // Fire first, to honor disabled set in the listner
5321 if (obj.fireEvent("contextMouseOver", context, e) !== false
5322 && !obj.cfg.getProperty("disabled")) {
5324 // Stop the tooltip from being hidden (set on last mouseout)
5325 if (obj.hideProcId) {
5326 clearTimeout(obj.hideProcId);
5327 obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
5328 obj.hideProcId = null;
5331 Event.on(context, "mousemove", obj.onContextMouseMove, obj);
5334 * The unique process ID associated with the thread responsible
5335 * for showing the Tooltip.
5338 obj.showProcId = obj.doShow(e, context);
5339 obj.logger.log("Setting show tooltip timeout: " + obj.showProcId, "time");
5344 * The default event handler fired when the user mouses out of
5345 * the context element.
5346 * @method onContextMouseOut
5347 * @param {DOMEvent} e The current DOM event
5348 * @param {Object} obj The object argument
5350 onContextMouseOut: function (e, obj) {
5353 if (obj._tempTitle) {
5354 el.title = obj._tempTitle;
5355 obj._tempTitle = null;
5358 if (obj.showProcId) {
5359 clearTimeout(obj.showProcId);
5360 obj.logger.log("Clearing show timer: " + obj.showProcId, "time");
5361 obj.showProcId = null;
5364 if (obj.hideProcId) {
5365 clearTimeout(obj.hideProcId);
5366 obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
5367 obj.hideProcId = null;
5370 obj.fireEvent("contextMouseOut", el, e);
5372 obj.hideProcId = setTimeout(function () {
5374 }, obj.cfg.getProperty("hidedelay"));
5377 // END BUILT-IN DOM EVENT HANDLERS //
5380 * Processes the showing of the Tooltip by setting the timeout delay
5381 * and offset of the Tooltip.
5383 * @param {DOMEvent} e The current DOM event
5384 * @param {HTMLElement} context The current context element
5385 * @return {Number} The process ID of the timeout function associated
5388 doShow: function (e, context) {
5390 var offset = this.cfg.getProperty("xyoffset"),
5391 xOffset = offset[0],
5392 yOffset = offset[1],
5395 if (UA.opera && context.tagName &&
5396 context.tagName.toUpperCase() == "A") {
5400 return setTimeout(function () {
5402 var txt = me.cfg.getProperty("text");
5404 // title does not over-ride text
5405 if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
5406 me.setBody(me._tempTitle);
5408 me.cfg.refireEvent("text");
5411 me.logger.log("Show tooltip", "time");
5412 me.moveTo(me.pageX + xOffset, me.pageY + yOffset);
5414 if (me.cfg.getProperty("preventoverlap")) {
5415 me.preventOverlap(me.pageX, me.pageY);
5418 Event.removeListener(context, "mousemove", me.onContextMouseMove);
5420 me.contextTriggerEvent.fire(context);
5424 me.hideProcId = me.doHide();
5425 me.logger.log("Hide tooltip time active: " + me.hideProcId, "time");
5427 }, this.cfg.getProperty("showdelay"));
5431 * Sets the timeout for the auto-dismiss delay, which by default is 5
5432 * seconds, meaning that a tooltip will automatically dismiss itself
5433 * after 5 seconds of being displayed.
5436 doHide: function () {
5440 me.logger.log("Setting hide tooltip timeout", "time");
5442 return setTimeout(function () {
5444 me.logger.log("Hide tooltip", "time");
5447 }, this.cfg.getProperty("autodismissdelay"));
5452 * Fired when the Tooltip is moved, this event handler is used to
5453 * prevent the Tooltip from overlapping with its context element.
5454 * @method preventOverlay
5455 * @param {Number} pageX The x coordinate position of the mouse pointer
5456 * @param {Number} pageY The y coordinate position of the mouse pointer
5458 preventOverlap: function (pageX, pageY) {
5460 var height = this.element.offsetHeight,
5461 mousePoint = new YAHOO.util.Point(pageX, pageY),
5462 elementRegion = Dom.getRegion(this.element);
5464 elementRegion.top -= 5;
5465 elementRegion.left -= 5;
5466 elementRegion.right += 5;
5467 elementRegion.bottom += 5;
5469 this.logger.log("context " + elementRegion, "ttip");
5470 this.logger.log("mouse " + mousePoint, "ttip");
5472 if (elementRegion.contains(mousePoint)) {
5473 this.logger.log("OVERLAP", "warn");
5474 this.cfg.setProperty("y", (pageY - height - 5));
5481 * @description "render" event handler for the Tooltip.
5482 * @param {String} p_sType String representing the name of the event
5484 * @param {Array} p_aArgs Array of arguments sent when the event
5487 onRender: function (p_sType, p_aArgs) {
5489 function sizeShadow() {
5491 var oElement = this.element,
5492 oShadow = this.underlay;
5495 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
5496 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
5501 function addShadowVisibleClass() {
5502 Dom.addClass(this.underlay, "yui-tt-shadow-visible");
5505 this.forceUnderlayRedraw();
5509 function removeShadowVisibleClass() {
5510 Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
5513 function createShadow() {
5515 var oShadow = this.underlay,
5523 oElement = this.element;
5524 Module = YAHOO.widget.Module;
5528 if (!m_oShadowTemplate) {
5529 m_oShadowTemplate = document.createElement("div");
5530 m_oShadowTemplate.className = "yui-tt-shadow";
5533 oShadow = m_oShadowTemplate.cloneNode(false);
5535 oElement.appendChild(oShadow);
5537 this.underlay = oShadow;
5539 // Backward compatibility, even though it's probably
5540 // intended to be "private", it isn't marked as such in the api docs
5541 this._shadow = this.underlay;
5543 addShadowVisibleClass.call(this);
5545 this.subscribe("beforeShow", addShadowVisibleClass);
5546 this.subscribe("hide", removeShadowVisibleClass);
5549 window.setTimeout(function () {
5550 sizeShadow.call(me);
5553 this.cfg.subscribeToConfigEvent("width", sizeShadow);
5554 this.cfg.subscribeToConfigEvent("height", sizeShadow);
5555 this.subscribe("changeContent", sizeShadow);
5557 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5558 this.subscribe("destroy", function () {
5559 Module.textResizeEvent.unsubscribe(sizeShadow, this);
5565 function onBeforeShow() {
5566 createShadow.call(this);
5567 this.unsubscribe("beforeShow", onBeforeShow);
5570 if (this.cfg.getProperty("visible")) {
5571 createShadow.call(this);
5573 this.subscribe("beforeShow", onBeforeShow);
5579 * Forces the underlay element to be repainted, through the application/removal
5580 * of a yui-force-redraw class to the underlay element.
5582 * @method forceUnderlayRedraw
5584 forceUnderlayRedraw : function() {
5586 Dom.addClass(tt.underlay, "yui-force-redraw");
5587 setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
5591 * Removes the Tooltip element from the DOM and sets all child
5595 destroy: function () {
5597 // Remove any existing mouseover/mouseout listeners
5598 this._removeEventListeners();
5600 Tooltip.superclass.destroy.call(this);
5605 * Returns a string representation of the object.
5607 * @return {String} The string representation of the Tooltip
5609 toString: function () {
5610 return "Tooltip " + this.id;
5619 * Panel is an implementation of Overlay that behaves like an OS window,
5620 * with a draggable header and an optional close icon at the top right.
5621 * @namespace YAHOO.widget
5623 * @extends YAHOO.widget.Overlay
5625 * @param {String} el The element ID representing the Panel <em>OR</em>
5626 * @param {HTMLElement} el The element representing the Panel
5627 * @param {Object} userConfig The configuration object literal containing
5628 * the configuration that should be set for this Panel. See configuration
5629 * documentation for more details.
5631 YAHOO.widget.Panel = function (el, userConfig) {
5632 YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5635 var _currentModal = null;
5637 var Lang = YAHOO.lang,
5641 CustomEvent = Util.CustomEvent,
5642 KeyListener = YAHOO.util.KeyListener,
5643 Config = Util.Config,
5644 Overlay = YAHOO.widget.Overlay,
5645 Panel = YAHOO.widget.Panel,
5648 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
5651 m_oUnderlayTemplate,
5652 m_oCloseIconTemplate,
5655 * Constant representing the name of the Panel's events
5656 * @property EVENT_TYPES
5662 "SHOW_MASK": "showMask",
5663 "HIDE_MASK": "hideMask",
5668 * Constant representing the Panel's configuration properties
5669 * @property DEFAULT_CONFIG
5679 validator: Lang.isBoolean,
5680 supercedes: ["visible"]
5685 value: (Util.DD ? true : false),
5686 validator: Lang.isBoolean,
5687 supercedes: ["visible"]
5693 validator: Lang.isBoolean,
5694 supercedes: ["draggable"]
5700 supercedes: ["visible"]
5706 validator: Lang.isBoolean,
5707 supercedes: ["visible", "zindex"]
5711 key: "keylisteners",
5712 suppressEvent: true,
5713 supercedes: ["visible"]
5718 supercedes: ["close"],
5719 validator: Lang.isObject,
5727 * Constant representing the default CSS class used for a Panel
5728 * @property YAHOO.widget.Panel.CSS_PANEL
5733 Panel.CSS_PANEL = "yui-panel";
5736 * Constant representing the default CSS class used for a Panel's
5737 * wrapping container
5738 * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5743 Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5746 * Constant representing the default set of focusable elements
5747 * on the pagewhich Modal Panels will prevent access to, when
5748 * the modal mask is displayed
5750 * @property YAHOO.widget.Panel.FOCUSABLE
5763 // Private CustomEvent listeners
5766 "beforeRender" event handler that creates an empty header for a Panel
5767 instance if its "draggable" configuration property is set to "true"
5768 and no header has been created.
5771 function createHeader(p_sType, p_aArgs) {
5772 if (!this.header && this.cfg.getProperty("draggable")) {
5773 this.setHeader(" ");
5778 "hide" event handler that sets a Panel instance's "width"
5779 configuration property back to its original value before
5780 "setWidthToOffsetWidth" was called.
5783 function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5785 var sOriginalWidth = p_oObject[0],
5786 sNewWidth = p_oObject[1],
5788 sCurrentWidth = oConfig.getProperty("width");
5790 if (sCurrentWidth == sNewWidth) {
5791 oConfig.setProperty("width", sOriginalWidth);
5794 this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5798 "beforeShow" event handler that sets a Panel instance's "width"
5799 configuration property to the value of its root HTML
5800 elements's offsetWidth
5803 function setWidthToOffsetWidth(p_sType, p_aArgs) {
5812 sOriginalWidth = oConfig.getProperty("width");
5814 if (!sOriginalWidth || sOriginalWidth == "auto") {
5816 sNewWidth = (this.element.offsetWidth + "px");
5818 oConfig.setProperty("width", sNewWidth);
5820 this.subscribe("hide", restoreOriginalWidth,
5821 [(sOriginalWidth || ""), sNewWidth]);
5827 YAHOO.extend(Panel, Overlay, {
5830 * The Overlay initialization method, which is executed for Overlay and
5831 * all of its subclasses. This method is automatically called by the
5832 * constructor, and sets up all DOM references for pre-existing markup,
5833 * and creates required markup if it is not already present.
5835 * @param {String} el The element ID representing the Overlay <em>OR</em>
5836 * @param {HTMLElement} el The element representing the Overlay
5837 * @param {Object} userConfig The configuration object literal
5838 * containing the configuration that should be set for this Overlay.
5839 * See configuration documentation for more details.
5841 init: function (el, userConfig) {
5843 Note that we don't pass the user config in here yet because
5844 we only want it executed once, at the lowest subclass level
5847 Panel.superclass.init.call(this, el/*, userConfig*/);
5849 this.beforeInitEvent.fire(Panel);
5851 Dom.addClass(this.element, Panel.CSS_PANEL);
5853 this.buildWrapper();
5856 this.cfg.applyConfig(userConfig, true);
5859 this.subscribe("showMask", this._addFocusHandlers);
5860 this.subscribe("hideMask", this._removeFocusHandlers);
5861 this.subscribe("beforeRender", createHeader);
5863 this.subscribe("render", function() {
5864 this.setFirstLastFocusable();
5865 this.subscribe("changeContent", this.setFirstLastFocusable);
5868 this.subscribe("show", this.focusFirst);
5870 this.initEvent.fire(Panel);
5874 * @method _onElementFocus
5877 * "focus" event handler for a focuable element. Used to automatically
5878 * blur the element when it receives focus to ensure that a Panel
5879 * instance's modality is not compromised.
5881 * @param {Event} e The DOM event object
5883 _onElementFocus : function(e){
5885 if(_currentModal === this) {
5887 var target = Event.getTarget(e),
5888 doc = document.documentElement,
5889 insideDoc = (target !== doc && target !== window);
5891 // mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on
5892 // the documentElement, when the document scrollbars are clicked on
5893 if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
5895 if (this.firstElement) {
5896 this.firstElement.focus();
5898 if (this._modalFocus) {
5899 this._modalFocus.focus();
5901 this.innerElement.focus();
5905 // Just in case we fail to focus
5907 if (insideDoc && target !== document.body) {
5917 * @method _addFocusHandlers
5920 * "showMask" event handler that adds a "focus" event handler to all
5921 * focusable elements in the document to enforce a Panel instance's
5922 * modality from being compromised.
5924 * @param p_sType {String} Custom event type
5925 * @param p_aArgs {Array} Custom event arguments
5927 _addFocusHandlers: function(p_sType, p_aArgs) {
5928 if (!this.firstElement) {
5929 if (UA.webkit || UA.opera) {
5930 if (!this._modalFocus) {
5931 this._createHiddenFocusElement();
5934 this.innerElement.tabIndex = 0;
5937 this.setTabLoop(this.firstElement, this.lastElement);
5938 Event.onFocus(document.documentElement, this._onElementFocus, this, true);
5939 _currentModal = this;
5943 * Creates a hidden focusable element, used to focus on,
5944 * to enforce modality for browsers in which focus cannot
5945 * be applied to the container box.
5947 * @method _createHiddenFocusElement
5950 _createHiddenFocusElement : function() {
5951 var e = document.createElement("button");
5952 e.style.height = "1px";
5953 e.style.width = "1px";
5954 e.style.position = "absolute";
5955 e.style.left = "-10000em";
5956 e.style.opacity = 0;
5958 this.innerElement.appendChild(e);
5959 this._modalFocus = e;
5963 * @method _removeFocusHandlers
5966 * "hideMask" event handler that removes all "focus" event handlers added
5967 * by the "addFocusEventHandlers" method.
5969 * @param p_sType {String} Event type
5970 * @param p_aArgs {Array} Event Arguments
5972 _removeFocusHandlers: function(p_sType, p_aArgs) {
5973 Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
5975 if (_currentModal == this) {
5976 _currentModal = null;
5981 * Sets focus to the first element in the Panel.
5983 * @method focusFirst
5985 focusFirst: function (type, args, obj) {
5986 var el = this.firstElement;
5988 if (args && args[1]) {
5989 Event.stopEvent(args[1]);
6002 * Sets focus to the last element in the Panel.
6006 focusLast: function (type, args, obj) {
6007 var el = this.lastElement;
6009 if (args && args[1]) {
6010 Event.stopEvent(args[1]);
6023 * Sets up a tab, shift-tab loop between the first and last elements
6024 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
6025 * instance properties, which are reset everytime this method is invoked.
6027 * @method setTabLoop
6028 * @param {HTMLElement} firstElement
6029 * @param {HTMLElement} lastElement
6032 setTabLoop : function(firstElement, lastElement) {
6034 var backTab = this.preventBackTab, tab = this.preventTabOut,
6035 showEvent = this.showEvent, hideEvent = this.hideEvent;
6039 showEvent.unsubscribe(backTab.enable, backTab);
6040 hideEvent.unsubscribe(backTab.disable, backTab);
6041 backTab = this.preventBackTab = null;
6046 showEvent.unsubscribe(tab.enable, tab);
6047 hideEvent.unsubscribe(tab.disable,tab);
6048 tab = this.preventTabOut = null;
6052 this.preventBackTab = new KeyListener(firstElement,
6053 {shift:true, keys:9},
6054 {fn:this.focusLast, scope:this, correctScope:true}
6056 backTab = this.preventBackTab;
6058 showEvent.subscribe(backTab.enable, backTab, true);
6059 hideEvent.subscribe(backTab.disable,backTab, true);
6063 this.preventTabOut = new KeyListener(lastElement,
6064 {shift:false, keys:9},
6065 {fn:this.focusFirst, scope:this, correctScope:true}
6067 tab = this.preventTabOut;
6069 showEvent.subscribe(tab.enable, tab, true);
6070 hideEvent.subscribe(tab.disable,tab, true);
6075 * Returns an array of the currently focusable items which reside within
6076 * Panel. The set of focusable elements the method looks for are defined
6077 * in the Panel.FOCUSABLE static property
6079 * @method getFocusableElements
6080 * @param {HTMLElement} root element to start from.
6082 getFocusableElements : function(root) {
6084 root = root || this.innerElement;
6087 for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
6088 focusable[Panel.FOCUSABLE[i]] = true;
6091 function isFocusable(el) {
6092 if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
6098 // Not looking by Tag, since we want elements in DOM order
6099 return Dom.getElementsBy(isFocusable, null, root);
6103 * Sets the firstElement and lastElement instance properties
6104 * to the first and last focusable elements in the Panel.
6106 * @method setFirstLastFocusable
6108 setFirstLastFocusable : function() {
6110 this.firstElement = null;
6111 this.lastElement = null;
6113 var elements = this.getFocusableElements();
6114 this.focusableElements = elements;
6116 if (elements.length > 0) {
6117 this.firstElement = elements[0];
6118 this.lastElement = elements[elements.length - 1];
6121 if (this.cfg.getProperty("modal")) {
6122 this.setTabLoop(this.firstElement, this.lastElement);
6127 * Initializes the custom events for Module which are fired
6128 * automatically at appropriate times by the Module class.
6130 initEvents: function () {
6131 Panel.superclass.initEvents.call(this);
6133 var SIGNATURE = CustomEvent.LIST;
6136 * CustomEvent fired after the modality mask is shown
6137 * @event showMaskEvent
6139 this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
6140 this.showMaskEvent.signature = SIGNATURE;
6143 * CustomEvent fired after the modality mask is hidden
6144 * @event hideMaskEvent
6146 this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
6147 this.hideMaskEvent.signature = SIGNATURE;
6150 * CustomEvent when the Panel is dragged
6153 this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
6154 this.dragEvent.signature = SIGNATURE;
6158 * Initializes the class's configurable properties which can be changed
6159 * using the Panel's Config object (cfg).
6160 * @method initDefaultConfig
6162 initDefaultConfig: function () {
6163 Panel.superclass.initDefaultConfig.call(this);
6165 // Add panel config properties //
6168 * True if the Panel should display a "close" button
6173 this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
6174 handler: this.configClose,
6175 value: DEFAULT_CONFIG.CLOSE.value,
6176 validator: DEFAULT_CONFIG.CLOSE.validator,
6177 supercedes: DEFAULT_CONFIG.CLOSE.supercedes
6181 * Boolean specifying if the Panel should be draggable. The default
6182 * value is "true" if the Drag and Drop utility is included,
6183 * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
6184 * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
6185 * (Quirks Mode) where Panels that either don't have a value set for
6186 * their "width" configuration property, or their "width"
6187 * configuration property is set to "auto" will only be draggable by
6188 * placing the mouse on the text of the Panel's header element.
6189 * To fix this bug, draggable Panels missing a value for their
6190 * "width" configuration property, or whose "width" configuration
6191 * property is set to "auto" will have it set to the value of
6192 * their root HTML element's offsetWidth before they are made
6193 * visible. The calculated width is then removed when the Panel is
6194 * hidden. <em>This fix is only applied to draggable Panels in IE 6
6195 * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
6196 * more information on this issue see:
6197 * YUILibrary bugs #1726972 and #1589210.
6202 this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
6203 handler: this.configDraggable,
6204 value: (Util.DD) ? true : false,
6205 validator: DEFAULT_CONFIG.DRAGGABLE.validator,
6206 supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
6210 * Boolean specifying if the draggable Panel should be drag only, not interacting with drop
6211 * targets on the page.
6213 * When set to true, draggable Panels will not check to see if they are over drop targets,
6214 * or fire the DragDrop events required to support drop target interaction (onDragEnter,
6215 * onDragOver, onDragOut, onDragDrop etc.).
6216 * If the Panel is not designed to be dropped on any target elements on the page, then this
6217 * flag can be set to true to improve performance.
6220 * When set to false, all drop target related events will be fired.
6223 * The property is set to false by default to maintain backwards compatibility but should be
6224 * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
6230 this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, {
6231 value: DEFAULT_CONFIG.DRAG_ONLY.value,
6232 validator: DEFAULT_CONFIG.DRAG_ONLY.validator,
6233 supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes
6237 * Sets the type of underlay to display for the Panel. Valid values
6238 * are "shadow," "matte," and "none". <strong>PLEASE NOTE:</strong>
6239 * The creation of the underlay element is deferred until the Panel
6240 * is initially made visible. For Gecko-based browsers on Mac
6241 * OS X the underlay elment is always created as it is used as a
6242 * shim to prevent Aqua scrollbars below a Panel instance from poking
6243 * through it (See YUILibrary bug #1723530).
6248 this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
6249 handler: this.configUnderlay,
6250 value: DEFAULT_CONFIG.UNDERLAY.value,
6251 supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
6255 * True if the Panel should be displayed in a modal fashion,
6256 * automatically creating a transparent mask over the document that
6257 * will not be removed until the Panel is dismissed.
6262 this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
6263 handler: this.configModal,
6264 value: DEFAULT_CONFIG.MODAL.value,
6265 validator: DEFAULT_CONFIG.MODAL.validator,
6266 supercedes: DEFAULT_CONFIG.MODAL.supercedes
6270 * A KeyListener (or array of KeyListeners) that will be enabled
6271 * when the Panel is shown, and disabled when the Panel is hidden.
6272 * @config keylisteners
6273 * @type YAHOO.util.KeyListener[]
6276 this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
6277 handler: this.configKeyListeners,
6278 suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
6279 supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
6283 * UI Strings used by the Panel
6287 * @default An object literal with the properties shown below:
6289 * <dt>close</dt><dd><em>String</em> : The string to use for the close icon. Defaults to "Close".</dd>
6292 this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, {
6293 value:DEFAULT_CONFIG.STRINGS.value,
6294 handler:this.configStrings,
6295 validator:DEFAULT_CONFIG.STRINGS.validator,
6296 supercedes:DEFAULT_CONFIG.STRINGS.supercedes
6300 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6303 * The default event handler fired when the "close" property is changed.
6304 * The method controls the appending or hiding of the close icon at the
6305 * top right of the Panel.
6306 * @method configClose
6307 * @param {String} type The CustomEvent type (usually the property name)
6308 * @param {Object[]} args The CustomEvent arguments. For configuration
6309 * handlers, args[0] will equal the newly applied value for the property.
6310 * @param {Object} obj The scope object. For configuration handlers,
6311 * this will usually equal the owner.
6313 configClose: function (type, args, obj) {
6316 oClose = this.close,
6317 strings = this.cfg.getProperty("strings");
6322 if (!m_oCloseIconTemplate) {
6323 m_oCloseIconTemplate = document.createElement("a");
6324 m_oCloseIconTemplate.className = "container-close";
6325 m_oCloseIconTemplate.href = "#";
6328 oClose = m_oCloseIconTemplate.cloneNode(true);
6329 this.innerElement.appendChild(oClose);
6331 oClose.innerHTML = (strings && strings.close) ? strings.close : " ";
6333 Event.on(oClose, "click", this._doClose, this, true);
6335 this.close = oClose;
6338 oClose.style.display = "block";
6343 oClose.style.display = "none";
6350 * Event handler for the close icon
6355 * @param {DOMEvent} e
6357 _doClose : function (e) {
6358 Event.preventDefault(e);
6363 * The default event handler fired when the "draggable" property
6365 * @method configDraggable
6366 * @param {String} type The CustomEvent type (usually the property name)
6367 * @param {Object[]} args The CustomEvent arguments. For configuration
6368 * handlers, args[0] will equal the newly applied value for the property.
6369 * @param {Object} obj The scope object. For configuration handlers,
6370 * this will usually equal the owner.
6372 configDraggable: function (type, args, obj) {
6377 YAHOO.log("DD dependency not met.", "error");
6378 this.cfg.setProperty("draggable", false);
6383 Dom.setStyle(this.header, "cursor", "move");
6384 this.registerDragDrop();
6387 this.subscribe("beforeShow", setWidthToOffsetWidth);
6396 Dom.setStyle(this.header,"cursor","auto");
6399 this.unsubscribe("beforeShow", setWidthToOffsetWidth);
6404 * The default event handler fired when the "underlay" property
6406 * @method configUnderlay
6407 * @param {String} type The CustomEvent type (usually the property name)
6408 * @param {Object[]} args The CustomEvent arguments. For configuration
6409 * handlers, args[0] will equal the newly applied value for the property.
6410 * @param {Object} obj The scope object. For configuration handlers,
6411 * this will usually equal the owner.
6413 configUnderlay: function (type, args, obj) {
6415 var bMacGecko = (this.platform == "mac" && UA.gecko),
6416 sUnderlay = args[0].toLowerCase(),
6417 oUnderlay = this.underlay,
6418 oElement = this.element;
6420 function createUnderlay() {
6422 if (!oUnderlay) { // create if not already in DOM
6424 if (!m_oUnderlayTemplate) {
6425 m_oUnderlayTemplate = document.createElement("div");
6426 m_oUnderlayTemplate.className = "underlay";
6429 oUnderlay = m_oUnderlayTemplate.cloneNode(false);
6430 this.element.appendChild(oUnderlay);
6432 this.underlay = oUnderlay;
6435 this.sizeUnderlay();
6436 this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
6437 this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
6439 this.changeContentEvent.subscribe(this.sizeUnderlay);
6440 YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
6443 if (UA.webkit && UA.webkit < 420) {
6444 this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
6451 function onBeforeShow() {
6452 var bNew = createUnderlay.call(this);
6453 if (!bNew && bIEQuirks) {
6454 this.sizeUnderlay();
6456 this._underlayDeferred = false;
6457 this.beforeShowEvent.unsubscribe(onBeforeShow);
6460 function destroyUnderlay() {
6461 if (this._underlayDeferred) {
6462 this.beforeShowEvent.unsubscribe(onBeforeShow);
6463 this._underlayDeferred = false;
6467 this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
6468 this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
6469 this.changeContentEvent.unsubscribe(this.sizeUnderlay);
6470 this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
6471 YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
6473 this.element.removeChild(oUnderlay);
6475 this.underlay = null;
6479 switch (sUnderlay) {
6481 Dom.removeClass(oElement, "matte");
6482 Dom.addClass(oElement, "shadow");
6486 destroyUnderlay.call(this);
6488 Dom.removeClass(oElement, "shadow");
6489 Dom.addClass(oElement, "matte");
6493 destroyUnderlay.call(this);
6495 Dom.removeClass(oElement, "shadow");
6496 Dom.removeClass(oElement, "matte");
6500 if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
6501 if (this.cfg.getProperty("visible")) {
6502 var bNew = createUnderlay.call(this);
6503 if (!bNew && bIEQuirks) {
6504 this.sizeUnderlay();
6507 if (!this._underlayDeferred) {
6508 this.beforeShowEvent.subscribe(onBeforeShow);
6509 this._underlayDeferred = true;
6516 * The default event handler fired when the "modal" property is
6517 * changed. This handler subscribes or unsubscribes to the show and hide
6518 * events to handle the display or hide of the modality mask.
6519 * @method configModal
6520 * @param {String} type The CustomEvent type (usually the property name)
6521 * @param {Object[]} args The CustomEvent arguments. For configuration
6522 * handlers, args[0] will equal the newly applied value for the property.
6523 * @param {Object} obj The scope object. For configuration handlers,
6524 * this will usually equal the owner.
6526 configModal: function (type, args, obj) {
6528 var modal = args[0];
6530 if (!this._hasModalityEventListeners) {
6532 this.subscribe("beforeShow", this.buildMask);
6533 this.subscribe("beforeShow", this.bringToTop);
6534 this.subscribe("beforeShow", this.showMask);
6535 this.subscribe("hide", this.hideMask);
6537 Overlay.windowResizeEvent.subscribe(this.sizeMask,
6540 this._hasModalityEventListeners = true;
6543 if (this._hasModalityEventListeners) {
6545 if (this.cfg.getProperty("visible")) {
6550 this.unsubscribe("beforeShow", this.buildMask);
6551 this.unsubscribe("beforeShow", this.bringToTop);
6552 this.unsubscribe("beforeShow", this.showMask);
6553 this.unsubscribe("hide", this.hideMask);
6555 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6557 this._hasModalityEventListeners = false;
6563 * Removes the modality mask.
6564 * @method removeMask
6566 removeMask: function () {
6568 var oMask = this.mask,
6573 Hide the mask before destroying it to ensure that DOM
6574 event handlers on focusable elements get removed.
6578 oParentNode = oMask.parentNode;
6580 oParentNode.removeChild(oMask);
6588 * The default event handler fired when the "keylisteners" property
6590 * @method configKeyListeners
6591 * @param {String} type The CustomEvent type (usually the property name)
6592 * @param {Object[]} args The CustomEvent arguments. For configuration
6593 * handlers, args[0] will equal the newly applied value for the property.
6594 * @param {Object} obj The scope object. For configuration handlers,
6595 * this will usually equal the owner.
6597 configKeyListeners: function (type, args, obj) {
6599 var listeners = args[0],
6606 if (listeners instanceof Array) {
6608 nListeners = listeners.length;
6610 for (i = 0; i < nListeners; i++) {
6612 listener = listeners[i];
6614 if (!Config.alreadySubscribed(this.showEvent,
6615 listener.enable, listener)) {
6617 this.showEvent.subscribe(listener.enable,
6622 if (!Config.alreadySubscribed(this.hideEvent,
6623 listener.disable, listener)) {
6625 this.hideEvent.subscribe(listener.disable,
6628 this.destroyEvent.subscribe(listener.disable,
6635 if (!Config.alreadySubscribed(this.showEvent,
6636 listeners.enable, listeners)) {
6638 this.showEvent.subscribe(listeners.enable,
6642 if (!Config.alreadySubscribed(this.hideEvent,
6643 listeners.disable, listeners)) {
6645 this.hideEvent.subscribe(listeners.disable,
6648 this.destroyEvent.subscribe(listeners.disable,
6660 * The default handler for the "strings" property
6661 * @method configStrings
6663 configStrings : function(type, args, obj) {
6664 var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
6665 this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
6669 * The default event handler fired when the "height" property is changed.
6670 * @method configHeight
6671 * @param {String} type The CustomEvent type (usually the property name)
6672 * @param {Object[]} args The CustomEvent arguments. For configuration
6673 * handlers, args[0] will equal the newly applied value for the property.
6674 * @param {Object} obj The scope object. For configuration handlers,
6675 * this will usually equal the owner.
6677 configHeight: function (type, args, obj) {
6678 var height = args[0],
6679 el = this.innerElement;
6681 Dom.setStyle(el, "height", height);
6682 this.cfg.refireEvent("iframe");
6686 * The default custom event handler executed when the Panel's height is changed,
6687 * if the autofillheight property has been set.
6689 * @method _autoFillOnHeightChange
6691 * @param {String} type The event type
6692 * @param {Array} args The array of arguments passed to event subscribers
6693 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
6694 * out the containers height
6696 _autoFillOnHeightChange : function(type, args, el) {
6697 Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
6700 setTimeout(function() {
6701 panel.sizeUnderlay();
6707 * The default event handler fired when the "width" property is changed.
6708 * @method configWidth
6709 * @param {String} type The CustomEvent type (usually the property name)
6710 * @param {Object[]} args The CustomEvent arguments. For configuration
6711 * handlers, args[0] will equal the newly applied value for the property.
6712 * @param {Object} obj The scope object. For configuration handlers,
6713 * this will usually equal the owner.
6715 configWidth: function (type, args, obj) {
6717 var width = args[0],
6718 el = this.innerElement;
6720 Dom.setStyle(el, "width", width);
6721 this.cfg.refireEvent("iframe");
6726 * The default event handler fired when the "zIndex" property is changed.
6727 * @method configzIndex
6728 * @param {String} type The CustomEvent type (usually the property name)
6729 * @param {Object[]} args The CustomEvent arguments. For configuration
6730 * handlers, args[0] will equal the newly applied value for the property.
6731 * @param {Object} obj The scope object. For configuration handlers,
6732 * this will usually equal the owner.
6734 configzIndex: function (type, args, obj) {
6735 Panel.superclass.configzIndex.call(this, type, args, obj);
6737 if (this.mask || this.cfg.getProperty("modal") === true) {
6738 var panelZ = Dom.getStyle(this.element, "zIndex");
6739 if (!panelZ || isNaN(panelZ)) {
6744 // Recursive call to configzindex (which should be stopped
6745 // from going further because panelZ should no longer === 0)
6746 this.cfg.setProperty("zIndex", 1);
6753 // END BUILT-IN PROPERTY EVENT HANDLERS //
6755 * Builds the wrapping container around the Panel that is used for
6756 * positioning the shadow and matte underlays. The container element is
6757 * assigned to a local instance variable called container, and the
6758 * element is reinserted inside of it.
6759 * @method buildWrapper
6761 buildWrapper: function () {
6763 var elementParent = this.element.parentNode,
6764 originalElement = this.element,
6765 wrapper = document.createElement("div");
6767 wrapper.className = Panel.CSS_PANEL_CONTAINER;
6768 wrapper.id = originalElement.id + "_c";
6770 if (elementParent) {
6771 elementParent.insertBefore(wrapper, originalElement);
6774 wrapper.appendChild(originalElement);
6776 this.element = wrapper;
6777 this.innerElement = originalElement;
6779 Dom.setStyle(this.innerElement, "visibility", "inherit");
6783 * Adjusts the size of the shadow based on the size of the element.
6784 * @method sizeUnderlay
6786 sizeUnderlay: function () {
6787 var oUnderlay = this.underlay,
6791 oElement = this.element;
6792 oUnderlay.style.width = oElement.offsetWidth + "px";
6793 oUnderlay.style.height = oElement.offsetHeight + "px";
6798 * Registers the Panel's header for drag & drop capability.
6799 * @method registerDragDrop
6801 registerDragDrop: function () {
6808 YAHOO.log("DD dependency not met.", "error");
6812 var bDragOnly = (this.cfg.getProperty("dragonly") === true);
6815 * The YAHOO.util.DD instance, used to implement the draggable header for the panel if draggable is enabled
6818 * @type YAHOO.util.DD
6820 this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
6822 if (!this.header.id) {
6823 this.header.id = this.id + "_h";
6826 this.dd.startDrag = function () {
6835 if (YAHOO.env.ua.ie == 6) {
6836 Dom.addClass(me.element,"drag");
6839 if (me.cfg.getProperty("constraintoviewport")) {
6841 var nViewportOffset = Overlay.VIEWPORT_OFFSET;
6843 offsetHeight = me.element.offsetHeight;
6844 offsetWidth = me.element.offsetWidth;
6846 viewPortWidth = Dom.getViewportWidth();
6847 viewPortHeight = Dom.getViewportHeight();
6849 scrollX = Dom.getDocumentScrollLeft();
6850 scrollY = Dom.getDocumentScrollTop();
6852 if (offsetHeight + nViewportOffset < viewPortHeight) {
6853 this.minY = scrollY + nViewportOffset;
6854 this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
6856 this.minY = scrollY + nViewportOffset;
6857 this.maxY = scrollY + nViewportOffset;
6860 if (offsetWidth + nViewportOffset < viewPortWidth) {
6861 this.minX = scrollX + nViewportOffset;
6862 this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
6864 this.minX = scrollX + nViewportOffset;
6865 this.maxX = scrollX + nViewportOffset;
6868 this.constrainX = true;
6869 this.constrainY = true;
6871 this.constrainX = false;
6872 this.constrainY = false;
6875 me.dragEvent.fire("startDrag", arguments);
6878 this.dd.onDrag = function () {
6880 me.cfg.refireEvent("iframe");
6881 if (this.platform == "mac" && YAHOO.env.ua.gecko) {
6882 this.showMacGeckoScrollbars();
6885 me.dragEvent.fire("onDrag", arguments);
6888 this.dd.endDrag = function () {
6890 if (YAHOO.env.ua.ie == 6) {
6891 Dom.removeClass(me.element,"drag");
6894 me.dragEvent.fire("endDrag", arguments);
6895 me.moveEvent.fire(me.cfg.getProperty("xy"));
6899 this.dd.setHandleElId(this.header.id);
6900 this.dd.addInvalidHandleType("INPUT");
6901 this.dd.addInvalidHandleType("SELECT");
6902 this.dd.addInvalidHandleType("TEXTAREA");
6907 * Builds the mask that is laid over the document when the Panel is
6908 * configured to be modal.
6911 buildMask: function () {
6912 var oMask = this.mask;
6914 if (!m_oMaskTemplate) {
6915 m_oMaskTemplate = document.createElement("div");
6916 m_oMaskTemplate.className = "mask";
6917 m_oMaskTemplate.innerHTML = " ";
6919 oMask = m_oMaskTemplate.cloneNode(true);
6920 oMask.id = this.id + "_mask";
6922 document.body.insertBefore(oMask, document.body.firstChild);
6926 if (YAHOO.env.ua.gecko && this.platform == "mac") {
6927 Dom.addClass(this.mask, "block-scrollbars");
6930 // Stack mask based on the element zindex
6936 * Hides the modality mask.
6939 hideMask: function () {
6940 if (this.cfg.getProperty("modal") && this.mask) {
6941 this.mask.style.display = "none";
6942 Dom.removeClass(document.body, "masked");
6943 this.hideMaskEvent.fire();
6948 * Shows the modality mask.
6951 showMask: function () {
6952 if (this.cfg.getProperty("modal") && this.mask) {
6953 Dom.addClass(document.body, "masked");
6955 this.mask.style.display = "block";
6956 this.showMaskEvent.fire();
6961 * Sets the size of the modality mask to cover the entire scrollable
6962 * area of the document
6965 sizeMask: function () {
6968 // Shrink mask first, so it doesn't affect the document size.
6969 var mask = this.mask,
6970 viewWidth = Dom.getViewportWidth(),
6971 viewHeight = Dom.getViewportHeight();
6973 if (mask.offsetHeight > viewHeight) {
6974 mask.style.height = viewHeight + "px";
6977 if (mask.offsetWidth > viewWidth) {
6978 mask.style.width = viewWidth + "px";
6981 // Then size it to the document
6982 mask.style.height = Dom.getDocumentHeight() + "px";
6983 mask.style.width = Dom.getDocumentWidth() + "px";
6988 * Sets the zindex of the mask, if it exists, based on the zindex of
6989 * the Panel element. The zindex of the mask is set to be one less
6990 * than the Panel element's zindex.
6992 * <p>NOTE: This method will not bump up the zindex of the Panel
6993 * to ensure that the mask has a non-negative zindex. If you require the
6994 * mask zindex to be 0 or higher, the zindex of the Panel
6995 * should be set to a value higher than 0, before this method is called.
6999 stackMask: function() {
7001 var panelZ = Dom.getStyle(this.element, "zIndex");
7002 if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
7003 Dom.setStyle(this.mask, "zIndex", panelZ - 1);
7009 * Renders the Panel by inserting the elements that are not already in
7010 * the main Panel into their correct places. Optionally appends the
7011 * Panel to the specified node prior to the render's execution. NOTE:
7012 * For Panels without existing markup, the appendToNode argument is
7013 * REQUIRED. If this argument is ommitted and the current element is
7014 * not present in the document, the function will return false,
7015 * indicating that the render was a failure.
7017 * @param {String} appendToNode The element id to which the Module
7018 * should be appended to prior to rendering <em>OR</em>
7019 * @param {HTMLElement} appendToNode The element to which the Module
7020 * should be appended to prior to rendering
7021 * @return {boolean} Success or failure of the render
7023 render: function (appendToNode) {
7024 return Panel.superclass.render.call(this, appendToNode, this.innerElement);
7028 * Renders the currently set header into it's proper position under the
7029 * module element. If the module element is not provided, "this.innerElement"
7032 * @method _renderHeader
7034 * @param {HTMLElement} moduleElement Optional. A reference to the module element
7036 _renderHeader: function(moduleElement){
7037 moduleElement = moduleElement || this.innerElement;
7038 Panel.superclass._renderHeader.call(this, moduleElement);
7042 * Renders the currently set body into it's proper position under the
7043 * module element. If the module element is not provided, "this.innerElement"
7046 * @method _renderBody
7048 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
7050 _renderBody: function(moduleElement){
7051 moduleElement = moduleElement || this.innerElement;
7052 Panel.superclass._renderBody.call(this, moduleElement);
7056 * Renders the currently set footer into it's proper position under the
7057 * module element. If the module element is not provided, "this.innerElement"
7060 * @method _renderFooter
7062 * @param {HTMLElement} moduleElement Optional. A reference to the module element
7064 _renderFooter: function(moduleElement){
7065 moduleElement = moduleElement || this.innerElement;
7066 Panel.superclass._renderFooter.call(this, moduleElement);
7070 * Removes the Panel element from the DOM and sets all child elements
7074 destroy: function () {
7075 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
7078 Event.purgeElement(this.close);
7080 Panel.superclass.destroy.call(this);
7084 * Forces the underlay element to be repainted through the application/removal
7085 * of a yui-force-redraw class to the underlay element.
7087 * @method forceUnderlayRedraw
7089 forceUnderlayRedraw : function () {
7090 var u = this.underlay;
7091 Dom.addClass(u, "yui-force-redraw");
7092 setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
7096 * Returns a String representation of the object.
7098 * @return {String} The string representation of the Panel.
7100 toString: function () {
7101 return "Panel " + this.id;
7111 * Dialog is an implementation of Panel that can be used to submit form
7115 * Built-in functionality for buttons with event handlers is included.
7116 * If the optional YUI Button dependancy is included on the page, the buttons
7117 * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
7121 * Forms can be processed in 3 ways -- via an asynchronous Connection utility call,
7122 * a simple form POST or GET, or manually. The YUI Connection utility should be
7123 * included if you're using the default "async" postmethod, but is not required if
7124 * you're using any of the other postmethod values.
7126 * @namespace YAHOO.widget
7128 * @extends YAHOO.widget.Panel
7130 * @param {String} el The element ID representing the Dialog <em>OR</em>
7131 * @param {HTMLElement} el The element representing the Dialog
7132 * @param {Object} userConfig The configuration object literal containing
7133 * the configuration that should be set for this Dialog. See configuration
7134 * documentation for more details.
7136 YAHOO.widget.Dialog = function (el, userConfig) {
7137 YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
7140 var Event = YAHOO.util.Event,
7141 CustomEvent = YAHOO.util.CustomEvent,
7142 Dom = YAHOO.util.Dom,
7143 Dialog = YAHOO.widget.Dialog,
7147 * Constant representing the name of the Dialog's events
7148 * @property EVENT_TYPES
7154 "BEFORE_SUBMIT": "beforeSubmit",
7156 "MANUAL_SUBMIT": "manualSubmit",
7157 "ASYNC_SUBMIT": "asyncSubmit",
7158 "FORM_SUBMIT": "formSubmit",
7163 * Constant representing the Dialog's configuration properties
7164 * @property DEFAULT_CONFIG
7184 supercedes: ["visible"]
7187 "HIDEAFTERSUBMIT" : {
7188 key: "hideaftersubmit",
7195 * Constant representing the default CSS class used for a Dialog
7196 * @property YAHOO.widget.Dialog.CSS_DIALOG
7201 Dialog.CSS_DIALOG = "yui-dialog";
7203 function removeButtonEventHandlers() {
7205 var aButtons = this._aButtons,
7210 if (Lang.isArray(aButtons)) {
7211 nButtons = aButtons.length;
7216 oButton = aButtons[i];
7218 if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
7221 else if (oButton.tagName.toUpperCase() == "BUTTON") {
7222 Event.purgeElement(oButton);
7223 Event.purgeElement(oButton, false);
7231 YAHOO.extend(Dialog, YAHOO.widget.Panel, {
7235 * @description Object reference to the Dialog's
7236 * <code><form></code> element.
7238 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7239 * level-one-html.html#ID-40002357">HTMLFormElement</a>
7244 * Initializes the class's configurable properties which can be changed
7245 * using the Dialog's Config object (cfg).
7246 * @method initDefaultConfig
7248 initDefaultConfig: function () {
7249 Dialog.superclass.initDefaultConfig.call(this);
7252 * The internally maintained callback object for use with the
7253 * Connection utility. The format of the callback object is
7254 * similar to Connection Manager's callback object and is
7255 * simply passed through to Connection Manager when the async
7257 * @property callback
7263 * The function to execute upon success of the
7264 * Connection submission (when the form does not
7265 * contain a file input element).
7267 * @property callback.success
7273 * The function to execute upon failure of the
7274 * Connection submission
7275 * @property callback.failure
7282 * The function to execute upon success of the
7283 * Connection submission, when the form contains
7284 * a file input element.
7287 * <em>NOTE:</em> Connection manager will not
7288 * invoke the success or failure handlers for the file
7289 * upload use case. This will be the only callback
7293 * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
7294 * Connection Manager documenation on file uploads</a>.
7296 * @property callback.upload
7301 * The arbitraty argument or arguments to pass to the Connection
7302 * callback functions
7303 * @property callback.argument
7310 // Add form dialog config properties //
7312 * The method to use for posting the Dialog's form. Possible values
7313 * are "async", "form", and "manual".
7314 * @config postmethod
7318 this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
7319 handler: this.configPostMethod,
7320 value: DEFAULT_CONFIG.POST_METHOD.value,
7321 validator: function (val) {
7322 if (val != "form" && val != "async" && val != "none" &&
7332 * Any additional post data which needs to be sent when using the
7333 * <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
7334 * The format for the post data string is defined by Connection Manager's
7335 * <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a>
7341 this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
7342 value: DEFAULT_CONFIG.POST_DATA.value
7346 * This property is used to configure whether or not the
7347 * dialog should be automatically hidden after submit.
7349 * @config hideaftersubmit
7353 this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
7354 value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
7358 * Array of object literals, each containing a set of properties
7359 * defining a button to be appended into the Dialog's footer.
7361 * <p>Each button object in the buttons array can have three properties:</p>
7365 * The text that will display on the face of the button. The text can
7366 * include HTML, as long as it is compliant with HTML Button specifications.
7369 * <dd>Can be either:
7371 * <li>A reference to a function that should fire when the
7372 * button is clicked. (In this case scope of this function is
7373 * always its Dialog instance.)</li>
7375 * <li>An object literal representing the code to be
7376 * executed when the button is clicked.
7383 * <strong>fn:</strong> Function, //
7384 * The handler to call when the event fires.
7386 * <strong>obj:</strong> Object, //
7387 * An object to pass back to the handler.
7389 * <strong>scope:</strong> Object //
7390 * The object to use for the scope of the handler.
7397 * <dt>isDefault:</dt>
7399 * An optional boolean value that specifies that a button
7400 * should be highlighted and focused by default.
7404 * <em>NOTE:</em>If the YUI Button Widget is included on the page,
7405 * the buttons created will be instances of YAHOO.widget.Button.
7406 * Otherwise, HTML Buttons (<code><BUTTON></code>) will be
7410 * @type {Array|String}
7413 this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
7414 handler: this.configButtons,
7415 value: DEFAULT_CONFIG.BUTTONS.value,
7416 supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
7422 * Initializes the custom events for Dialog which are fired
7423 * automatically at appropriate times by the Dialog class.
7424 * @method initEvents
7426 initEvents: function () {
7427 Dialog.superclass.initEvents.call(this);
7429 var SIGNATURE = CustomEvent.LIST;
7432 * CustomEvent fired prior to submission
7433 * @event beforeSubmitEvent
7435 this.beforeSubmitEvent =
7436 this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
7437 this.beforeSubmitEvent.signature = SIGNATURE;
7440 * CustomEvent fired after submission
7441 * @event submitEvent
7443 this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
7444 this.submitEvent.signature = SIGNATURE;
7447 * CustomEvent fired for manual submission, before the generic submit event is fired
7448 * @event manualSubmitEvent
7450 this.manualSubmitEvent =
7451 this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
7452 this.manualSubmitEvent.signature = SIGNATURE;
7455 * CustomEvent fired after asynchronous submission, before the generic submit event is fired
7457 * @event asyncSubmitEvent
7458 * @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
7460 this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
7461 this.asyncSubmitEvent.signature = SIGNATURE;
7464 * CustomEvent fired after form-based submission, before the generic submit event is fired
7465 * @event formSubmitEvent
7467 this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
7468 this.formSubmitEvent.signature = SIGNATURE;
7471 * CustomEvent fired after cancel
7472 * @event cancelEvent
7474 this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
7475 this.cancelEvent.signature = SIGNATURE;
7480 * The Dialog initialization method, which is executed for Dialog and
7481 * all of its subclasses. This method is automatically called by the
7482 * constructor, and sets up all DOM references for pre-existing markup,
7483 * and creates required markup if it is not already present.
7486 * @param {String} el The element ID representing the Dialog <em>OR</em>
7487 * @param {HTMLElement} el The element representing the Dialog
7488 * @param {Object} userConfig The configuration object literal
7489 * containing the configuration that should be set for this Dialog.
7490 * See configuration documentation for more details.
7492 init: function (el, userConfig) {
7495 Note that we don't pass the user config in here yet because
7496 we only want it executed once, at the lowest subclass level
7499 Dialog.superclass.init.call(this, el/*, userConfig*/);
7501 this.beforeInitEvent.fire(Dialog);
7503 Dom.addClass(this.element, Dialog.CSS_DIALOG);
7505 this.cfg.setProperty("visible", false);
7508 this.cfg.applyConfig(userConfig, true);
7511 this.showEvent.subscribe(this.focusFirst, this, true);
7512 this.beforeHideEvent.subscribe(this.blurButtons, this, true);
7514 this.subscribe("changeBody", this.registerForm);
7516 this.initEvent.fire(Dialog);
7520 * Submits the Dialog's form depending on the value of the
7521 * "postmethod" configuration property. <strong>Please note:
7522 * </strong> As of version 2.3 this method will automatically handle
7523 * asyncronous file uploads should the Dialog instance's form contain
7524 * <code><input type="file"></code> elements. If a Dialog
7525 * instance will be handling asyncronous file uploads, its
7526 * <code>callback</code> property will need to be setup with a
7527 * <code>upload</code> handler rather than the standard
7528 * <code>success</code> and, or <code>failure</code> handlers. For more
7529 * information, see the <a href="http://developer.yahoo.com/yui/
7530 * connection/#file">Connection Manager documenation on file uploads</a>.
7533 doSubmit: function () {
7535 var Connect = YAHOO.util.Connect,
7537 bUseFileUpload = false,
7538 bUseSecureFileUpload = false,
7544 switch (this.cfg.getProperty("postmethod")) {
7547 aElements = oForm.elements;
7548 nElements = aElements.length;
7550 if (nElements > 0) {
7553 if (aElements[i].type == "file") {
7554 bUseFileUpload = true;
7561 if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
7562 bUseSecureFileUpload = true;
7565 formAttrs = this._getFormAttributes(oForm);
7567 Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
7569 var postData = this.cfg.getProperty("postdata");
7570 var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
7572 this.asyncSubmitEvent.fire(c);
7578 this.formSubmitEvent.fire();
7583 this.manualSubmitEvent.fire();
7589 * Retrieves important attributes (currently method and action) from
7590 * the form element, accounting for any elements which may have the same name
7591 * as the attributes. Defaults to "POST" and "" for method and action respectively
7592 * if the attribute cannot be retrieved.
7594 * @method _getFormAttributes
7596 * @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
7597 * @return {Object} Object literal, with method and action String properties.
7599 _getFormAttributes : function(oForm){
7606 if (oForm.getAttributeNode) {
7607 var action = oForm.getAttributeNode("action");
7608 var method = oForm.getAttributeNode("method");
7611 attrs.action = action.value;
7615 attrs.method = method.value;
7619 attrs.action = oForm.getAttribute("action");
7620 attrs.method = oForm.getAttribute("method");
7624 attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
7625 attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
7631 * Prepares the Dialog's internal FORM object, creating one if one is
7632 * not currently present.
7633 * @method registerForm
7635 registerForm: function() {
7637 var form = this.element.getElementsByTagName("form")[0];
7640 if (this.form == form && Dom.isAncestor(this.element, this.form)) {
7643 Event.purgeElement(this.form);
7649 form = document.createElement("form");
7650 form.name = "frm_" + this.id;
7651 this.body.appendChild(form);
7656 Event.on(form, "submit", this._submitHandler, this, true);
7661 * Internal handler for the form submit event
7663 * @method _submitHandler
7665 * @param {DOMEvent} e The DOM Event object
7667 _submitHandler : function(e) {
7674 * Sets up a tab, shift-tab loop between the first and last elements
7675 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
7676 * instance properties, which are reset everytime this method is invoked.
7678 * @method setTabLoop
7679 * @param {HTMLElement} firstElement
7680 * @param {HTMLElement} lastElement
7683 setTabLoop : function(firstElement, lastElement) {
7685 firstElement = firstElement || this.firstButton;
7686 lastElement = this.lastButton || lastElement;
7688 Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
7692 * Configures instance properties, pointing to the
7693 * first and last focusable elements in the Dialog's form.
7695 * @method setFirstLastFocusable
7697 setFirstLastFocusable : function() {
7699 Dialog.superclass.setFirstLastFocusable.call(this);
7701 var i, l, el, elements = this.focusableElements;
7703 this.firstFormElement = null;
7704 this.lastFormElement = null;
7706 if (this.form && elements && elements.length > 0) {
7707 l = elements.length;
7709 for (i = 0; i < l; ++i) {
7711 if (this.form === el.form) {
7712 this.firstFormElement = el;
7717 for (i = l-1; i >= 0; --i) {
7719 if (this.form === el.form) {
7720 this.lastFormElement = el;
7727 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7729 * The default event handler fired when the "close" property is
7730 * changed. The method controls the appending or hiding of the close
7731 * icon at the top right of the Dialog.
7732 * @method configClose
7733 * @param {String} type The CustomEvent type (usually the property name)
7734 * @param {Object[]} args The CustomEvent arguments. For
7735 * configuration handlers, args[0] will equal the newly applied value
7737 * @param {Object} obj The scope object. For configuration handlers,
7738 * this will usually equal the owner.
7740 configClose: function (type, args, obj) {
7741 Dialog.superclass.configClose.apply(this, arguments);
7745 * Event handler for the close icon
7750 * @param {DOMEvent} e
7752 _doClose : function(e) {
7753 Event.preventDefault(e);
7758 * The default event handler for the "buttons" configuration property
7759 * @method configButtons
7760 * @param {String} type The CustomEvent type (usually the property name)
7761 * @param {Object[]} args The CustomEvent arguments. For configuration
7762 * handlers, args[0] will equal the newly applied value for the property.
7763 * @param {Object} obj The scope object. For configuration handlers,
7764 * this will usually equal the owner.
7766 configButtons: function (type, args, obj) {
7768 var Button = YAHOO.widget.Button,
7770 oInnerElement = this.innerElement,
7779 removeButtonEventHandlers.call(this);
7781 this._aButtons = null;
7783 if (Lang.isArray(aButtons)) {
7785 oSpan = document.createElement("span");
7786 oSpan.className = "button-group";
7787 nButtons = aButtons.length;
7789 this._aButtons = [];
7790 this.defaultHtmlButton = null;
7792 for (i = 0; i < nButtons; i++) {
7793 oButton = aButtons[i];
7796 oYUIButton = new Button({ label: oButton.text});
7797 oYUIButton.appendTo(oSpan);
7799 oButtonEl = oYUIButton.get("element");
7801 if (oButton.isDefault) {
7802 oYUIButton.addClass("default");
7803 this.defaultHtmlButton = oButtonEl;
7806 if (Lang.isFunction(oButton.handler)) {
7808 oYUIButton.set("onclick", {
7809 fn: oButton.handler,
7814 } else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
7816 oYUIButton.set("onclick", {
7817 fn: oButton.handler.fn,
7818 obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7819 scope: (oButton.handler.scope || this)
7824 this._aButtons[this._aButtons.length] = oYUIButton;
7828 oButtonEl = document.createElement("button");
7829 oButtonEl.setAttribute("type", "button");
7831 if (oButton.isDefault) {
7832 oButtonEl.className = "default";
7833 this.defaultHtmlButton = oButtonEl;
7836 oButtonEl.innerHTML = oButton.text;
7838 if (Lang.isFunction(oButton.handler)) {
7839 Event.on(oButtonEl, "click", oButton.handler, this, true);
7840 } else if (Lang.isObject(oButton.handler) &&
7841 Lang.isFunction(oButton.handler.fn)) {
7843 Event.on(oButtonEl, "click",
7845 ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7846 (oButton.handler.scope || this));
7849 oSpan.appendChild(oButtonEl);
7850 this._aButtons[this._aButtons.length] = oButtonEl;
7853 oButton.htmlButton = oButtonEl;
7856 this.firstButton = oButtonEl;
7859 if (i == (nButtons - 1)) {
7860 this.lastButton = oButtonEl;
7864 this.setFooter(oSpan);
7866 oFooter = this.footer;
7868 if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
7869 oInnerElement.appendChild(oFooter);
7872 this.buttonSpan = oSpan;
7874 } else { // Do cleanup
7875 oSpan = this.buttonSpan;
7876 oFooter = this.footer;
7877 if (oSpan && oFooter) {
7878 oFooter.removeChild(oSpan);
7879 this.buttonSpan = null;
7880 this.firstButton = null;
7881 this.lastButton = null;
7882 this.defaultHtmlButton = null;
7886 this.changeContentEvent.fire();
7890 * @method getButtons
7891 * @description Returns an array containing each of the Dialog's
7892 * buttons, by default an array of HTML <code><BUTTON></code>
7893 * elements. If the Dialog's buttons were created using the
7894 * YAHOO.widget.Button class (via the inclusion of the optional Button
7895 * dependancy on the page), an array of YAHOO.widget.Button instances
7899 getButtons: function () {
7900 return this._aButtons || null;
7905 * Sets focus to the first focusable element in the Dialog's form if found,
7906 * else, the default button if found, else the first button defined via the
7907 * "buttons" configuration property.
7910 * This method is invoked when the Dialog is made visible.
7912 * @method focusFirst
7914 focusFirst: function (type, args, obj) {
7916 var el = this.firstFormElement;
7918 if (args && args[1]) {
7919 Event.stopEvent(args[1]);
7925 } catch(oException) {
7929 if (this.defaultHtmlButton) {
7930 this.focusDefaultButton();
7932 this.focusFirstButton();
7938 * Sets focus to the last element in the Dialog's form or the last
7939 * button defined via the "buttons" configuration property.
7942 focusLast: function (type, args, obj) {
7944 var aButtons = this.cfg.getProperty("buttons"),
7945 el = this.lastFormElement;
7947 if (args && args[1]) {
7948 Event.stopEvent(args[1]);
7951 if (aButtons && Lang.isArray(aButtons)) {
7952 this.focusLastButton();
7957 } catch(oException) {
7965 * Helper method to normalize button references. It either returns the
7966 * YUI Button instance for the given element if found,
7967 * or the passes back the HTMLElement reference if a corresponding YUI Button
7968 * reference is not found or YAHOO.widget.Button does not exist on the page.
7970 * @method _getButton
7972 * @param {HTMLElement} button
7973 * @return {YAHOO.widget.Button|HTMLElement}
7975 _getButton : function(button) {
7976 var Button = YAHOO.widget.Button;
7978 // If we have an HTML button and YUI Button is on the page,
7979 // get the YUI Button reference if available.
7980 if (Button && button && button.nodeName && button.id) {
7981 button = Button.getButton(button.id) || button;
7988 * Sets the focus to the button that is designated as the default via
7989 * the "buttons" configuration property. By default, this method is
7990 * called when the Dialog is made visible.
7991 * @method focusDefaultButton
7993 focusDefaultButton: function () {
7994 var button = this._getButton(this.defaultHtmlButton);
7997 Place the call to the "focus" method inside a try/catch
7998 block to prevent IE from throwing JavaScript errors if
7999 the element is disabled or hidden.
8003 } catch(oException) {
8009 * Blurs all the buttons defined via the "buttons"
8010 * configuration property.
8011 * @method blurButtons
8013 blurButtons: function () {
8015 var aButtons = this.cfg.getProperty("buttons"),
8021 if (aButtons && Lang.isArray(aButtons)) {
8022 nButtons = aButtons.length;
8026 oButton = aButtons[i];
8028 oElement = this._getButton(oButton.htmlButton);
8031 Place the call to the "blur" method inside
8032 a try/catch block to prevent IE from
8033 throwing JavaScript errors if the element
8034 is disabled or hidden.
8038 } catch(oException) {
8049 * Sets the focus to the first button created via the "buttons"
8050 * configuration property.
8051 * @method focusFirstButton
8053 focusFirstButton: function () {
8055 var aButtons = this.cfg.getProperty("buttons"),
8059 if (aButtons && Lang.isArray(aButtons)) {
8060 oButton = aButtons[0];
8062 oElement = this._getButton(oButton.htmlButton);
8065 Place the call to the "focus" method inside a
8066 try/catch block to prevent IE from throwing
8067 JavaScript errors if the element is disabled
8072 } catch(oException) {
8081 * Sets the focus to the last button created via the "buttons"
8082 * configuration property.
8083 * @method focusLastButton
8085 focusLastButton: function () {
8087 var aButtons = this.cfg.getProperty("buttons"),
8092 if (aButtons && Lang.isArray(aButtons)) {
8093 nButtons = aButtons.length;
8095 oButton = aButtons[(nButtons - 1)];
8098 oElement = this._getButton(oButton.htmlButton);
8101 Place the call to the "focus" method inside a
8102 try/catch block to prevent IE from throwing
8103 JavaScript errors if the element is disabled
8109 } catch(oException) {
8119 * The default event handler for the "postmethod" configuration property
8120 * @method configPostMethod
8121 * @param {String} type The CustomEvent type (usually the property name)
8122 * @param {Object[]} args The CustomEvent arguments. For
8123 * configuration handlers, args[0] will equal the newly applied value
8125 * @param {Object} obj The scope object. For configuration handlers,
8126 * this will usually equal the owner.
8128 configPostMethod: function (type, args, obj) {
8129 this.registerForm();
8132 // END BUILT-IN PROPERTY EVENT HANDLERS //
8135 * Built-in function hook for writing a validation function that will
8136 * be checked for a "true" value prior to a submit. This function, as
8137 * implemented by default, always returns true, so it should be
8138 * overridden if validation is necessary.
8141 validate: function () {
8146 * Executes a submit of the Dialog if validation
8147 * is successful. By default the Dialog is hidden
8148 * after submission, but you can set the "hideaftersubmit"
8149 * configuration property to false, to prevent the Dialog
8150 * from being hidden.
8154 submit: function () {
8155 if (this.validate()) {
8156 if (this.beforeSubmitEvent.fire()) {
8158 this.submitEvent.fire();
8160 if (this.cfg.getProperty("hideaftersubmit")) {
8174 * Executes the cancel of the Dialog followed by a hide.
8177 cancel: function () {
8178 this.cancelEvent.fire();
8183 * Returns a JSON-compatible data structure representing the data
8184 * currently contained in the form.
8186 * @return {Object} A JSON object reprsenting the data of the
8189 getData: function () {
8191 var oForm = this.form,
8210 function isFormElement(p_oElement) {
8211 var sTag = p_oElement.tagName.toUpperCase();
8212 return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
8213 sTag == "SELECT") && p_oElement.name == sName);
8218 aElements = oForm.elements;
8219 nTotalElements = aElements.length;
8222 for (i = 0; i < nTotalElements; i++) {
8223 sName = aElements[i].name;
8226 Using "Dom.getElementsBy" to safeguard user from JS
8227 errors that result from giving a form field (or set of
8228 fields) the same name as a native method of a form
8229 (like "submit") or a DOM collection (such as the "item"
8230 method). Originally tried accessing fields via the
8231 "namedItem" method of the "element" collection, but
8232 discovered that it won't return a collection of fields
8236 oElement = Dom.getElementsBy(isFormElement, "*", oForm);
8237 nElements = oElement.length;
8239 if (nElements > 0) {
8240 if (nElements == 1) {
8241 oElement = oElement[0];
8243 sType = oElement.type;
8244 sTagName = oElement.tagName.toUpperCase();
8248 if (sType == "checkbox") {
8249 oData[sName] = oElement.checked;
8250 } else if (sType != "radio") {
8251 oData[sName] = oElement.value;
8256 oData[sName] = oElement.value;
8260 aOptions = oElement.options;
8261 nOptions = aOptions.length;
8264 for (n = 0; n < nOptions; n++) {
8265 oOption = aOptions[n];
8266 if (oOption.selected) {
8267 valueAttr = oOption.attributes.value;
8268 aValues[aValues.length] = (valueAttr && valueAttr.specified) ? oOption.value : oOption.text;
8271 oData[sName] = aValues;
8276 sType = oElement[0].type;
8279 for (n = 0; n < nElements; n++) {
8280 oRadio = oElement[n];
8281 if (oRadio.checked) {
8282 oData[sName] = oRadio.value;
8290 for (n = 0; n < nElements; n++) {
8291 oCheckbox = oElement[n];
8292 if (oCheckbox.checked) {
8293 aValues[aValues.length] = oCheckbox.value;
8296 oData[sName] = aValues;
8308 * Removes the Panel element from the DOM and sets all child elements
8312 destroy: function () {
8313 removeButtonEventHandlers.call(this);
8315 this._aButtons = null;
8317 var aForms = this.element.getElementsByTagName("form"),
8320 if (aForms.length > 0) {
8324 Event.purgeElement(oForm);
8325 if (oForm.parentNode) {
8326 oForm.parentNode.removeChild(oForm);
8331 Dialog.superclass.destroy.call(this);
8335 * Returns a string representation of the object.
8337 * @return {String} The string representation of the Dialog
8339 toString: function () {
8340 return "Dialog " + this.id;
8349 * SimpleDialog is a simple implementation of Dialog that can be used to
8350 * submit a single value. Forms can be processed in 3 ways -- via an
8351 * asynchronous Connection utility call, a simple form POST or GET,
8353 * @namespace YAHOO.widget
8354 * @class SimpleDialog
8355 * @extends YAHOO.widget.Dialog
8357 * @param {String} el The element ID representing the SimpleDialog
8359 * @param {HTMLElement} el The element representing the SimpleDialog
8360 * @param {Object} userConfig The configuration object literal containing
8361 * the configuration that should be set for this SimpleDialog. See
8362 * configuration documentation for more details.
8364 YAHOO.widget.SimpleDialog = function (el, userConfig) {
8366 YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
8371 var Dom = YAHOO.util.Dom,
8372 SimpleDialog = YAHOO.widget.SimpleDialog,
8375 * Constant representing the SimpleDialog's configuration properties
8376 * @property DEFAULT_CONFIG
8392 suppressEvent: true,
8393 supercedes: ["icon"]
8399 * Constant for the standard network icon for a blocking action
8400 * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
8405 SimpleDialog.ICON_BLOCK = "blckicon";
8408 * Constant for the standard network icon for alarm
8409 * @property YAHOO.widget.SimpleDialog.ICON_ALARM
8414 SimpleDialog.ICON_ALARM = "alrticon";
8417 * Constant for the standard network icon for help
8418 * @property YAHOO.widget.SimpleDialog.ICON_HELP
8423 SimpleDialog.ICON_HELP = "hlpicon";
8426 * Constant for the standard network icon for info
8427 * @property YAHOO.widget.SimpleDialog.ICON_INFO
8432 SimpleDialog.ICON_INFO = "infoicon";
8435 * Constant for the standard network icon for warn
8436 * @property YAHOO.widget.SimpleDialog.ICON_WARN
8441 SimpleDialog.ICON_WARN = "warnicon";
8444 * Constant for the standard network icon for a tip
8445 * @property YAHOO.widget.SimpleDialog.ICON_TIP
8450 SimpleDialog.ICON_TIP = "tipicon";
8453 * Constant representing the name of the CSS class applied to the element
8454 * created by the "icon" configuration property.
8455 * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
8460 SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
8463 * Constant representing the default CSS class used for a SimpleDialog
8464 * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
8469 SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
8472 YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
8475 * Initializes the class's configurable properties which can be changed
8476 * using the SimpleDialog's Config object (cfg).
8477 * @method initDefaultConfig
8479 initDefaultConfig: function () {
8481 SimpleDialog.superclass.initDefaultConfig.call(this);
8483 // Add dialog config properties //
8486 * Sets the informational icon for the SimpleDialog
8491 this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
8492 handler: this.configIcon,
8493 value: DEFAULT_CONFIG.ICON.value,
8494 suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
8498 * Sets the text for the SimpleDialog
8503 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
8504 handler: this.configText,
8505 value: DEFAULT_CONFIG.TEXT.value,
8506 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
8507 supercedes: DEFAULT_CONFIG.TEXT.supercedes
8514 * The SimpleDialog initialization method, which is executed for
8515 * SimpleDialog and all of its subclasses. This method is automatically
8516 * called by the constructor, and sets up all DOM references for
8517 * pre-existing markup, and creates required markup if it is not
8520 * @param {String} el The element ID representing the SimpleDialog
8522 * @param {HTMLElement} el The element representing the SimpleDialog
8523 * @param {Object} userConfig The configuration object literal
8524 * containing the configuration that should be set for this
8525 * SimpleDialog. See configuration documentation for more details.
8527 init: function (el, userConfig) {
8530 Note that we don't pass the user config in here yet because we
8531 only want it executed once, at the lowest subclass level
8534 SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
8536 this.beforeInitEvent.fire(SimpleDialog);
8538 Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
8540 this.cfg.queueProperty("postmethod", "manual");
8543 this.cfg.applyConfig(userConfig, true);
8546 this.beforeRenderEvent.subscribe(function () {
8552 this.initEvent.fire(SimpleDialog);
8557 * Prepares the SimpleDialog's internal FORM object, creating one if one
8558 * is not currently present, and adding the value hidden field.
8559 * @method registerForm
8561 registerForm: function () {
8563 SimpleDialog.superclass.registerForm.call(this);
8565 this.form.innerHTML += "<input type=\"hidden\" name=\"" +
8566 this.id + "\" value=\"\"/>";
8570 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
8573 * Fired when the "icon" property is set.
8574 * @method configIcon
8575 * @param {String} type The CustomEvent type (usually the property name)
8576 * @param {Object[]} args The CustomEvent arguments. For configuration
8577 * handlers, args[0] will equal the newly applied value for the property.
8578 * @param {Object} obj The scope object. For configuration handlers,
8579 * this will usually equal the owner.
8581 configIcon: function (type,args,obj) {
8583 var sIcon = args[0],
8585 sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
8590 if (sIcon && sIcon != "none") {
8592 aElements = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
8594 if (aElements.length === 1) {
8596 oIcon = aElements[0];
8597 oIconParent = oIcon.parentNode;
8601 oIconParent.removeChild(oIcon);
8610 if (sIcon.indexOf(".") == -1) {
8612 oIcon = document.createElement("span");
8613 oIcon.className = (sCSSClass + " " + sIcon);
8614 oIcon.innerHTML = " ";
8618 oIcon = document.createElement("img");
8619 oIcon.src = (this.imageRoot + sIcon);
8620 oIcon.className = sCSSClass;
8627 oBody.insertBefore(oIcon, oBody.firstChild);
8636 * Fired when the "text" property is set.
8637 * @method configText
8638 * @param {String} type The CustomEvent type (usually the property name)
8639 * @param {Object[]} args The CustomEvent arguments. For configuration
8640 * handlers, args[0] will equal the newly applied value for the property.
8641 * @param {Object} obj The scope object. For configuration handlers,
8642 * this will usually equal the owner.
8644 configText: function (type,args,obj) {
8648 this.cfg.refireEvent("icon");
8652 // END BUILT-IN PROPERTY EVENT HANDLERS //
8655 * Returns a string representation of the object.
8657 * @return {String} The string representation of the SimpleDialog
8659 toString: function () {
8660 return "SimpleDialog " + this.id;
8665 * Sets the SimpleDialog's body content to the HTML specified.
8666 * If no body is present, one will be automatically created.
8667 * An empty string can be passed to the method to clear the contents of the body.
8669 * <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
8670 * and <a href="#config_icon">icon</a> configuration properties to set the contents
8671 * of it's body element in accordance with the UI design for a SimpleDialog (an
8672 * icon and message text). Calling setBody on the SimpleDialog will not enforce this
8673 * UI design constraint and will replace the entire contents of the SimpleDialog body.
8674 * It should only be used if you wish the replace the default icon/text body structure
8675 * of a SimpleDialog with your own custom markup.</p>
8678 * @param {String} bodyContent The HTML used to set the body.
8679 * As a convenience, non HTMLElement objects can also be passed into
8680 * the method, and will be treated as strings, with the body innerHTML
8681 * set to their default toString implementations.
8683 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
8685 * @param {DocumentFragment} bodyContent The document fragment
8686 * containing elements which are to be added to the body
8694 * ContainerEffect encapsulates animation transitions that are executed when
8695 * an Overlay is shown or hidden.
8696 * @namespace YAHOO.widget
8697 * @class ContainerEffect
8699 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
8700 * should be associated with
8701 * @param {Object} attrIn The object literal representing the animation
8702 * arguments to be used for the animate-in transition. The arguments for
8703 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8704 * duration(Number), and method(i.e. Easing.easeIn).
8705 * @param {Object} attrOut The object literal representing the animation
8706 * arguments to be used for the animate-out transition. The arguments for
8707 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8708 * duration(Number), and method(i.e. Easing.easeIn).
8709 * @param {HTMLElement} targetElement Optional. The target element that
8710 * should be animated during the transition. Defaults to overlay.element.
8711 * @param {class} Optional. The animation class to instantiate. Defaults to
8712 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
8714 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
8717 animClass = YAHOO.util.Anim;
8721 * The overlay to animate
8723 * @type YAHOO.widget.Overlay
8725 this.overlay = overlay;
8728 * The animation attributes to use when transitioning into view
8732 this.attrIn = attrIn;
8735 * The animation attributes to use when transitioning out of view
8739 this.attrOut = attrOut;
8742 * The target element to be animated
8743 * @property targetElement
8746 this.targetElement = targetElement || overlay.element;
8749 * The animation class to use for animating the overlay
8750 * @property animClass
8753 this.animClass = animClass;
8758 var Dom = YAHOO.util.Dom,
8759 CustomEvent = YAHOO.util.CustomEvent,
8760 ContainerEffect = YAHOO.widget.ContainerEffect;
8764 * A pre-configured ContainerEffect instance that can be used for fading
8765 * an overlay in and out.
8768 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8769 * @param {Number} dur The duration of the animation
8770 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8772 ContainerEffect.FADE = function (overlay, dur) {
8774 var Easing = YAHOO.util.Easing,
8776 attributes: {opacity:{from:0, to:1}},
8778 method: Easing.easeIn
8781 attributes: {opacity:{to:0}},
8783 method: Easing.easeOut
8785 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
8787 fade.handleUnderlayStart = function() {
8788 var underlay = this.overlay.underlay;
8789 if (underlay && YAHOO.env.ua.ie) {
8790 var hasFilters = (underlay.filters && underlay.filters.length > 0);
8792 Dom.addClass(overlay.element, "yui-effect-fade");
8797 fade.handleUnderlayComplete = function() {
8798 var underlay = this.overlay.underlay;
8799 if (underlay && YAHOO.env.ua.ie) {
8800 Dom.removeClass(overlay.element, "yui-effect-fade");
8804 fade.handleStartAnimateIn = function (type, args, obj) {
8805 Dom.addClass(obj.overlay.element, "hide-select");
8807 if (!obj.overlay.underlay) {
8808 obj.overlay.cfg.refireEvent("underlay");
8811 obj.handleUnderlayStart();
8813 obj.overlay._setDomVisibility(true);
8814 Dom.setStyle(obj.overlay.element, "opacity", 0);
8817 fade.handleCompleteAnimateIn = function (type,args,obj) {
8818 Dom.removeClass(obj.overlay.element, "hide-select");
8820 if (obj.overlay.element.style.filter) {
8821 obj.overlay.element.style.filter = null;
8824 obj.handleUnderlayComplete();
8826 obj.overlay.cfg.refireEvent("iframe");
8827 obj.animateInCompleteEvent.fire();
8830 fade.handleStartAnimateOut = function (type, args, obj) {
8831 Dom.addClass(obj.overlay.element, "hide-select");
8832 obj.handleUnderlayStart();
8835 fade.handleCompleteAnimateOut = function (type, args, obj) {
8836 Dom.removeClass(obj.overlay.element, "hide-select");
8837 if (obj.overlay.element.style.filter) {
8838 obj.overlay.element.style.filter = null;
8840 obj.overlay._setDomVisibility(false);
8841 Dom.setStyle(obj.overlay.element, "opacity", 1);
8843 obj.handleUnderlayComplete();
8845 obj.overlay.cfg.refireEvent("iframe");
8846 obj.animateOutCompleteEvent.fire();
8855 * A pre-configured ContainerEffect instance that can be used for sliding an
8856 * overlay in and out.
8859 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8860 * @param {Number} dur The duration of the animation
8861 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8863 ContainerEffect.SLIDE = function (overlay, dur) {
8864 var Easing = YAHOO.util.Easing,
8866 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
8867 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
8868 clientWidth = Dom.getClientWidth(),
8869 offsetWidth = overlay.element.offsetWidth,
8872 attributes: { points: { to: [x, y] } },
8874 method: Easing.easeIn
8878 attributes: { points: { to: [(clientWidth + 25), y] } },
8880 method: Easing.easeOut
8883 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
8885 slide.handleStartAnimateIn = function (type,args,obj) {
8886 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
8887 obj.overlay.element.style.top = y + "px";
8890 slide.handleTweenAnimateIn = function (type, args, obj) {
8892 var pos = Dom.getXY(obj.overlay.element),
8896 if (Dom.getStyle(obj.overlay.element, "visibility") ==
8897 "hidden" && currentX < x) {
8899 obj.overlay._setDomVisibility(true);
8903 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
8904 obj.overlay.cfg.refireEvent("iframe");
8907 slide.handleCompleteAnimateIn = function (type, args, obj) {
8908 obj.overlay.cfg.setProperty("xy", [x, y], true);
8911 obj.overlay.cfg.refireEvent("iframe");
8912 obj.animateInCompleteEvent.fire();
8915 slide.handleStartAnimateOut = function (type, args, obj) {
8917 var vw = Dom.getViewportWidth(),
8918 pos = Dom.getXY(obj.overlay.element),
8921 obj.animOut.attributes.points.to = [(vw + 25), yso];
8924 slide.handleTweenAnimateOut = function (type, args, obj) {
8926 var pos = Dom.getXY(obj.overlay.element),
8930 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
8931 obj.overlay.cfg.refireEvent("iframe");
8934 slide.handleCompleteAnimateOut = function (type, args, obj) {
8935 obj.overlay._setDomVisibility(false);
8937 obj.overlay.cfg.setProperty("xy", [x, y]);
8938 obj.animateOutCompleteEvent.fire();
8945 ContainerEffect.prototype = {
8948 * Initializes the animation classes and events.
8953 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
8954 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
8956 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
8957 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
8959 this.animateInCompleteEvent = this.createEvent("animateInComplete");
8960 this.animateInCompleteEvent.signature = CustomEvent.LIST;
8962 this.animateOutCompleteEvent =
8963 this.createEvent("animateOutComplete");
8964 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
8966 this.animIn = new this.animClass(this.targetElement,
8967 this.attrIn.attributes, this.attrIn.duration,
8968 this.attrIn.method);
8970 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
8971 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
8973 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
8976 this.animOut = new this.animClass(this.targetElement,
8977 this.attrOut.attributes, this.attrOut.duration,
8978 this.attrOut.method);
8980 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
8981 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
8982 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
8988 * Triggers the in-animation.
8991 animateIn: function () {
8992 this.beforeAnimateInEvent.fire();
8993 this.animIn.animate();
8997 * Triggers the out-animation.
8998 * @method animateOut
9000 animateOut: function () {
9001 this.beforeAnimateOutEvent.fire();
9002 this.animOut.animate();
9006 * The default onStart handler for the in-animation.
9007 * @method handleStartAnimateIn
9008 * @param {String} type The CustomEvent type
9009 * @param {Object[]} args The CustomEvent arguments
9010 * @param {Object} obj The scope object
9012 handleStartAnimateIn: function (type, args, obj) { },
9015 * The default onTween handler for the in-animation.
9016 * @method handleTweenAnimateIn
9017 * @param {String} type The CustomEvent type
9018 * @param {Object[]} args The CustomEvent arguments
9019 * @param {Object} obj The scope object
9021 handleTweenAnimateIn: function (type, args, obj) { },
9024 * The default onComplete handler for the in-animation.
9025 * @method handleCompleteAnimateIn
9026 * @param {String} type The CustomEvent type
9027 * @param {Object[]} args The CustomEvent arguments
9028 * @param {Object} obj The scope object
9030 handleCompleteAnimateIn: function (type, args, obj) { },
9033 * The default onStart handler for the out-animation.
9034 * @method handleStartAnimateOut
9035 * @param {String} type The CustomEvent type
9036 * @param {Object[]} args The CustomEvent arguments
9037 * @param {Object} obj The scope object
9039 handleStartAnimateOut: function (type, args, obj) { },
9042 * The default onTween handler for the out-animation.
9043 * @method handleTweenAnimateOut
9044 * @param {String} type The CustomEvent type
9045 * @param {Object[]} args The CustomEvent arguments
9046 * @param {Object} obj The scope object
9048 handleTweenAnimateOut: function (type, args, obj) { },
9051 * The default onComplete handler for the out-animation.
9052 * @method handleCompleteAnimateOut
9053 * @param {String} type The CustomEvent type
9054 * @param {Object[]} args The CustomEvent arguments
9055 * @param {Object} obj The scope object
9057 handleCompleteAnimateOut: function (type, args, obj) { },
9060 * Returns a string representation of the object.
9062 * @return {String} The string representation of the ContainerEffect
9064 toString: function () {
9065 var output = "ContainerEffect";
9067 output += " [" + this.overlay.toString() + "]";
9073 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
9076 YAHOO.register("container", YAHOO.widget.Module, {version: "2.8.0r4", build: "2449"});