2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
10 * Config is a utility used within an Object to allow the implementer to
11 * maintain a list of local configuration properties and listen for changes
12 * to those properties dynamically using CustomEvent. The initial values are
13 * also maintained so that the configuration can be reset at any given point
14 * to its initial state.
15 * @namespace YAHOO.util
18 * @param {Object} owner The owner Object to which this Config Object belongs
20 YAHOO.util.Config = function (owner) {
26 if (!owner) { YAHOO.log("No owner specified for Config object", "error", "Config"); }
31 var Lang = YAHOO.lang,
32 CustomEvent = YAHOO.util.CustomEvent,
33 Config = YAHOO.util.Config;
37 * Constant representing the CustomEvent type for the config changed event.
38 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
43 Config.CONFIG_CHANGED_EVENT = "configChanged";
46 * Constant representing the boolean type string
47 * @property YAHOO.util.Config.BOOLEAN_TYPE
52 Config.BOOLEAN_TYPE = "boolean";
57 * Object reference to the owner of this Config Object
64 * Boolean flag that specifies whether a queue is currently
66 * @property queueInProgress
69 queueInProgress: false,
72 * Maintains the local collection of configuration property objects and
73 * their specified values
81 * Maintains the local collection of configuration property objects as
82 * they were initially applied.
83 * This object is used when resetting a property.
84 * @property initialConfig
91 * Maintains the local, normalized CustomEvent queue
92 * @property eventQueue
99 * Custom Event, notifying subscribers when Config properties are set
100 * (setProperty is called without the silent flag
101 * @event configChangedEvent
103 configChangedEvent: null,
106 * Initializes the configuration Object and all of its local members.
108 * @param {Object} owner The owner Object to which this Config
111 init: function (owner) {
115 this.configChangedEvent =
116 this.createEvent(Config.CONFIG_CHANGED_EVENT);
118 this.configChangedEvent.signature = CustomEvent.LIST;
119 this.queueInProgress = false;
121 this.initialConfig = {};
122 this.eventQueue = [];
127 * Validates that the value passed in is a Boolean.
128 * @method checkBoolean
129 * @param {Object} val The value to validate
130 * @return {Boolean} true, if the value is valid
132 checkBoolean: function (val) {
133 return (typeof val == Config.BOOLEAN_TYPE);
137 * Validates that the value passed in is a number.
138 * @method checkNumber
139 * @param {Object} val The value to validate
140 * @return {Boolean} true, if the value is valid
142 checkNumber: function (val) {
143 return (!isNaN(val));
147 * Fires a configuration property event using the specified value.
150 * @param {String} key The configuration property's name
151 * @param {value} Object The value of the correct type for the property
153 fireEvent: function ( key, value ) {
154 YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
155 var property = this.config[key];
157 if (property && property.event) {
158 property.event.fire(value);
163 * Adds a property to the Config Object's private config hash.
164 * @method addProperty
165 * @param {String} key The configuration property's name
166 * @param {Object} propertyObject The Object containing all of this
167 * property's arguments
169 addProperty: function ( key, propertyObject ) {
170 key = key.toLowerCase();
171 YAHOO.log("Added property: " + key, "info", "Config");
173 this.config[key] = propertyObject;
175 propertyObject.event = this.createEvent(key, { scope: this.owner });
176 propertyObject.event.signature = CustomEvent.LIST;
179 propertyObject.key = key;
181 if (propertyObject.handler) {
182 propertyObject.event.subscribe(propertyObject.handler,
186 this.setProperty(key, propertyObject.value, true);
188 if (! propertyObject.suppressEvent) {
189 this.queueProperty(key, propertyObject.value);
195 * Returns a key-value configuration map of the values currently set in
198 * @return {Object} The current config, represented in a key-value map
200 getConfig: function () {
203 currCfg = this.config,
207 for (prop in currCfg) {
208 if (Lang.hasOwnProperty(currCfg, prop)) {
209 property = currCfg[prop];
210 if (property && property.event) {
211 cfg[prop] = property.value;
220 * Returns the value of specified property.
221 * @method getProperty
222 * @param {String} key The name of the property
223 * @return {Object} The value of the specified property
225 getProperty: function (key) {
226 var property = this.config[key.toLowerCase()];
227 if (property && property.event) {
228 return property.value;
235 * Resets the specified property's value to its initial value.
236 * @method resetProperty
237 * @param {String} key The name of the property
238 * @return {Boolean} True is the property was reset, false if not
240 resetProperty: function (key) {
242 key = key.toLowerCase();
244 var property = this.config[key];
246 if (property && property.event) {
248 if (this.initialConfig[key] &&
249 !Lang.isUndefined(this.initialConfig[key])) {
251 this.setProperty(key, this.initialConfig[key]);
265 * Sets the value of a property. If the silent property is passed as
266 * true, the property's event will not be fired.
267 * @method setProperty
268 * @param {String} key The name of the property
269 * @param {String} value The value to set the property to
270 * @param {Boolean} silent Whether the value should be set silently,
271 * without firing the property event.
272 * @return {Boolean} True, if the set was successful, false if it failed.
274 setProperty: function (key, value, silent) {
278 key = key.toLowerCase();
279 YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
281 if (this.queueInProgress && ! silent) {
282 // Currently running through a queue...
283 this.queueProperty(key,value);
287 property = this.config[key];
288 if (property && property.event) {
289 if (property.validator && !property.validator(value)) {
292 property.value = value;
294 this.fireEvent(key, value);
295 this.configChangedEvent.fire([key, value]);
306 * Sets the value of a property and queues its event to execute. If the
307 * event is already scheduled to execute, it is
308 * moved from its current position to the end of the queue.
309 * @method queueProperty
310 * @param {String} key The name of the property
311 * @param {String} value The value to set the property to
312 * @return {Boolean} true, if the set was successful, false if
315 queueProperty: function (key, value) {
317 key = key.toLowerCase();
318 YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
320 var property = this.config[key],
321 foundDuplicate = false,
336 if (property && property.event) {
338 if (!Lang.isUndefined(value) && property.validator &&
339 !property.validator(value)) { // validator
343 if (!Lang.isUndefined(value)) {
344 property.value = value;
346 value = property.value;
349 foundDuplicate = false;
350 iLen = this.eventQueue.length;
352 for (i = 0; i < iLen; i++) {
353 queueItem = this.eventQueue[i];
356 queueItemKey = queueItem[0];
357 queueItemValue = queueItem[1];
359 if (queueItemKey == key) {
362 found a dupe... push to end of queue, null
363 current item, and break
366 this.eventQueue[i] = null;
368 this.eventQueue.push(
369 [key, (!Lang.isUndefined(value) ?
370 value : queueItemValue)]);
372 foundDuplicate = true;
378 // this is a refire, or a new property in the queue
380 if (! foundDuplicate && !Lang.isUndefined(value)) {
381 this.eventQueue.push([key, value]);
385 if (property.supercedes) {
387 sLen = property.supercedes.length;
389 for (s = 0; s < sLen; s++) {
391 supercedesCheck = property.supercedes[s];
392 qLen = this.eventQueue.length;
394 for (q = 0; q < qLen; q++) {
395 queueItemCheck = this.eventQueue[q];
397 if (queueItemCheck) {
398 queueItemCheckKey = queueItemCheck[0];
399 queueItemCheckValue = queueItemCheck[1];
401 if (queueItemCheckKey ==
402 supercedesCheck.toLowerCase() ) {
404 this.eventQueue.push([queueItemCheckKey,
405 queueItemCheckValue]);
407 this.eventQueue[q] = null;
416 YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
425 * Fires the event for a property using the property's current value.
426 * @method refireEvent
427 * @param {String} key The name of the property
429 refireEvent: function (key) {
431 key = key.toLowerCase();
433 var property = this.config[key];
435 if (property && property.event &&
437 !Lang.isUndefined(property.value)) {
439 if (this.queueInProgress) {
441 this.queueProperty(key);
445 this.fireEvent(key, property.value);
453 * Applies a key-value Object literal to the configuration, replacing
454 * any existing values, and queueing the property events.
455 * Although the values will be set, fireQueue() must be called for their
456 * associated events to execute.
457 * @method applyConfig
458 * @param {Object} userConfig The configuration Object literal
459 * @param {Boolean} init When set to true, the initialConfig will
460 * be set to the userConfig passed in, so that calling a reset will
461 * reset the properties to the passed values.
463 applyConfig: function (userConfig, init) {
470 for (sKey in userConfig) {
471 if (Lang.hasOwnProperty(userConfig, sKey)) {
472 oConfig[sKey.toLowerCase()] = userConfig[sKey];
475 this.initialConfig = oConfig;
478 for (sKey in userConfig) {
479 if (Lang.hasOwnProperty(userConfig, sKey)) {
480 this.queueProperty(sKey, userConfig[sKey]);
486 * Refires the events for all configuration properties using their
490 refresh: function () {
494 for (prop in this.config) {
495 if (Lang.hasOwnProperty(this.config, prop)) {
496 this.refireEvent(prop);
502 * Fires the normalized list of queued property change events
505 fireQueue: function () {
513 this.queueInProgress = true;
514 for (i = 0;i < this.eventQueue.length; i++) {
515 queueItem = this.eventQueue[i];
519 value = queueItem[1];
520 property = this.config[key];
522 property.value = value;
524 // Clear out queue entry, to avoid it being
525 // re-added to the queue by any queueProperty/supercedes
526 // calls which are invoked during fireEvent
527 this.eventQueue[i] = null;
529 this.fireEvent(key,value);
533 this.queueInProgress = false;
534 this.eventQueue = [];
538 * Subscribes an external handler to the change event for any
540 * @method subscribeToConfigEvent
541 * @param {String} key The property name
542 * @param {Function} handler The handler function to use subscribe to
543 * the property's event
544 * @param {Object} obj The Object to use for scoping the event handler
545 * (see CustomEvent documentation)
546 * @param {Boolean} override Optional. If true, will override "this"
547 * within the handler to map to the scope Object passed into the method.
548 * @return {Boolean} True, if the subscription was successful,
551 subscribeToConfigEvent: function (key, handler, obj, override) {
553 var property = this.config[key.toLowerCase()];
555 if (property && property.event) {
556 if (!Config.alreadySubscribed(property.event, handler, obj)) {
557 property.event.subscribe(handler, obj, override);
567 * Unsubscribes an external handler from the change event for any
569 * @method unsubscribeFromConfigEvent
570 * @param {String} key The property name
571 * @param {Function} handler The handler function to use subscribe to
572 * the property's event
573 * @param {Object} obj The Object to use for scoping the event
574 * handler (see CustomEvent documentation)
575 * @return {Boolean} True, if the unsubscription was successful,
578 unsubscribeFromConfigEvent: function (key, handler, obj) {
579 var property = this.config[key.toLowerCase()];
580 if (property && property.event) {
581 return property.event.unsubscribe(handler, obj);
588 * Returns a string representation of the Config object
590 * @return {String} The Config object in string format.
592 toString: function () {
593 var output = "Config";
595 output += " [" + this.owner.toString() + "]";
601 * Returns a string representation of the Config object's current
603 * @method outputEventQueue
604 * @return {String} The string list of CustomEvents currently queued
607 outputEventQueue: function () {
612 nQueue = this.eventQueue.length;
614 for (q = 0; q < nQueue; q++) {
615 queueItem = this.eventQueue[q];
617 output += queueItem[0] + "=" + queueItem[1] + ", ";
624 * Sets all properties to null, unsubscribes all listeners from each
625 * property's change event and all listeners from the configChangedEvent.
628 destroy: function () {
630 var oConfig = this.config,
635 for (sProperty in oConfig) {
637 if (Lang.hasOwnProperty(oConfig, sProperty)) {
639 oProperty = oConfig[sProperty];
641 oProperty.event.unsubscribeAll();
642 oProperty.event = null;
648 this.configChangedEvent.unsubscribeAll();
650 this.configChangedEvent = null;
653 this.initialConfig = null;
654 this.eventQueue = null;
663 * Checks to determine if a particular function/Object pair are already
664 * subscribed to the specified CustomEvent
665 * @method YAHOO.util.Config.alreadySubscribed
667 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
669 * @param {Function} fn The function to look for in the subscribers list
670 * @param {Object} obj The execution scope Object for the subscription
671 * @return {Boolean} true, if the function/Object pair is already subscribed
672 * to the CustomEvent passed in
674 Config.alreadySubscribed = function (evt, fn, obj) {
676 var nSubscribers = evt.subscribers.length,
680 if (nSubscribers > 0) {
681 i = nSubscribers - 1;
683 subsc = evt.subscribers[i];
684 if (subsc && subsc.obj == obj && subsc.fn == fn) {
695 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
702 * The Container family of components is designed to enable developers to
703 * create different kinds of content-containing modules on the web. Module
704 * and Overlay are the most basic containers, and they can be used directly
705 * or extended to build custom containers. Also part of the Container family
706 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
707 * Dialog, and SimpleDialog.
710 * @requires yahoo, dom, event
711 * @optional dragdrop, animation, button
715 * Module is a JavaScript representation of the Standard Module Format.
716 * Standard Module Format is a simple standard for markup containers where
717 * child nodes representing the header, body, and footer of the content are
718 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
719 * Module is the base class for all other classes in the YUI
721 * @namespace YAHOO.widget
724 * @param {String} el The element ID representing the Module <em>OR</em>
725 * @param {HTMLElement} el The element representing the Module
726 * @param {Object} userConfig The configuration Object literal containing
727 * the configuration that should be set for this module. See configuration
728 * documentation for more details.
730 YAHOO.widget.Module = function (el, userConfig) {
732 this.init(el, userConfig);
734 YAHOO.log("No element or element ID specified" +
735 " for Module instantiation", "error");
739 var Dom = YAHOO.util.Dom,
740 Config = YAHOO.util.Config,
741 Event = YAHOO.util.Event,
742 CustomEvent = YAHOO.util.CustomEvent,
743 Module = YAHOO.widget.Module,
752 * Constant representing the name of the Module's events
753 * @property EVENT_TYPES
759 "BEFORE_INIT": "beforeInit",
762 "BEFORE_RENDER": "beforeRender",
764 "CHANGE_HEADER": "changeHeader",
765 "CHANGE_BODY": "changeBody",
766 "CHANGE_FOOTER": "changeFooter",
767 "CHANGE_CONTENT": "changeContent",
768 "DESTORY": "destroy",
769 "BEFORE_SHOW": "beforeShow",
771 "BEFORE_HIDE": "beforeHide",
776 * Constant representing the Module's configuration properties
777 * @property DEFAULT_CONFIG
787 validator: YAHOO.lang.isBoolean
793 supercedes: ["visible"]
797 key: "monitorresize",
801 "APPEND_TO_DOCUMENT_BODY": {
802 key: "appendtodocumentbody",
808 * Constant representing the prefix path to use for non-secure images
809 * @property YAHOO.widget.Module.IMG_ROOT
814 Module.IMG_ROOT = null;
817 * Constant representing the prefix path to use for securely served images
818 * @property YAHOO.widget.Module.IMG_ROOT_SSL
823 Module.IMG_ROOT_SSL = null;
826 * Constant for the default CSS class name that represents a Module
827 * @property YAHOO.widget.Module.CSS_MODULE
832 Module.CSS_MODULE = "yui-module";
835 * Constant representing the module header
836 * @property YAHOO.widget.Module.CSS_HEADER
841 Module.CSS_HEADER = "hd";
844 * Constant representing the module body
845 * @property YAHOO.widget.Module.CSS_BODY
850 Module.CSS_BODY = "bd";
853 * Constant representing the module footer
854 * @property YAHOO.widget.Module.CSS_FOOTER
859 Module.CSS_FOOTER = "ft";
862 * Constant representing the url for the "src" attribute of the iframe
863 * used to monitor changes to the browser's base font size
864 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
869 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
872 * Constant representing the buffer amount (in pixels) to use when positioning
873 * the text resize monitor offscreen. The resize monitor is positioned
874 * offscreen by an amount eqaul to its offsetHeight + the buffer value.
876 * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
880 // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
881 Module.RESIZE_MONITOR_BUFFER = 1;
884 * Singleton CustomEvent fired when the font size is changed in the browser.
885 * Opera's "zoom" functionality currently does not support text
887 * @event YAHOO.widget.Module.textResizeEvent
889 Module.textResizeEvent = new CustomEvent("textResize");
892 * Helper utility method, which forces a document level
893 * redraw for Opera, which can help remove repaint
894 * irregularities after applying DOM changes.
896 * @method YAHOO.widget.Module.forceDocumentRedraw
899 Module.forceDocumentRedraw = function() {
900 var docEl = document.documentElement;
902 docEl.className += " ";
903 docEl.className = YAHOO.lang.trim(docEl.className);
907 function createModuleTemplate() {
909 if (!m_oModuleTemplate) {
910 m_oModuleTemplate = document.createElement("div");
912 m_oModuleTemplate.innerHTML = ("<div class=\"" +
913 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
914 Module.CSS_BODY + "\"></div><div class=\"" +
915 Module.CSS_FOOTER + "\"></div>");
917 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
918 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
919 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
922 return m_oModuleTemplate;
925 function createHeader() {
926 if (!m_oHeaderTemplate) {
927 createModuleTemplate();
929 return (m_oHeaderTemplate.cloneNode(false));
932 function createBody() {
933 if (!m_oBodyTemplate) {
934 createModuleTemplate();
936 return (m_oBodyTemplate.cloneNode(false));
939 function createFooter() {
940 if (!m_oFooterTemplate) {
941 createModuleTemplate();
943 return (m_oFooterTemplate.cloneNode(false));
949 * The class's constructor function
950 * @property contructor
956 * The main module element that contains the header, body, and footer
963 * The header element, denoted with CSS class "hd"
970 * The body element, denoted with CSS class "bd"
977 * The footer element, denoted with CSS class "ft"
984 * The id of the element
991 * A string representing the root path for all images created by
993 * @deprecated It is recommend that any images for a Module be applied
994 * via CSS using the "background-image" property.
995 * @property imageRoot
998 imageRoot: Module.IMG_ROOT,
1001 * Initializes the custom events for Module which are fired
1002 * automatically at appropriate times by the Module class.
1003 * @method initEvents
1005 initEvents: function () {
1007 var SIGNATURE = CustomEvent.LIST;
1010 * CustomEvent fired prior to class initalization.
1011 * @event beforeInitEvent
1012 * @param {class} classRef class reference of the initializing
1013 * class, such as this.beforeInitEvent.fire(Module)
1015 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1016 this.beforeInitEvent.signature = SIGNATURE;
1019 * CustomEvent fired after class initalization.
1021 * @param {class} classRef class reference of the initializing
1022 * class, such as this.beforeInitEvent.fire(Module)
1024 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1025 this.initEvent.signature = SIGNATURE;
1028 * CustomEvent fired when the Module is appended to the DOM
1029 * @event appendEvent
1031 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1032 this.appendEvent.signature = SIGNATURE;
1035 * CustomEvent fired before the Module is rendered
1036 * @event beforeRenderEvent
1038 this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1039 this.beforeRenderEvent.signature = SIGNATURE;
1042 * CustomEvent fired after the Module is rendered
1043 * @event renderEvent
1045 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1046 this.renderEvent.signature = SIGNATURE;
1049 * CustomEvent fired when the header content of the Module
1051 * @event changeHeaderEvent
1052 * @param {String/HTMLElement} content String/element representing
1053 * the new header content
1055 this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1056 this.changeHeaderEvent.signature = SIGNATURE;
1059 * CustomEvent fired when the body content of the Module is modified
1060 * @event changeBodyEvent
1061 * @param {String/HTMLElement} content String/element representing
1062 * the new body content
1064 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1065 this.changeBodyEvent.signature = SIGNATURE;
1068 * CustomEvent fired when the footer content of the Module
1070 * @event changeFooterEvent
1071 * @param {String/HTMLElement} content String/element representing
1072 * the new footer content
1074 this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1075 this.changeFooterEvent.signature = SIGNATURE;
1078 * CustomEvent fired when the content of the Module is modified
1079 * @event changeContentEvent
1081 this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1082 this.changeContentEvent.signature = SIGNATURE;
1085 * CustomEvent fired when the Module is destroyed
1086 * @event destroyEvent
1088 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
1089 this.destroyEvent.signature = SIGNATURE;
1092 * CustomEvent fired before the Module is shown
1093 * @event beforeShowEvent
1095 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1096 this.beforeShowEvent.signature = SIGNATURE;
1099 * CustomEvent fired after the Module is shown
1102 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1103 this.showEvent.signature = SIGNATURE;
1106 * CustomEvent fired before the Module is hidden
1107 * @event beforeHideEvent
1109 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1110 this.beforeHideEvent.signature = SIGNATURE;
1113 * CustomEvent fired after the Module is hidden
1116 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1117 this.hideEvent.signature = SIGNATURE;
1121 * String representing the current user-agent platform
1122 * @property platform
1125 platform: function () {
1126 var ua = navigator.userAgent.toLowerCase();
1128 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1130 } else if (ua.indexOf("macintosh") != -1) {
1138 * String representing the user-agent of the browser
1139 * @deprecated Use YAHOO.env.ua
1143 browser: function () {
1144 var ua = navigator.userAgent.toLowerCase();
1146 Check Opera first in case of spoof and check Safari before
1147 Gecko since Safari's user agent string includes "like Gecko"
1149 if (ua.indexOf('opera') != -1) {
1151 } else if (ua.indexOf('msie 7') != -1) {
1153 } else if (ua.indexOf('msie') != -1) {
1155 } else if (ua.indexOf('safari') != -1) {
1157 } else if (ua.indexOf('gecko') != -1) {
1165 * Boolean representing whether or not the current browsing context is
1167 * @property isSecure
1170 isSecure: function () {
1171 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1179 * Initializes the custom events for Module which are fired
1180 * automatically at appropriate times by the Module class.
1182 initDefaultConfig: function () {
1183 // Add properties //
1185 * Specifies whether the Module is visible on the page.
1190 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1191 handler: this.configVisible,
1192 value: DEFAULT_CONFIG.VISIBLE.value,
1193 validator: DEFAULT_CONFIG.VISIBLE.validator
1198 * Object or array of objects representing the ContainerEffect
1199 * classes that are active for animating the container.
1202 * <strong>NOTE:</strong> Although this configuration
1203 * property is introduced at the Module level, an out of the box
1204 * implementation is not shipped for the Module class so setting
1205 * the proroperty on the Module class has no effect. The Overlay
1206 * class is the first class to provide out of the box ContainerEffect
1213 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1214 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1215 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1219 * Specifies whether to create a special proxy iframe to monitor
1220 * for user font resizing in the document
1221 * @config monitorresize
1225 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1226 handler: this.configMonitorResize,
1227 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1231 * Specifies if the module should be rendered as the first child
1232 * of document.body or appended as the last child when render is called
1233 * with document.body as the "appendToNode".
1235 * Appending to the body while the DOM is still being constructed can
1236 * lead to Operation Aborted errors in IE hence this flag is set to
1240 * @config appendtodocumentbody
1244 this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1245 value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1250 * The Module class's initialization method, which is executed for
1251 * Module and all of its subclasses. This method is automatically
1252 * called by the constructor, and sets up all DOM references for
1253 * pre-existing markup, and creates required markup if it is not
1256 * If the element passed in does not have an id, one will be generated
1260 * @param {String} el The element ID representing the Module <em>OR</em>
1261 * @param {HTMLElement} el The element representing the Module
1262 * @param {Object} userConfig The configuration Object literal
1263 * containing the configuration that should be set for this module.
1264 * See configuration documentation for more details.
1266 init: function (el, userConfig) {
1271 this.beforeInitEvent.fire(Module);
1274 * The Module's Config object used for monitoring
1275 * configuration properties.
1277 * @type YAHOO.util.Config
1279 this.cfg = new Config(this);
1281 if (this.isSecure) {
1282 this.imageRoot = Module.IMG_ROOT_SSL;
1285 if (typeof el == "string") {
1287 el = document.getElementById(el);
1289 el = (createModuleTemplate()).cloneNode(false);
1294 this.id = Dom.generateId(el);
1297 child = this.element.firstChild;
1300 var fndHd = false, fndBd = false, fndFt = false;
1302 // We're looking for elements
1303 if (1 == child.nodeType) {
1304 if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1305 this.header = child;
1307 } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1310 } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1311 this.footer = child;
1315 } while ((child = child.nextSibling));
1318 this.initDefaultConfig();
1320 Dom.addClass(this.element, Module.CSS_MODULE);
1323 this.cfg.applyConfig(userConfig, true);
1327 Subscribe to the fireQueue() method of Config so that any
1328 queued configuration changes are excecuted upon render of
1332 if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1333 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1336 this.initEvent.fire(Module);
1340 * Initialize an empty IFRAME that is placed out of the visible area
1341 * that can be used to detect text resize.
1342 * @method initResizeMonitor
1344 initResizeMonitor: function () {
1346 var isGeckoWin = (UA.gecko && this.platform == "windows");
1348 // Help prevent spinning loading icon which
1349 // started with FireFox 2.0.0.8/Win
1351 setTimeout(function(){self._initResizeMonitor();}, 0);
1353 this._initResizeMonitor();
1358 * Create and initialize the text resize monitoring iframe.
1361 * @method _initResizeMonitor
1363 _initResizeMonitor : function() {
1369 function fireTextResize() {
1370 Module.textResizeEvent.fire();
1374 oIFrame = Dom.get("_yuiResizeMonitor");
1376 var supportsCWResize = this._supportsCWResize();
1379 oIFrame = document.createElement("iframe");
1381 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1382 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1385 if (!supportsCWResize) {
1386 // Can't monitor on contentWindow, so fire from inside iframe
1387 sHTML = ["<html><head><script ",
1388 "type=\"text/javascript\">",
1389 "window.onresize=function(){window.parent.",
1390 "YAHOO.widget.Module.textResizeEvent.",
1393 "<body></body></html>"].join('');
1395 oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1398 oIFrame.id = "_yuiResizeMonitor";
1399 oIFrame.title = "Text Resize Monitor";
1401 Need to set "position" property before inserting the
1402 iframe into the document or Safari's status bar will
1403 forever indicate the iframe is loading
1404 (See SourceForge bug #1723064)
1406 oIFrame.style.position = "absolute";
1407 oIFrame.style.visibility = "hidden";
1409 var db = document.body,
1412 db.insertBefore(oIFrame, fc);
1414 db.appendChild(oIFrame);
1417 oIFrame.style.width = "2em";
1418 oIFrame.style.height = "2em";
1419 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1420 oIFrame.style.left = "0";
1421 oIFrame.style.borderWidth = "0";
1422 oIFrame.style.visibility = "visible";
1425 Don't open/close the document for Gecko like we used to, since it
1426 leads to duplicate cookies. (See SourceForge bug #1721755)
1429 oDoc = oIFrame.contentWindow.document;
1435 if (oIFrame && oIFrame.contentWindow) {
1436 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1438 if (!Module.textResizeInitialized) {
1439 if (supportsCWResize) {
1440 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1442 This will fail in IE if document.domain has
1443 changed, so we must change the listener to
1444 use the oIFrame element instead
1446 Event.on(oIFrame, "resize", fireTextResize);
1449 Module.textResizeInitialized = true;
1451 this.resizeMonitor = oIFrame;
1457 * Text resize monitor helper method.
1458 * Determines if the browser supports resize events on iframe content windows.
1461 * @method _supportsCWResize
1463 _supportsCWResize : function() {
1465 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1466 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1468 We don't want to start sniffing for patch versions, so fire textResize the same
1469 way on all FF2 flavors
1471 var bSupported = true;
1472 if (UA.gecko && UA.gecko <= 1.8) {
1479 * Event handler fired when the resize monitor element is resized.
1480 * @method onDomResize
1481 * @param {DOMEvent} e The DOM resize event
1482 * @param {Object} obj The scope object passed to the handler
1484 onDomResize: function (e, obj) {
1486 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1488 this.resizeMonitor.style.top = nTop + "px";
1489 this.resizeMonitor.style.left = "0";
1493 * Sets the Module's header content to the string specified, or appends
1494 * the passed element to the header. If no header is present, one will
1495 * be automatically created. An empty string can be passed to the method
1496 * to clear the contents of the header.
1499 * @param {String} headerContent The string used to set the header.
1500 * As a convenience, non HTMLElement objects can also be passed into
1501 * the method, and will be treated as strings, with the header innerHTML
1502 * set to their default toString implementations.
1504 * @param {HTMLElement} headerContent The HTMLElement to append to
1506 * @param {DocumentFragment} headerContent The document fragment
1507 * containing elements which are to be added to the header
1509 setHeader: function (headerContent) {
1510 var oHeader = this.header || (this.header = createHeader());
1512 if (headerContent.nodeName) {
1513 oHeader.innerHTML = "";
1514 oHeader.appendChild(headerContent);
1516 oHeader.innerHTML = headerContent;
1519 this.changeHeaderEvent.fire(headerContent);
1520 this.changeContentEvent.fire();
1525 * Appends the passed element to the header. If no header is present,
1526 * one will be automatically created.
1527 * @method appendToHeader
1528 * @param {HTMLElement | DocumentFragment} element The element to
1529 * append to the header. In the case of a document fragment, the
1530 * children of the fragment will be appended to the header.
1532 appendToHeader: function (element) {
1533 var oHeader = this.header || (this.header = createHeader());
1535 oHeader.appendChild(element);
1537 this.changeHeaderEvent.fire(element);
1538 this.changeContentEvent.fire();
1543 * Sets the Module's body content to the HTML specified.
1545 * If no body is present, one will be automatically created.
1547 * An empty string can be passed to the method to clear the contents of the body.
1549 * @param {String} bodyContent The HTML used to set the body.
1550 * As a convenience, non HTMLElement objects can also be passed into
1551 * the method, and will be treated as strings, with the body innerHTML
1552 * set to their default toString implementations.
1554 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1555 * child of the body element.
1557 * @param {DocumentFragment} bodyContent The document fragment
1558 * containing elements which are to be added to the body
1560 setBody: function (bodyContent) {
1561 var oBody = this.body || (this.body = createBody());
1563 if (bodyContent.nodeName) {
1564 oBody.innerHTML = "";
1565 oBody.appendChild(bodyContent);
1567 oBody.innerHTML = bodyContent;
1570 this.changeBodyEvent.fire(bodyContent);
1571 this.changeContentEvent.fire();
1575 * Appends the passed element to the body. If no body is present, one
1576 * will be automatically created.
1577 * @method appendToBody
1578 * @param {HTMLElement | DocumentFragment} element The element to
1579 * append to the body. In the case of a document fragment, the
1580 * children of the fragment will be appended to the body.
1583 appendToBody: function (element) {
1584 var oBody = this.body || (this.body = createBody());
1586 oBody.appendChild(element);
1588 this.changeBodyEvent.fire(element);
1589 this.changeContentEvent.fire();
1594 * Sets the Module's footer content to the HTML specified, or appends
1595 * the passed element to the footer. If no footer is present, one will
1596 * be automatically created. An empty string can be passed to the method
1597 * to clear the contents of the footer.
1599 * @param {String} footerContent The HTML used to set the footer
1600 * As a convenience, non HTMLElement objects can also be passed into
1601 * the method, and will be treated as strings, with the footer innerHTML
1602 * set to their default toString implementations.
1604 * @param {HTMLElement} footerContent The HTMLElement to append to
1607 * @param {DocumentFragment} footerContent The document fragment containing
1608 * elements which are to be added to the footer
1610 setFooter: function (footerContent) {
1612 var oFooter = this.footer || (this.footer = createFooter());
1614 if (footerContent.nodeName) {
1615 oFooter.innerHTML = "";
1616 oFooter.appendChild(footerContent);
1618 oFooter.innerHTML = footerContent;
1621 this.changeFooterEvent.fire(footerContent);
1622 this.changeContentEvent.fire();
1626 * Appends the passed element to the footer. If no footer is present,
1627 * one will be automatically created.
1628 * @method appendToFooter
1629 * @param {HTMLElement | DocumentFragment} element The element to
1630 * append to the footer. In the case of a document fragment, the
1631 * children of the fragment will be appended to the footer
1633 appendToFooter: function (element) {
1635 var oFooter = this.footer || (this.footer = createFooter());
1637 oFooter.appendChild(element);
1639 this.changeFooterEvent.fire(element);
1640 this.changeContentEvent.fire();
1645 * Renders the Module by inserting the elements that are not already
1646 * in the main Module into their correct places. Optionally appends
1647 * the Module to the specified node prior to the render's execution.
1649 * For Modules without existing markup, the appendToNode argument
1650 * is REQUIRED. If this argument is ommitted and the current element is
1651 * not present in the document, the function will return false,
1652 * indicating that the render was a failure.
1655 * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1656 * then the module is rendered as the first child of the body element,
1657 * and not appended to it, to avoid Operation Aborted errors in IE when
1658 * rendering the module before window's load event is fired. You can
1659 * use the appendtodocumentbody configuration property to change this
1660 * to append to document.body if required.
1663 * @param {String} appendToNode The element id to which the Module
1664 * should be appended to prior to rendering <em>OR</em>
1665 * @param {HTMLElement} appendToNode The element to which the Module
1666 * should be appended to prior to rendering
1667 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1668 * represents the actual Standard Module container.
1669 * @return {Boolean} Success or failure of the render
1671 render: function (appendToNode, moduleElement) {
1676 function appendTo(parentNode) {
1677 if (typeof parentNode == "string") {
1678 parentNode = document.getElementById(parentNode);
1682 me._addToParent(parentNode, me.element);
1683 me.appendEvent.fire();
1687 this.beforeRenderEvent.fire();
1689 if (! moduleElement) {
1690 moduleElement = this.element;
1694 appendTo(appendToNode);
1696 // No node was passed in. If the element is not already in the Dom, this fails
1697 if (! Dom.inDocument(this.element)) {
1698 YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
1703 // Need to get everything into the DOM if it isn't already
1704 if (this.header && ! Dom.inDocument(this.header)) {
1705 // There is a header, but it's not in the DOM yet. Need to add it.
1706 firstChild = moduleElement.firstChild;
1708 moduleElement.insertBefore(this.header, firstChild);
1710 moduleElement.appendChild(this.header);
1714 if (this.body && ! Dom.inDocument(this.body)) {
1715 // There is a body, but it's not in the DOM yet. Need to add it.
1716 if (this.footer && Dom.isAncestor(this.moduleElement, this.footer)) {
1717 moduleElement.insertBefore(this.body, this.footer);
1719 moduleElement.appendChild(this.body);
1723 if (this.footer && ! Dom.inDocument(this.footer)) {
1724 // There is a footer, but it's not in the DOM yet. Need to add it.
1725 moduleElement.appendChild(this.footer);
1728 this.renderEvent.fire();
1733 * Removes the Module element from the DOM and sets all child elements
1737 destroy: function () {
1742 Event.purgeElement(this.element, true);
1743 parent = this.element.parentNode;
1747 parent.removeChild(this.element);
1750 this.element = null;
1755 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1760 this.destroyEvent.fire();
1764 * Shows the Module element by setting the visible configuration
1765 * property to true. Also fires two events: beforeShowEvent prior to
1766 * the visibility change, and showEvent after.
1770 this.cfg.setProperty("visible", true);
1774 * Hides the Module element by setting the visible configuration
1775 * property to false. Also fires two events: beforeHideEvent prior to
1776 * the visibility change, and hideEvent after.
1780 this.cfg.setProperty("visible", false);
1783 // BUILT-IN EVENT HANDLERS FOR MODULE //
1785 * Default event handler for changing the visibility property of a
1786 * Module. By default, this is achieved by switching the "display" style
1787 * between "block" and "none".
1788 * This method is responsible for firing showEvent and hideEvent.
1789 * @param {String} type The CustomEvent type (usually the property name)
1790 * @param {Object[]} args The CustomEvent arguments. For configuration
1791 * handlers, args[0] will equal the newly applied value for the property.
1792 * @param {Object} obj The scope object. For configuration handlers,
1793 * this will usually equal the owner.
1794 * @method configVisible
1796 configVisible: function (type, args, obj) {
1797 var visible = args[0];
1799 this.beforeShowEvent.fire();
1800 Dom.setStyle(this.element, "display", "block");
1801 this.showEvent.fire();
1803 this.beforeHideEvent.fire();
1804 Dom.setStyle(this.element, "display", "none");
1805 this.hideEvent.fire();
1810 * Default event handler for the "monitorresize" configuration property
1811 * @param {String} type The CustomEvent type (usually the property name)
1812 * @param {Object[]} args The CustomEvent arguments. For configuration
1813 * handlers, args[0] will equal the newly applied value for the property.
1814 * @param {Object} obj The scope object. For configuration handlers,
1815 * this will usually equal the owner.
1816 * @method configMonitorResize
1818 configMonitorResize: function (type, args, obj) {
1819 var monitor = args[0];
1821 this.initResizeMonitor();
1823 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1824 this.resizeMonitor = null;
1829 * This method is a protected helper, used when constructing the DOM structure for the module
1830 * to account for situations which may cause Operation Aborted errors in IE. It should not
1831 * be used for general DOM construction.
1833 * If the parentNode is not document.body, the element is appended as the last element.
1836 * If the parentNode is document.body the element is added as the first child to help
1837 * prevent Operation Aborted errors in IE.
1840 * @param {parentNode} The HTML element to which the element will be added
1841 * @param {element} The HTML element to be added to parentNode's children
1842 * @method _addToParent
1845 _addToParent: function(parentNode, element) {
1846 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1847 parentNode.insertBefore(element, parentNode.firstChild);
1849 parentNode.appendChild(element);
1854 * Returns a String representation of the Object.
1856 * @return {String} The string representation of the Module
1858 toString: function () {
1859 return "Module " + this.id;
1863 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1870 * Overlay is a Module that is absolutely positioned above the page flow. It
1871 * has convenience methods for positioning and sizing, as well as options for
1872 * controlling zIndex and constraining the Overlay's position to the current
1873 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1874 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1875 * properly rendered above SELECT elements.
1876 * @namespace YAHOO.widget
1878 * @extends YAHOO.widget.Module
1879 * @param {String} el The element ID representing the Overlay <em>OR</em>
1880 * @param {HTMLElement} el The element representing the Overlay
1881 * @param {Object} userConfig The configuration object literal containing
1882 * the configuration that should be set for this Overlay. See configuration
1883 * documentation for more details.
1886 YAHOO.widget.Overlay = function (el, userConfig) {
1887 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1890 var Lang = YAHOO.lang,
1891 CustomEvent = YAHOO.util.CustomEvent,
1892 Module = YAHOO.widget.Module,
1893 Event = YAHOO.util.Event,
1894 Dom = YAHOO.util.Dom,
1895 Config = YAHOO.util.Config,
1897 Overlay = YAHOO.widget.Overlay,
1899 _SUBSCRIBE = "subscribe",
1900 _UNSUBSCRIBE = "unsubscribe",
1901 _CONTAINED = "contained",
1906 * Constant representing the name of the Overlay's events
1907 * @property EVENT_TYPES
1913 "BEFORE_MOVE": "beforeMove",
1918 * Constant representing the Overlay's configuration properties
1919 * @property DEFAULT_CONFIG
1928 validator: Lang.isNumber,
1929 suppressEvent: true,
1930 supercedes: ["iframe"]
1935 validator: Lang.isNumber,
1936 suppressEvent: true,
1937 supercedes: ["iframe"]
1942 suppressEvent: true,
1943 supercedes: ["iframe"]
1948 suppressEvent: true,
1949 supercedes: ["iframe"]
1955 supercedes: ["iframe", "visible"]
1960 suppressEvent: true,
1961 supercedes: ["context", "fixedcenter", "iframe"]
1966 suppressEvent: true,
1967 supercedes: ["context", "fixedcenter", "iframe"]
1970 "AUTO_FILL_HEIGHT" : {
1971 key: "autofillheight",
1972 supercedes: ["height"],
1981 "CONSTRAIN_TO_VIEWPORT": {
1982 key: "constraintoviewport",
1984 validator: Lang.isBoolean,
1985 supercedes: ["iframe", "x", "y", "xy"]
1990 value: (UA.ie == 6 ? true : false),
1991 validator: Lang.isBoolean,
1992 supercedes: ["zindex"]
1995 "PREVENT_CONTEXT_OVERLAP": {
1996 key: "preventcontextoverlap",
1998 validator: Lang.isBoolean,
1999 supercedes: ["constraintoviewport"]
2005 * The URL that will be placed in the iframe
2006 * @property YAHOO.widget.Overlay.IFRAME_SRC
2011 Overlay.IFRAME_SRC = "javascript:false;";
2014 * Number representing how much the iframe shim should be offset from each
2015 * side of an Overlay instance, in pixels.
2016 * @property YAHOO.widget.Overlay.IFRAME_SRC
2022 Overlay.IFRAME_OFFSET = 3;
2025 * Number representing the minimum distance an Overlay instance should be
2026 * positioned relative to the boundaries of the browser's viewport, in pixels.
2027 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2033 Overlay.VIEWPORT_OFFSET = 10;
2036 * Constant representing the top left corner of an element, used for
2037 * configuring the context element alignment
2038 * @property YAHOO.widget.Overlay.TOP_LEFT
2043 Overlay.TOP_LEFT = "tl";
2046 * Constant representing the top right corner of an element, used for
2047 * configuring the context element alignment
2048 * @property YAHOO.widget.Overlay.TOP_RIGHT
2053 Overlay.TOP_RIGHT = "tr";
2056 * Constant representing the top bottom left corner of an element, used for
2057 * configuring the context element alignment
2058 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2063 Overlay.BOTTOM_LEFT = "bl";
2066 * Constant representing the bottom right corner of an element, used for
2067 * configuring the context element alignment
2068 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2073 Overlay.BOTTOM_RIGHT = "br";
2076 * Constant representing the default CSS class used for an Overlay
2077 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2082 Overlay.CSS_OVERLAY = "yui-overlay";
2085 * Constant representing the names of the standard module elements
2086 * used in the overlay.
2087 * @property YAHOO.widget.Overlay.STD_MOD_RE
2092 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2095 * A singleton CustomEvent used for reacting to the DOM event for
2097 * @event YAHOO.widget.Overlay.windowScrollEvent
2099 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2102 * A singleton CustomEvent used for reacting to the DOM event for
2104 * @event YAHOO.widget.Overlay.windowResizeEvent
2106 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2109 * The DOM event handler used to fire the CustomEvent for window scroll
2110 * @method YAHOO.widget.Overlay.windowScrollHandler
2112 * @param {DOMEvent} e The DOM scroll event
2114 Overlay.windowScrollHandler = function (e) {
2115 var t = Event.getTarget(e);
2117 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2118 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2119 // - IE doesn't recognize scroll registered on the document.
2121 // Also, when document view is scrolled, IE doesn't provide a target,
2122 // rest of the browsers set target to window.document, apart from opera
2123 // which sets target to window.
2124 if (!t || t === window || t === window.document) {
2127 if (! window.scrollEnd) {
2128 window.scrollEnd = -1;
2131 clearTimeout(window.scrollEnd);
2133 window.scrollEnd = setTimeout(function () {
2134 Overlay.windowScrollEvent.fire();
2138 Overlay.windowScrollEvent.fire();
2144 * The DOM event handler used to fire the CustomEvent for window resize
2145 * @method YAHOO.widget.Overlay.windowResizeHandler
2147 * @param {DOMEvent} e The DOM resize event
2149 Overlay.windowResizeHandler = function (e) {
2152 if (! window.resizeEnd) {
2153 window.resizeEnd = -1;
2156 clearTimeout(window.resizeEnd);
2158 window.resizeEnd = setTimeout(function () {
2159 Overlay.windowResizeEvent.fire();
2162 Overlay.windowResizeEvent.fire();
2167 * A boolean that indicated whether the window resize and scroll events have
2168 * already been subscribed to.
2169 * @property YAHOO.widget.Overlay._initialized
2173 Overlay._initialized = null;
2175 if (Overlay._initialized === null) {
2176 Event.on(window, "scroll", Overlay.windowScrollHandler);
2177 Event.on(window, "resize", Overlay.windowResizeHandler);
2178 Overlay._initialized = true;
2182 * Internal map of special event types, which are provided
2183 * by the instance. It maps the event type to the custom event
2184 * instance. Contains entries for the "windowScroll", "windowResize" and
2185 * "textResize" static container events.
2187 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2192 Overlay._TRIGGER_MAP = {
2193 "windowScroll" : Overlay.windowScrollEvent,
2194 "windowResize" : Overlay.windowResizeEvent,
2195 "textResize" : Module.textResizeEvent
2198 YAHOO.extend(Overlay, Module, {
2202 * Array of default event types which will trigger
2203 * context alignment for the Overlay class.
2205 * <p>The array is empty by default for Overlay,
2206 * but maybe populated in future releases, so classes extending
2207 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2208 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2209 * value with their own array of values.
2213 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2216 * @property CONTEXT_TRIGGERS
2220 CONTEXT_TRIGGERS : [],
2223 * The Overlay initialization method, which is executed for Overlay and
2224 * all of its subclasses. This method is automatically called by the
2225 * constructor, and sets up all DOM references for pre-existing markup,
2226 * and creates required markup if it is not already present.
2228 * @param {String} el The element ID representing the Overlay <em>OR</em>
2229 * @param {HTMLElement} el The element representing the Overlay
2230 * @param {Object} userConfig The configuration object literal
2231 * containing the configuration that should be set for this Overlay.
2232 * See configuration documentation for more details.
2234 init: function (el, userConfig) {
2237 Note that we don't pass the user config in here yet because we
2238 only want it executed once, at the lowest subclass level
2241 Overlay.superclass.init.call(this, el/*, userConfig*/);
2243 this.beforeInitEvent.fire(Overlay);
2245 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2248 this.cfg.applyConfig(userConfig, true);
2251 if (this.platform == "mac" && UA.gecko) {
2253 if (! Config.alreadySubscribed(this.showEvent,
2254 this.showMacGeckoScrollbars, this)) {
2256 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2261 if (! Config.alreadySubscribed(this.hideEvent,
2262 this.hideMacGeckoScrollbars, this)) {
2264 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2270 this.initEvent.fire(Overlay);
2274 * Initializes the custom events for Overlay which are fired
2275 * automatically at appropriate times by the Overlay class.
2276 * @method initEvents
2278 initEvents: function () {
2280 Overlay.superclass.initEvents.call(this);
2282 var SIGNATURE = CustomEvent.LIST;
2285 * CustomEvent fired before the Overlay is moved.
2286 * @event beforeMoveEvent
2287 * @param {Number} x x coordinate
2288 * @param {Number} y y coordinate
2290 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2291 this.beforeMoveEvent.signature = SIGNATURE;
2294 * CustomEvent fired after the Overlay is moved.
2296 * @param {Number} x x coordinate
2297 * @param {Number} y y coordinate
2299 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2300 this.moveEvent.signature = SIGNATURE;
2305 * Initializes the class's configurable properties which can be changed
2306 * using the Overlay's Config object (cfg).
2307 * @method initDefaultConfig
2309 initDefaultConfig: function () {
2311 Overlay.superclass.initDefaultConfig.call(this);
2315 // Add overlay config properties //
2318 * The absolute x-coordinate position of the Overlay
2323 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2325 handler: this.configX,
2326 validator: DEFAULT_CONFIG.X.validator,
2327 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2328 supercedes: DEFAULT_CONFIG.X.supercedes
2333 * The absolute y-coordinate position of the Overlay
2338 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2340 handler: this.configY,
2341 validator: DEFAULT_CONFIG.Y.validator,
2342 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2343 supercedes: DEFAULT_CONFIG.Y.supercedes
2348 * An array with the absolute x and y positions of the Overlay
2353 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2354 handler: this.configXY,
2355 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2356 supercedes: DEFAULT_CONFIG.XY.supercedes
2361 * The array of context arguments for context-sensitive positioning.
2365 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional)]</code>, the
2366 * the 4 array elements described in detail below:
2370 * <dt>contextElementOrId <String|HTMLElement></dt>
2371 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2372 * <dt>overlayCorner <String></dt>
2373 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2374 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2375 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2376 * <dt>contextCorner <String></dt>
2377 * <dd>The corner of the context element which is to be used for alignment. Supported string values are the same ones listed for the "overlayCorner" entry above.</dd>
2378 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2381 * By default, context alignment is a one time operation, aligning the Overlay to the context element when context configuration property is set, or when the <a href="#method_align">align</a>
2382 * method is invoked. However, you can use the optional "arrayOfTriggerEvents" entry to define the list of events which should force the overlay to re-align itself with the context element.
2383 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2386 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2387 * 3 static container event types are also currently supported : <code>"windowResize", "windowScroll", "textResize"</code> (defined in <a href="#property__TRIGGER_MAP">_TRIGGER_MAP</a> private property).
2393 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2394 * align the Overlay's top left corner to the bottom left corner of the
2395 * context element with id "img1".
2398 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"]]</code>,
2399 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2406 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2407 handler: this.configContext,
2408 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2409 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2413 * Determines whether or not the Overlay should be anchored
2414 * to the center of the viewport.
2416 * <p>This property can be set to:</p>
2421 * To enable fixed center positioning
2423 * When enabled, the overlay will
2424 * be positioned in the center of viewport when initially displayed, and
2425 * will remain in the center of the viewport whenever the window is
2426 * scrolled or resized.
2429 * If the overlay is too big for the viewport,
2430 * it's top left corner will be aligned with the top left corner of the viewport.
2435 * To disable fixed center positioning.
2436 * <p>In this case the overlay can still be
2437 * centered as a one-off operation, by invoking the <code>center()</code> method,
2438 * however it will not remain centered when the window is scrolled/resized.
2440 * <dt>"contained"<dt>
2441 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2442 * <p>However, unlike setting the property to <code>true</code>,
2443 * when the property is set to <code>"contained"</code>, if the overlay is
2444 * too big for the viewport, it will not get automatically centered when the
2445 * user scrolls or resizes the window (until the window is large enough to contain the
2446 * overlay). This is useful in cases where the Overlay has both header and footer
2447 * UI controls which the user may need to access.
2452 * @config fixedcenter
2453 * @type Boolean | String
2456 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2457 handler: this.configFixedCenter,
2458 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2459 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2460 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2464 * CSS width of the Overlay.
2469 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2470 handler: this.configWidth,
2471 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2472 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2476 * CSS height of the Overlay.
2481 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2482 handler: this.configHeight,
2483 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2484 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2488 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2489 * Supported values are "header", "body", "footer".
2491 * @config autofillheight
2495 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2496 handler: this.configAutoFillHeight,
2497 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2498 validator : this._validateAutoFill,
2499 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2503 * CSS z-index of the Overlay.
2508 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2509 handler: this.configzIndex,
2510 value: DEFAULT_CONFIG.ZINDEX.value
2514 * True if the Overlay should be prevented from being positioned
2515 * out of the viewport.
2516 * @config constraintoviewport
2520 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2522 handler: this.configConstrainToViewport,
2523 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2524 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2525 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2531 * @description Boolean indicating whether or not the Overlay should
2532 * have an IFRAME shim; used to prevent SELECT elements from
2533 * poking through an Overlay instance in IE6. When set to "true",
2534 * the iframe shim is created when the Overlay instance is intially
2537 * @default true for IE6 and below, false for all other browsers.
2539 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2541 handler: this.configIframe,
2542 value: DEFAULT_CONFIG.IFRAME.value,
2543 validator: DEFAULT_CONFIG.IFRAME.validator,
2544 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2549 * @config preventcontextoverlap
2550 * @description Boolean indicating whether or not the Overlay should overlap its
2551 * context element (defined using the "context" configuration property) when the
2552 * "constraintoviewport" configuration property is set to "true".
2556 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2558 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2559 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2560 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2567 * Moves the Overlay to the specified position. This function is
2568 * identical to calling this.cfg.setProperty("xy", [x,y]);
2570 * @param {Number} x The Overlay's new x position
2571 * @param {Number} y The Overlay's new y position
2573 moveTo: function (x, y) {
2574 this.cfg.setProperty("xy", [x, y]);
2578 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2579 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2580 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2581 * @method hideMacGeckoScrollbars
2583 hideMacGeckoScrollbars: function () {
2584 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2588 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2589 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2590 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2591 * @method showMacGeckoScrollbars
2593 showMacGeckoScrollbars: function () {
2594 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2598 * Internal implementation to set the visibility of the overlay in the DOM.
2600 * @method _setDomVisibility
2601 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2604 _setDomVisibility : function(show) {
2605 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2608 Dom.removeClass(this.element, "yui-overlay-hidden");
2610 Dom.addClass(this.element, "yui-overlay-hidden");
2614 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2616 * The default event handler fired when the "visible" property is
2617 * changed. This method is responsible for firing showEvent
2619 * @method configVisible
2620 * @param {String} type The CustomEvent type (usually the property name)
2621 * @param {Object[]} args The CustomEvent arguments. For configuration
2622 * handlers, args[0] will equal the newly applied value for the property.
2623 * @param {Object} obj The scope object. For configuration handlers,
2624 * this will usually equal the owner.
2626 configVisible: function (type, args, obj) {
2628 var visible = args[0],
2629 currentVis = Dom.getStyle(this.element, "visibility"),
2630 effect = this.cfg.getProperty("effect"),
2631 effectInstances = [],
2632 isMacGecko = (this.platform == "mac" && UA.gecko),
2633 alreadySubscribed = Config.alreadySubscribed,
2634 eff, ei, e, i, j, k, h,
2638 if (currentVis == "inherit") {
2639 e = this.element.parentNode;
2641 while (e.nodeType != 9 && e.nodeType != 11) {
2642 currentVis = Dom.getStyle(e, "visibility");
2644 if (currentVis != "inherit") {
2651 if (currentVis == "inherit") {
2652 currentVis = "visible";
2657 if (effect instanceof Array) {
2658 nEffects = effect.length;
2660 for (i = 0; i < nEffects; i++) {
2662 effectInstances[effectInstances.length] =
2663 eff.effect(this, eff.duration);
2667 effectInstances[effectInstances.length] =
2668 effect.effect(this, effect.duration);
2672 if (visible) { // Show
2674 this.showMacGeckoScrollbars();
2677 if (effect) { // Animate in
2678 if (visible) { // Animate in if not showing
2679 if (currentVis != "visible" || currentVis === "") {
2680 this.beforeShowEvent.fire();
2681 nEffectInstances = effectInstances.length;
2683 for (j = 0; j < nEffectInstances; j++) {
2684 ei = effectInstances[j];
2685 if (j === 0 && !alreadySubscribed(
2686 ei.animateInCompleteEvent,
2687 this.showEvent.fire, this.showEvent)) {
2690 Delegate showEvent until end
2691 of animateInComplete
2694 ei.animateInCompleteEvent.subscribe(
2695 this.showEvent.fire, this.showEvent, true);
2702 if (currentVis != "visible" || currentVis === "") {
2703 this.beforeShowEvent.fire();
2705 this._setDomVisibility(true);
2707 this.cfg.refireEvent("iframe");
2708 this.showEvent.fire();
2710 this._setDomVisibility(true);
2716 this.hideMacGeckoScrollbars();
2719 if (effect) { // Animate out if showing
2720 if (currentVis == "visible") {
2721 this.beforeHideEvent.fire();
2723 nEffectInstances = effectInstances.length;
2724 for (k = 0; k < nEffectInstances; k++) {
2725 h = effectInstances[k];
2727 if (k === 0 && !alreadySubscribed(
2728 h.animateOutCompleteEvent, this.hideEvent.fire,
2732 Delegate hideEvent until end
2733 of animateOutComplete
2736 h.animateOutCompleteEvent.subscribe(
2737 this.hideEvent.fire, this.hideEvent, true);
2743 } else if (currentVis === "") {
2744 this._setDomVisibility(false);
2747 } else { // Simple hide
2749 if (currentVis == "visible" || currentVis === "") {
2750 this.beforeHideEvent.fire();
2751 this._setDomVisibility(false);
2752 this.hideEvent.fire();
2754 this._setDomVisibility(false);
2761 * Fixed center event handler used for centering on scroll/resize, but only if
2762 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2763 * the overlay fits within the viewport.
2765 * @method doCenterOnDOMEvent
2767 doCenterOnDOMEvent: function () {
2769 fc = cfg.getProperty("fixedcenter");
2771 if (cfg.getProperty("visible")) {
2772 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2779 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2780 * will fit entirely inside the viewport, in both dimensions - width and height.
2782 * @method fitsInViewport
2783 * @return boolean true if the Overlay will fit, false if not
2785 fitsInViewport : function() {
2786 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2787 element = this.element,
2788 elementWidth = element.offsetWidth,
2789 elementHeight = element.offsetHeight,
2790 viewportWidth = Dom.getViewportWidth(),
2791 viewportHeight = Dom.getViewportHeight();
2793 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2797 * The default event handler fired when the "fixedcenter" property
2799 * @method configFixedCenter
2800 * @param {String} type The CustomEvent type (usually the property name)
2801 * @param {Object[]} args The CustomEvent arguments. For configuration
2802 * handlers, args[0] will equal the newly applied value for the property.
2803 * @param {Object} obj The scope object. For configuration handlers,
2804 * this will usually equal the owner.
2806 configFixedCenter: function (type, args, obj) {
2809 alreadySubscribed = Config.alreadySubscribed,
2810 windowResizeEvent = Overlay.windowResizeEvent,
2811 windowScrollEvent = Overlay.windowScrollEvent;
2816 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2817 this.beforeShowEvent.subscribe(this.center);
2820 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2821 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2824 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2825 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2829 this.beforeShowEvent.unsubscribe(this.center);
2831 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2832 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2837 * The default event handler fired when the "height" property is changed.
2838 * @method configHeight
2839 * @param {String} type The CustomEvent type (usually the property name)
2840 * @param {Object[]} args The CustomEvent arguments. For configuration
2841 * handlers, args[0] will equal the newly applied value for the property.
2842 * @param {Object} obj The scope object. For configuration handlers,
2843 * this will usually equal the owner.
2845 configHeight: function (type, args, obj) {
2847 var height = args[0],
2850 Dom.setStyle(el, "height", height);
2851 this.cfg.refireEvent("iframe");
2855 * The default event handler fired when the "autofillheight" property is changed.
2856 * @method configAutoFillHeight
2858 * @param {String} type The CustomEvent type (usually the property name)
2859 * @param {Object[]} args The CustomEvent arguments. For configuration
2860 * handlers, args[0] will equal the newly applied value for the property.
2861 * @param {Object} obj The scope object. For configuration handlers,
2862 * this will usually equal the owner.
2864 configAutoFillHeight: function (type, args, obj) {
2865 var fillEl = args[0],
2867 autoFillHeight = "autofillheight",
2869 currEl = cfg.getProperty(autoFillHeight),
2870 autoFill = this._autoFillOnHeightChange;
2872 cfg.unsubscribeFromConfigEvent(height, autoFill);
2873 Module.textResizeEvent.unsubscribe(autoFill);
2874 this.changeContentEvent.unsubscribe(autoFill);
2876 if (currEl && fillEl !== currEl && this[currEl]) {
2877 Dom.setStyle(this[currEl], height, "");
2881 fillEl = Lang.trim(fillEl.toLowerCase());
2883 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
2884 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
2885 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
2887 cfg.setProperty(autoFillHeight, fillEl, true);
2892 * The default event handler fired when the "width" property is changed.
2893 * @method configWidth
2894 * @param {String} type The CustomEvent type (usually the property name)
2895 * @param {Object[]} args The CustomEvent arguments. For configuration
2896 * handlers, args[0] will equal the newly applied value for the property.
2897 * @param {Object} obj The scope object. For configuration handlers,
2898 * this will usually equal the owner.
2900 configWidth: function (type, args, obj) {
2902 var width = args[0],
2905 Dom.setStyle(el, "width", width);
2906 this.cfg.refireEvent("iframe");
2910 * The default event handler fired when the "zIndex" property is changed.
2911 * @method configzIndex
2912 * @param {String} type The CustomEvent type (usually the property name)
2913 * @param {Object[]} args The CustomEvent arguments. For configuration
2914 * handlers, args[0] will equal the newly applied value for the property.
2915 * @param {Object} obj The scope object. For configuration handlers,
2916 * this will usually equal the owner.
2918 configzIndex: function (type, args, obj) {
2920 var zIndex = args[0],
2924 zIndex = Dom.getStyle(el, "zIndex");
2925 if (! zIndex || isNaN(zIndex)) {
2930 if (this.iframe || this.cfg.getProperty("iframe") === true) {
2936 Dom.setStyle(el, "zIndex", zIndex);
2937 this.cfg.setProperty("zIndex", zIndex, true);
2945 * The default event handler fired when the "xy" property is changed.
2947 * @param {String} type The CustomEvent type (usually the property name)
2948 * @param {Object[]} args The CustomEvent arguments. For configuration
2949 * handlers, args[0] will equal the newly applied value for the property.
2950 * @param {Object} obj The scope object. For configuration handlers,
2951 * this will usually equal the owner.
2953 configXY: function (type, args, obj) {
2959 this.cfg.setProperty("x", x);
2960 this.cfg.setProperty("y", y);
2962 this.beforeMoveEvent.fire([x, y]);
2964 x = this.cfg.getProperty("x");
2965 y = this.cfg.getProperty("y");
2967 YAHOO.log(("xy: " + [x, y]), "iframe");
2969 this.cfg.refireEvent("iframe");
2970 this.moveEvent.fire([x, y]);
2974 * The default event handler fired when the "x" property is changed.
2976 * @param {String} type The CustomEvent type (usually the property name)
2977 * @param {Object[]} args The CustomEvent arguments. For configuration
2978 * handlers, args[0] will equal the newly applied value for the property.
2979 * @param {Object} obj The scope object. For configuration handlers,
2980 * this will usually equal the owner.
2982 configX: function (type, args, obj) {
2985 y = this.cfg.getProperty("y");
2987 this.cfg.setProperty("x", x, true);
2988 this.cfg.setProperty("y", y, true);
2990 this.beforeMoveEvent.fire([x, y]);
2992 x = this.cfg.getProperty("x");
2993 y = this.cfg.getProperty("y");
2995 Dom.setX(this.element, x, true);
2997 this.cfg.setProperty("xy", [x, y], true);
2999 this.cfg.refireEvent("iframe");
3000 this.moveEvent.fire([x, y]);
3004 * The default event handler fired when the "y" property is changed.
3006 * @param {String} type The CustomEvent type (usually the property name)
3007 * @param {Object[]} args The CustomEvent arguments. For configuration
3008 * handlers, args[0] will equal the newly applied value for the property.
3009 * @param {Object} obj The scope object. For configuration handlers,
3010 * this will usually equal the owner.
3012 configY: function (type, args, obj) {
3014 var x = this.cfg.getProperty("x"),
3017 this.cfg.setProperty("x", x, true);
3018 this.cfg.setProperty("y", y, true);
3020 this.beforeMoveEvent.fire([x, y]);
3022 x = this.cfg.getProperty("x");
3023 y = this.cfg.getProperty("y");
3025 Dom.setY(this.element, y, true);
3027 this.cfg.setProperty("xy", [x, y], true);
3029 this.cfg.refireEvent("iframe");
3030 this.moveEvent.fire([x, y]);
3034 * Shows the iframe shim, if it has been enabled.
3035 * @method showIframe
3037 showIframe: function () {
3039 var oIFrame = this.iframe,
3043 oParentNode = this.element.parentNode;
3045 if (oParentNode != oIFrame.parentNode) {
3046 this._addToParent(oParentNode, oIFrame);
3048 oIFrame.style.display = "block";
3053 * Hides the iframe shim, if it has been enabled.
3054 * @method hideIframe
3056 hideIframe: function () {
3058 this.iframe.style.display = "none";
3063 * Syncronizes the size and position of iframe shim to that of its
3064 * corresponding Overlay instance.
3065 * @method syncIframe
3067 syncIframe: function () {
3069 var oIFrame = this.iframe,
3070 oElement = this.element,
3071 nOffset = Overlay.IFRAME_OFFSET,
3072 nDimensionOffset = (nOffset * 2),
3077 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3078 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3080 // Position <iframe>
3081 aXY = this.cfg.getProperty("xy");
3083 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3084 this.syncPosition();
3085 aXY = this.cfg.getProperty("xy");
3087 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3092 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3093 * the Overlay element. The zindex of the iframe is set to be one less
3094 * than the Overlay element's zindex.
3096 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3097 * to ensure that the iframe shim has a non-negative zindex.
3098 * If you require the iframe zindex to be 0 or higher, the zindex of
3099 * the Overlay element should be set to a value greater than 0, before
3100 * this method is called.
3102 * @method stackIframe
3104 stackIframe: function () {
3106 var overlayZ = Dom.getStyle(this.element, "zIndex");
3107 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3108 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3114 * The default event handler fired when the "iframe" property is changed.
3115 * @method configIframe
3116 * @param {String} type The CustomEvent type (usually the property name)
3117 * @param {Object[]} args The CustomEvent arguments. For configuration
3118 * handlers, args[0] will equal the newly applied value for the property.
3119 * @param {Object} obj The scope object. For configuration handlers,
3120 * this will usually equal the owner.
3122 configIframe: function (type, args, obj) {
3124 var bIFrame = args[0];
3126 function createIFrame() {
3128 var oIFrame = this.iframe,
3129 oElement = this.element,
3133 if (!m_oIFrameTemplate) {
3134 m_oIFrameTemplate = document.createElement("iframe");
3136 if (this.isSecure) {
3137 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3141 Set the opacity of the <iframe> to 0 so that it
3142 doesn't modify the opacity of any transparent
3143 elements that may be on top of it (like a shadow).
3146 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3148 Need to set the "frameBorder" property to 0
3149 supress the default <iframe> border in IE.
3150 Setting the CSS "border" property alone
3153 m_oIFrameTemplate.frameBorder = 0;
3156 m_oIFrameTemplate.style.opacity = "0";
3159 m_oIFrameTemplate.style.position = "absolute";
3160 m_oIFrameTemplate.style.border = "none";
3161 m_oIFrameTemplate.style.margin = "0";
3162 m_oIFrameTemplate.style.padding = "0";
3163 m_oIFrameTemplate.style.display = "none";
3164 m_oIFrameTemplate.tabIndex = -1;
3167 oIFrame = m_oIFrameTemplate.cloneNode(false);
3168 oParent = oElement.parentNode;
3170 var parentNode = oParent || document.body;
3172 this._addToParent(parentNode, oIFrame);
3173 this.iframe = oIFrame;
3177 Show the <iframe> before positioning it since the "setXY"
3178 method of DOM requires the element be in the document
3184 Syncronize the size and position of the <iframe> to that
3190 // Add event listeners to update the <iframe> when necessary
3191 if (!this._hasIframeEventListeners) {
3192 this.showEvent.subscribe(this.showIframe);
3193 this.hideEvent.subscribe(this.hideIframe);
3194 this.changeContentEvent.subscribe(this.syncIframe);
3196 this._hasIframeEventListeners = true;
3200 function onBeforeShow() {
3201 createIFrame.call(this);
3202 this.beforeShowEvent.unsubscribe(onBeforeShow);
3203 this._iframeDeferred = false;
3206 if (bIFrame) { // <iframe> shim is enabled
3208 if (this.cfg.getProperty("visible")) {
3209 createIFrame.call(this);
3211 if (!this._iframeDeferred) {
3212 this.beforeShowEvent.subscribe(onBeforeShow);
3213 this._iframeDeferred = true;
3217 } else { // <iframe> shim is disabled
3220 if (this._hasIframeEventListeners) {
3221 this.showEvent.unsubscribe(this.showIframe);
3222 this.hideEvent.unsubscribe(this.hideIframe);
3223 this.changeContentEvent.unsubscribe(this.syncIframe);
3225 this._hasIframeEventListeners = false;
3231 * Set's the container's XY value from DOM if not already set.
3233 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3234 * not already set. The method also refire's the XY config property event, so any
3235 * beforeMove, Move event listeners are invoked.
3237 * @method _primeXYFromDOM
3240 _primeXYFromDOM : function() {
3241 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3242 // Set CFG XY based on DOM XY
3243 this.syncPosition();
3244 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3245 this.cfg.refireEvent("xy");
3246 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3251 * The default event handler fired when the "constraintoviewport"
3252 * property is changed.
3253 * @method configConstrainToViewport
3254 * @param {String} type The CustomEvent type (usually the property name)
3255 * @param {Object[]} args The CustomEvent arguments. For configuration
3256 * handlers, args[0] will equal the newly applied value for
3258 * @param {Object} obj The scope object. For configuration handlers,
3259 * this will usually equal the owner.
3261 configConstrainToViewport: function (type, args, obj) {
3265 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3266 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3268 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3269 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3272 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3273 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3278 * The default event handler fired when the "context" property
3281 * @method configContext
3282 * @param {String} type The CustomEvent type (usually the property name)
3283 * @param {Object[]} args The CustomEvent arguments. For configuration
3284 * handlers, args[0] will equal the newly applied value for the property.
3285 * @param {Object} obj The scope object. For configuration handlers,
3286 * this will usually equal the owner.
3288 configContext: function (type, args, obj) {
3290 var contextArgs = args[0],
3292 elementMagnetCorner,
3293 contextMagnetCorner,
3295 defTriggers = this.CONTEXT_TRIGGERS;
3299 contextEl = contextArgs[0];
3300 elementMagnetCorner = contextArgs[1];
3301 contextMagnetCorner = contextArgs[2];
3302 triggers = contextArgs[3];
3304 if (defTriggers && defTriggers.length > 0) {
3305 triggers = (triggers || []).concat(defTriggers);
3309 if (typeof contextEl == "string") {
3310 this.cfg.setProperty("context", [
3311 document.getElementById(contextEl),
3312 elementMagnetCorner,
3313 contextMagnetCorner,
3318 if (elementMagnetCorner && contextMagnetCorner) {
3319 this.align(elementMagnetCorner, contextMagnetCorner);
3322 if (this._contextTriggers) {
3323 // Unsubscribe Old Set
3324 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3328 // Subscribe New Set
3329 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3330 this._contextTriggers = triggers;
3337 * Custom Event handler for context alignment triggers. Invokes the align method
3339 * @method _alignOnTrigger
3342 * @param {String} type The event type (not used by the default implementation)
3343 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3345 _alignOnTrigger: function(type, args) {
3350 * Helper method to locate the custom event instance for the event name string
3351 * passed in. As a convenience measure, any custom events passed in are returned.
3353 * @method _findTriggerCE
3356 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3357 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3359 _findTriggerCE : function(t) {
3361 if (t instanceof CustomEvent) {
3363 } else if (Overlay._TRIGGER_MAP[t]) {
3364 tce = Overlay._TRIGGER_MAP[t];
3370 * Utility method that subscribes or unsubscribes the given
3371 * function from the list of trigger events provided.
3373 * @method _processTriggers
3376 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3377 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3378 * subscribed/unsubscribed respectively.
3380 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3381 * we are subscribing or unsubscribing trigger listeners
3383 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3384 * Context is always set to the overlay instance, and no additional object argument
3385 * get passed to the subscribed function.
3387 _processTriggers : function(triggers, mode, fn) {
3390 for (var i = 0, l = triggers.length; i < l; ++i) {
3392 tce = this._findTriggerCE(t);
3394 tce[mode](fn, this, true);
3401 // END BUILT-IN PROPERTY EVENT HANDLERS //
3403 * Aligns the Overlay to its context element using the specified corner
3404 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3407 * @param {String} elementAlign The String representing the corner of
3408 * the Overlay that should be aligned to the context element
3409 * @param {String} contextAlign The corner of the context element
3410 * that the elementAlign corner should stick to.
3412 align: function (elementAlign, contextAlign) {
3414 var contextArgs = this.cfg.getProperty("context"),
3420 function doAlign(v, h) {
3422 switch (elementAlign) {
3424 case Overlay.TOP_LEFT:
3428 case Overlay.TOP_RIGHT:
3429 me.moveTo((h - element.offsetWidth), v);
3432 case Overlay.BOTTOM_LEFT:
3433 me.moveTo(h, (v - element.offsetHeight));
3436 case Overlay.BOTTOM_RIGHT:
3437 me.moveTo((h - element.offsetWidth),
3438 (v - element.offsetHeight));
3446 context = contextArgs[0];
3447 element = this.element;
3450 if (! elementAlign) {
3451 elementAlign = contextArgs[1];
3454 if (! contextAlign) {
3455 contextAlign = contextArgs[2];
3458 if (element && context) {
3459 contextRegion = Dom.getRegion(context);
3461 switch (contextAlign) {
3463 case Overlay.TOP_LEFT:
3464 doAlign(contextRegion.top, contextRegion.left);
3467 case Overlay.TOP_RIGHT:
3468 doAlign(contextRegion.top, contextRegion.right);
3471 case Overlay.BOTTOM_LEFT:
3472 doAlign(contextRegion.bottom, contextRegion.left);
3475 case Overlay.BOTTOM_RIGHT:
3476 doAlign(contextRegion.bottom, contextRegion.right);
3487 * The default event handler executed when the moveEvent is fired, if the
3488 * "constraintoviewport" is set to true.
3489 * @method enforceConstraints
3490 * @param {String} type The CustomEvent type (usually the property name)
3491 * @param {Object[]} args The CustomEvent arguments. For configuration
3492 * handlers, args[0] will equal the newly applied value for the property.
3493 * @param {Object} obj The scope object. For configuration handlers,
3494 * this will usually equal the owner.
3496 enforceConstraints: function (type, args, obj) {
3499 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3500 this.cfg.setProperty("x", cXY[0], true);
3501 this.cfg.setProperty("y", cXY[1], true);
3502 this.cfg.setProperty("xy", cXY, true);
3507 * Given x coordinate value, returns the calculated x coordinate required to
3508 * position the Overlay if it is to be constrained to the viewport, based on the
3509 * current element size, viewport dimensions and scroll values.
3511 * @param {Number} x The X coordinate value to be constrained
3512 * @return {Number} The constrained x coordinate
3514 getConstrainedX: function (x) {
3516 var oOverlay = this,
3517 oOverlayEl = oOverlay.element,
3518 nOverlayOffsetWidth = oOverlayEl.offsetWidth,
3520 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3521 viewPortWidth = Dom.getViewportWidth(),
3522 scrollX = Dom.getDocumentScrollLeft(),
3524 bCanConstrain = (nOverlayOffsetWidth + nViewportOffset < viewPortWidth),
3526 aContext = this.cfg.getProperty("context"),
3536 leftConstraint = scrollX + nViewportOffset,
3537 rightConstraint = scrollX + viewPortWidth - nOverlayOffsetWidth - nViewportOffset,
3541 oOverlapPositions = {
3551 var flipHorizontal = function () {
3555 if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
3556 nNewX = (nContextElX - nOverlayOffsetWidth);
3559 nNewX = (nContextElX + nContextElWidth);
3563 oOverlay.cfg.setProperty("x", (nNewX + scrollX), true);
3572 Uses the context element's position to calculate the availble width
3573 to the right and left of it to display its corresponding Overlay.
3576 var getDisplayRegionWidth = function () {
3578 // The Overlay is to the right of the context element
3580 if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
3581 return (nRightRegionWidth - nViewportOffset);
3583 else { // The Overlay is to the left of the context element
3584 return (nLeftRegionWidth - nViewportOffset);
3591 Positions the Overlay to the left or right of the context element so that it remains
3592 inside the viewport.
3595 var setHorizontalPosition = function () {
3597 var nDisplayRegionWidth = getDisplayRegionWidth(),
3600 if (nOverlayOffsetWidth > nDisplayRegionWidth) {
3605 All possible positions and values have been
3606 tried, but none were successful, so fall back
3607 to the original size and position.
3619 fnReturnVal = setHorizontalPosition();
3629 // Determine if the current value for the Overlay's "x" configuration property will
3630 // result in the Overlay being positioned outside the boundaries of the viewport
3632 if (x < leftConstraint || x > rightConstraint) {
3634 // The current value for the Overlay's "x" configuration property WILL
3635 // result in the Overlay being positioned outside the boundaries of the viewport
3637 if (bCanConstrain) {
3639 // If the "preventcontextoverlap" configuration property is set to "true",
3640 // try to flip the Overlay to both keep it inside the boundaries of the
3641 // viewport AND from overlaping its context element.
3643 if (this.cfg.getProperty("preventcontextoverlap") && aContext &&
3644 oOverlapPositions[(aContext[1] + aContext[2])]) {
3646 oContextEl = aContext[0];
3647 nContextElX = Dom.getX(oContextEl) - scrollX;
3648 nContextElWidth = oContextEl.offsetWidth;
3649 nLeftRegionWidth = nContextElX;
3650 nRightRegionWidth = (viewPortWidth - (nContextElX + nContextElWidth));
3652 setHorizontalPosition();
3654 xNew = this.cfg.getProperty("x");
3659 if (x < leftConstraint) {
3660 xNew = leftConstraint;
3661 } else if (x > rightConstraint) {
3662 xNew = rightConstraint;
3668 // The "x" configuration property cannot be set to a value that will keep
3669 // entire Overlay inside the boundary of the viewport. Therefore, set
3670 // the "x" configuration property to scrollY to keep as much of the
3671 // Overlay inside the viewport as possible.
3672 xNew = nViewportOffset + scrollX;
3683 * Given y coordinate value, returns the calculated y coordinate required to
3684 * position the Overlay if it is to be constrained to the viewport, based on the
3685 * current element size, viewport dimensions and scroll values.
3687 * @param {Number} y The Y coordinate value to be constrained
3688 * @return {Number} The constrained y coordinate
3690 getConstrainedY: function (y) {
3692 var oOverlay = this,
3693 oOverlayEl = oOverlay.element,
3694 nOverlayOffsetHeight = oOverlayEl.offsetHeight,
3696 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3697 viewPortHeight = Dom.getViewportHeight(),
3698 scrollY = Dom.getDocumentScrollTop(),
3700 bCanConstrain = (nOverlayOffsetHeight + nViewportOffset < viewPortHeight),
3702 aContext = this.cfg.getProperty("context"),
3710 nBottomRegionHeight,
3712 topConstraint = scrollY + nViewportOffset,
3713 bottomConstraint = scrollY + viewPortHeight - nOverlayOffsetHeight - nViewportOffset,
3717 oOverlapPositions = {
3725 var flipVertical = function () {
3729 // The Overlay is below the context element, flip it above
3730 if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
3731 nNewY = (nContextElY - nOverlayOffsetHeight);
3733 else { // The Overlay is above the context element, flip it below
3734 nNewY = (nContextElY + nContextElHeight);
3737 oOverlay.cfg.setProperty("y", (nNewY + scrollY), true);
3745 Uses the context element's position to calculate the availble height
3746 above and below it to display its corresponding Overlay.
3749 var getDisplayRegionHeight = function () {
3751 // The Overlay is below the context element
3752 if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
3753 return (nBottomRegionHeight - nViewportOffset);
3755 else { // The Overlay is above the context element
3756 return (nTopRegionHeight - nViewportOffset);
3763 Trys to place the Overlay in the best possible position (either above or
3764 below its corresponding context element).
3767 var setVerticalPosition = function () {
3769 var nDisplayRegionHeight = getDisplayRegionHeight(),
3773 if (nOverlayOffsetHeight > nDisplayRegionHeight) {
3778 All possible positions and values for the
3779 "maxheight" configuration property have been
3780 tried, but none were successful, so fall back
3781 to the original size and position.
3793 fnReturnVal = setVerticalPosition();
3804 // Determine if the current value for the Overlay's "y" configuration property will
3805 // result in the Overlay being positioned outside the boundaries of the viewport
3807 if (y < topConstraint || y > bottomConstraint) {
3809 // The current value for the Overlay's "y" configuration property WILL
3810 // result in the Overlay being positioned outside the boundaries of the viewport
3812 if (bCanConstrain) {
3814 // If the "preventcontextoverlap" configuration property is set to "true",
3815 // try to flip the Overlay to both keep it inside the boundaries of the
3816 // viewport AND from overlaping its context element.
3818 if (this.cfg.getProperty("preventcontextoverlap") && aContext &&
3819 oOverlapPositions[(aContext[1] + aContext[2])]) {
3821 oContextEl = aContext[0];
3822 nContextElHeight = oContextEl.offsetHeight;
3823 nContextElY = (Dom.getY(oContextEl) - scrollY);
3825 nTopRegionHeight = nContextElY;
3826 nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
3828 setVerticalPosition();
3830 yNew = oOverlay.cfg.getProperty("y");
3835 if (y < topConstraint) {
3836 yNew = topConstraint;
3837 } else if (y > bottomConstraint) {
3838 yNew = bottomConstraint;
3846 // The "y" configuration property cannot be set to a value that will keep
3847 // entire Overlay inside the boundary of the viewport. Therefore, set
3848 // the "y" configuration property to scrollY to keep as much of the
3849 // Overlay inside the viewport as possible.
3851 yNew = nViewportOffset + scrollY;
3861 * Given x, y coordinate values, returns the calculated coordinates required to
3862 * position the Overlay if it is to be constrained to the viewport, based on the
3863 * current element size, viewport dimensions and scroll values.
3865 * @param {Number} x The X coordinate value to be constrained
3866 * @param {Number} y The Y coordinate value to be constrained
3867 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3869 getConstrainedXY: function(x, y) {
3870 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3874 * Centers the container in the viewport.
3877 center: function () {
3879 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3880 elementWidth = this.element.offsetWidth,
3881 elementHeight = this.element.offsetHeight,
3882 viewPortWidth = Dom.getViewportWidth(),
3883 viewPortHeight = Dom.getViewportHeight(),
3887 if (elementWidth < viewPortWidth) {
3888 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3890 x = nViewportOffset + Dom.getDocumentScrollLeft();
3893 if (elementHeight < viewPortHeight) {
3894 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3896 y = nViewportOffset + Dom.getDocumentScrollTop();
3899 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3900 this.cfg.refireEvent("iframe");
3903 this.forceContainerRedraw();
3908 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3909 * Panel's position in the DOM. This is primarily used to update
3910 * position information during drag & drop.
3911 * @method syncPosition
3913 syncPosition: function () {
3915 var pos = Dom.getXY(this.element);
3917 this.cfg.setProperty("x", pos[0], true);
3918 this.cfg.setProperty("y", pos[1], true);
3919 this.cfg.setProperty("xy", pos, true);
3924 * Event handler fired when the resize monitor element is resized.
3925 * @method onDomResize
3926 * @param {DOMEvent} e The resize DOM event
3927 * @param {Object} obj The scope object
3929 onDomResize: function (e, obj) {
3933 Overlay.superclass.onDomResize.call(this, e, obj);
3935 setTimeout(function () {
3937 me.cfg.refireEvent("iframe");
3938 me.cfg.refireEvent("context");
3943 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3945 * @method _getComputedHeight
3947 * @param {HTMLElement} el The element for which the content height needs to be determined
3948 * @return {Number} The content box height of the given element, or null if it could not be determined.
3950 _getComputedHeight : (function() {
3952 if (document.defaultView && document.defaultView.getComputedStyle) {
3953 return function(el) {
3955 if (el.ownerDocument && el.ownerDocument.defaultView) {
3956 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3958 height = parseInt(computed.height, 10);
3961 return (Lang.isNumber(height)) ? height : null;
3964 return function(el) {
3966 if (el.style.pixelHeight) {
3967 height = el.style.pixelHeight;
3969 return (Lang.isNumber(height)) ? height : null;
3975 * autofillheight validator. Verifies that the autofill value is either null
3976 * or one of the strings : "body", "header" or "footer".
3978 * @method _validateAutoFillHeight
3980 * @param {String} val
3981 * @return true, if valid, false otherwise
3983 _validateAutoFillHeight : function(val) {
3984 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3988 * The default custom event handler executed when the overlay's height is changed,
3989 * if the autofillheight property has been set.
3991 * @method _autoFillOnHeightChange
3993 * @param {String} type The event type
3994 * @param {Array} args The array of arguments passed to event subscribers
3995 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3996 * out the containers height
3998 _autoFillOnHeightChange : function(type, args, el) {
3999 var height = this.cfg.getProperty("height");
4000 if ((height && height !== "auto") || (height === 0)) {
4001 this.fillHeight(el);
4006 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
4007 * otherwise returns the offsetHeight
4008 * @method _getPreciseHeight
4010 * @param {HTMLElement} el
4011 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
4013 _getPreciseHeight : function(el) {
4014 var height = el.offsetHeight;
4016 if (el.getBoundingClientRect) {
4017 var rect = el.getBoundingClientRect();
4018 height = rect.bottom - rect.top;
4026 * Sets the height on the provided header, body or footer element to
4027 * fill out the height of the container. It determines the height of the
4028 * containers content box, based on it's configured height value, and
4029 * sets the height of the autofillheight element to fill out any
4030 * space remaining after the other standard module element heights
4031 * have been accounted for.
4033 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
4034 * height has not been set on the container, since for an "auto" height container,
4035 * the heights of the header/body/footer will drive the height of the container.</p>
4037 * @method fillHeight
4038 * @param {HTMLElement} el The element which should be resized to fill out the height
4039 * of the container element.
4041 fillHeight : function(el) {
4043 var container = this.innerElement || this.element,
4044 containerEls = [this.header, this.body, this.footer],
4051 for (var i = 0, l = containerEls.length; i < l; i++) {
4052 containerEl = containerEls[i];
4054 if (el !== containerEl) {
4055 filled += this._getPreciseHeight(containerEl);
4064 if (UA.ie || UA.opera) {
4065 // Need to set height to 0, to allow height to be reduced
4066 Dom.setStyle(el, 'height', 0 + 'px');
4069 total = this._getComputedHeight(container);
4071 // Fallback, if we can't get computed value for content height
4072 if (total === null) {
4073 Dom.addClass(container, "yui-override-padding");
4074 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4075 Dom.removeClass(container, "yui-override-padding");
4078 remaining = Math.max(total - filled, 0);
4080 Dom.setStyle(el, "height", remaining + "px");
4082 // Re-adjust height if required, to account for el padding and border
4083 if (el.offsetHeight != remaining) {
4084 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4086 Dom.setStyle(el, "height", remaining + "px");
4092 * Places the Overlay on top of all other instances of
4093 * YAHOO.widget.Overlay.
4094 * @method bringToTop
4096 bringToTop: function () {
4099 oElement = this.element;
4101 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4103 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4104 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4106 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4107 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4109 if (nZIndex1 > nZIndex2) {
4111 } else if (nZIndex1 < nZIndex2) {
4118 function isOverlayElement(p_oElement) {
4120 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4121 Panel = YAHOO.widget.Panel;
4123 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4124 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4125 aOverlays[aOverlays.length] = p_oElement.parentNode;
4127 aOverlays[aOverlays.length] = p_oElement;
4132 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
4134 aOverlays.sort(compareZIndexDesc);
4136 var oTopOverlay = aOverlays[0],
4140 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4142 if (!isNaN(nTopZIndex)) {
4143 var bRequiresBump = false;
4145 if (oTopOverlay != oElement) {
4146 bRequiresBump = true;
4147 } else if (aOverlays.length > 1) {
4148 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4149 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4150 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4151 bRequiresBump = true;
4154 if (bRequiresBump) {
4155 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4162 * Removes the Overlay element from the DOM and sets all child
4166 destroy: function () {
4169 this.iframe.parentNode.removeChild(this.iframe);
4174 Overlay.windowResizeEvent.unsubscribe(
4175 this.doCenterOnDOMEvent, this);
4177 Overlay.windowScrollEvent.unsubscribe(
4178 this.doCenterOnDOMEvent, this);
4180 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4182 Overlay.superclass.destroy.call(this);
4186 * Can be used to force the container to repaint/redraw it's contents.
4188 * By default applies and then removes a 1px bottom margin through the
4189 * application/removal of a "yui-force-redraw" class.
4192 * It is currently used by Overlay to force a repaint for webkit
4193 * browsers, when centering.
4195 * @method forceContainerRedraw
4197 forceContainerRedraw : function() {
4199 Dom.addClass(c.element, "yui-force-redraw");
4200 setTimeout(function() {
4201 Dom.removeClass(c.element, "yui-force-redraw");
4206 * Returns a String representation of the object.
4208 * @return {String} The string representation of the Overlay.
4210 toString: function () {
4211 return "Overlay " + this.id;
4220 * OverlayManager is used for maintaining the focus status of
4221 * multiple Overlays.
4222 * @namespace YAHOO.widget
4223 * @namespace YAHOO.widget
4224 * @class OverlayManager
4226 * @param {Array} overlays Optional. A collection of Overlays to register
4228 * @param {Object} userConfig The object literal representing the user
4229 * configuration of the OverlayManager
4231 YAHOO.widget.OverlayManager = function (userConfig) {
4232 this.init(userConfig);
4235 var Overlay = YAHOO.widget.Overlay,
4236 Event = YAHOO.util.Event,
4237 Dom = YAHOO.util.Dom,
4238 Config = YAHOO.util.Config,
4239 CustomEvent = YAHOO.util.CustomEvent,
4240 OverlayManager = YAHOO.widget.OverlayManager;
4243 * The CSS class representing a focused Overlay
4244 * @property OverlayManager.CSS_FOCUSED
4249 OverlayManager.CSS_FOCUSED = "focused";
4251 OverlayManager.prototype = {
4254 * The class's constructor function
4255 * @property contructor
4258 constructor: OverlayManager,
4261 * The array of Overlays that are currently registered
4262 * @property overlays
4263 * @type YAHOO.widget.Overlay[]
4268 * Initializes the default configuration of the OverlayManager
4269 * @method initDefaultConfig
4271 initDefaultConfig: function () {
4273 * The collection of registered Overlays in use by
4274 * the OverlayManager
4276 * @type YAHOO.widget.Overlay[]
4279 this.cfg.addProperty("overlays", { suppressEvent: true } );
4282 * The default DOM event that should be used to focus an Overlay
4283 * @config focusevent
4285 * @default "mousedown"
4287 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4291 * Initializes the OverlayManager
4293 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4294 * register with the manager.
4295 * @param {Object} userConfig The object literal representing the user
4296 * configuration of the OverlayManager
4298 init: function (userConfig) {
4301 * The OverlayManager's Config object used for monitoring
4302 * configuration properties.
4306 this.cfg = new Config(this);
4308 this.initDefaultConfig();
4311 this.cfg.applyConfig(userConfig, true);
4313 this.cfg.fireQueue();
4316 * The currently activated Overlay
4317 * @property activeOverlay
4319 * @type YAHOO.widget.Overlay
4321 var activeOverlay = null;
4324 * Returns the currently focused Overlay
4326 * @return {Overlay} The currently focused Overlay
4328 this.getActive = function () {
4329 return activeOverlay;
4333 * Focuses the specified Overlay
4335 * @param {Overlay} overlay The Overlay to focus
4336 * @param {String} overlay The id of the Overlay to focus
4338 this.focus = function (overlay) {
4339 var o = this.find(overlay);
4346 * Removes the specified Overlay from the manager
4348 * @param {Overlay} overlay The Overlay to remove
4349 * @param {String} overlay The id of the Overlay to remove
4351 this.remove = function (overlay) {
4353 var o = this.find(overlay),
4357 if (activeOverlay == o) {
4358 activeOverlay = null;
4361 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4364 // Set it's zindex so that it's sorted to the end.
4365 originalZ = Dom.getStyle(o.element, "zIndex");
4366 o.cfg.setProperty("zIndex", -1000, true);
4369 this.overlays.sort(this.compareZIndexDesc);
4370 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4372 o.hideEvent.unsubscribe(o.blur);
4373 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4374 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4375 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4378 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4379 o.cfg.setProperty("zIndex", originalZ, true);
4380 o.cfg.setProperty("manager", null);
4383 /* _managed Flag for custom or existing. Don't want to remove existing */
4384 if (o.focusEvent._managed) { o.focusEvent = null; }
4385 if (o.blurEvent._managed) { o.blurEvent = null; }
4387 if (o.focus._managed) { o.focus = null; }
4388 if (o.blur._managed) { o.blur = null; }
4393 * Removes focus from all registered Overlays in the manager
4396 this.blurAll = function () {
4398 var nOverlays = this.overlays.length,
4401 if (nOverlays > 0) {
4404 this.overlays[i].blur();
4411 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4414 * @method _manageBlur
4415 * @param {Overlay} overlay The overlay instance which got blurred.
4418 this._manageBlur = function (overlay) {
4419 var changed = false;
4420 if (activeOverlay == overlay) {
4421 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4422 activeOverlay = null;
4429 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4432 * @method _manageFocus
4433 * @param {Overlay} overlay The overlay instance which got focus.
4436 this._manageFocus = function(overlay) {
4437 var changed = false;
4438 if (activeOverlay != overlay) {
4439 if (activeOverlay) {
4440 activeOverlay.blur();
4442 activeOverlay = overlay;
4443 this.bringToTop(activeOverlay);
4444 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4450 var overlays = this.cfg.getProperty("overlays");
4452 if (! this.overlays) {
4457 this.register(overlays);
4458 this.overlays.sort(this.compareZIndexDesc);
4463 * @method _onOverlayElementFocus
4464 * @description Event handler for the DOM event that is used to focus
4465 * the Overlay instance as specified by the "focusevent"
4466 * configuration property.
4468 * @param {Event} p_oEvent Object representing the DOM event
4469 * object passed back by the event utility (Event).
4471 _onOverlayElementFocus: function (p_oEvent) {
4473 var oTarget = Event.getTarget(p_oEvent),
4474 oClose = this.close;
4476 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4484 * @method _onOverlayDestroy
4485 * @description "destroy" event handler for the Overlay.
4487 * @param {String} p_sType String representing the name of the event
4489 * @param {Array} p_aArgs Array of arguments sent when the event
4491 * @param {Overlay} p_oOverlay Object representing the overlay that
4494 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4495 this.remove(p_oOverlay);
4499 * @method _onOverlayFocusHandler
4501 * focusEvent Handler, used to delegate to _manageFocus with the
4502 * correct arguments.
4505 * @param {String} p_sType String representing the name of the event
4507 * @param {Array} p_aArgs Array of arguments sent when the event
4509 * @param {Overlay} p_oOverlay Object representing the overlay that
4512 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4513 this._manageFocus(p_oOverlay);
4517 * @method _onOverlayBlurHandler
4519 * blurEvent Handler, used to delegate to _manageBlur with the
4520 * correct arguments.
4523 * @param {String} p_sType String representing the name of the event
4525 * @param {Array} p_aArgs Array of arguments sent when the event
4527 * @param {Overlay} p_oOverlay Object representing the overlay that
4530 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4531 this._manageBlur(p_oOverlay);
4535 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4536 * monitor focus state.
4538 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4539 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4540 * on the instance, the _bindFocus method will add them, and the focus method will
4541 * update the OverlayManager's state directly.
4543 * @method _bindFocus
4544 * @param {Overlay} overlay The overlay for which focus needs to be managed
4547 _bindFocus : function(overlay) {
4550 if (!overlay.focusEvent) {
4551 overlay.focusEvent = overlay.createEvent("focus");
4552 overlay.focusEvent.signature = CustomEvent.LIST;
4553 overlay.focusEvent._managed = true;
4555 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4558 if (!overlay.focus) {
4559 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4560 overlay.focus = function () {
4561 if (mgr._manageFocus(this)) {
4563 if (this.cfg.getProperty("visible") && this.focusFirst) {
4566 this.focusEvent.fire();
4569 overlay.focus._managed = true;
4574 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4575 * monitor blur state.
4577 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4578 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4579 * on the instance, the _bindBlur method will add them, and the blur method
4580 * update the OverlayManager's state directly.
4583 * @param {Overlay} overlay The overlay for which blur needs to be managed
4586 _bindBlur : function(overlay) {
4589 if (!overlay.blurEvent) {
4590 overlay.blurEvent = overlay.createEvent("blur");
4591 overlay.blurEvent.signature = CustomEvent.LIST;
4592 overlay.focusEvent._managed = true;
4594 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4597 if (!overlay.blur) {
4598 overlay.blur = function () {
4599 if (mgr._manageBlur(this)) {
4600 this.blurEvent.fire();
4603 overlay.blur._managed = true;
4606 overlay.hideEvent.subscribe(overlay.blur);
4610 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4611 * to be removed for the OverlayManager when destroyed.
4613 * @method _bindDestroy
4614 * @param {Overlay} overlay The overlay instance being managed
4617 _bindDestroy : function(overlay) {
4619 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4623 * Ensures the zIndex configuration property on the managed overlay based instance
4624 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4626 * @method _syncZIndex
4627 * @param {Overlay} overlay The overlay instance being managed
4630 _syncZIndex : function(overlay) {
4631 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4632 if (!isNaN(zIndex)) {
4633 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4635 overlay.cfg.setProperty("zIndex", 0);
4640 * Registers an Overlay or an array of Overlays with the manager. Upon
4641 * registration, the Overlay receives functions for focus and blur,
4642 * along with CustomEvents for each.
4645 * @param {Overlay} overlay An Overlay to register with the manager.
4646 * @param {Overlay[]} overlay An array of Overlays to register with
4648 * @return {boolean} true if any Overlays are registered.
4650 register: function (overlay) {
4652 var registered = false,
4656 if (overlay instanceof Overlay) {
4658 overlay.cfg.addProperty("manager", { value: this } );
4660 this._bindFocus(overlay);
4661 this._bindBlur(overlay);
4662 this._bindDestroy(overlay);
4663 this._syncZIndex(overlay);
4665 this.overlays.push(overlay);
4666 this.bringToTop(overlay);
4670 } else if (overlay instanceof Array) {
4672 for (i = 0, n = overlay.length; i < n; i++) {
4673 registered = this.register(overlay[i]) || registered;
4682 * Places the specified Overlay instance on top of all other
4683 * Overlay instances.
4684 * @method bringToTop
4685 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4687 * @param {String} p_oOverlay String representing the id of an
4690 bringToTop: function (p_oOverlay) {
4692 var oOverlay = this.find(p_oOverlay),
4699 aOverlays = this.overlays;
4700 aOverlays.sort(this.compareZIndexDesc);
4702 oTopOverlay = aOverlays[0];
4705 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4707 if (!isNaN(nTopZIndex)) {
4709 var bRequiresBump = false;
4711 if (oTopOverlay !== oOverlay) {
4712 bRequiresBump = true;
4713 } else if (aOverlays.length > 1) {
4714 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4715 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4716 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4717 bRequiresBump = true;
4721 if (bRequiresBump) {
4722 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4725 aOverlays.sort(this.compareZIndexDesc);
4731 * Attempts to locate an Overlay by instance or ID.
4733 * @param {Overlay} overlay An Overlay to locate within the manager
4734 * @param {String} overlay An Overlay id to locate within the manager
4735 * @return {Overlay} The requested Overlay, if found, or null if it
4736 * cannot be located.
4738 find: function (overlay) {
4740 var isInstance = overlay instanceof Overlay,
4741 overlays = this.overlays,
4742 n = overlays.length,
4747 if (isInstance || typeof overlay == "string") {
4748 for (i = n-1; i >= 0; i--) {
4750 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4761 * Used for sorting the manager's Overlays by z-index.
4762 * @method compareZIndexDesc
4764 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4765 * fall in the stacking order.
4767 compareZIndexDesc: function (o1, o2) {
4769 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4770 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4772 if (zIndex1 === null && zIndex2 === null) {
4774 } else if (zIndex1 === null){
4776 } else if (zIndex2 === null) {
4778 } else if (zIndex1 > zIndex2) {
4780 } else if (zIndex1 < zIndex2) {
4788 * Shows all Overlays in the manager.
4791 showAll: function () {
4792 var overlays = this.overlays,
4793 n = overlays.length,
4796 for (i = n - 1; i >= 0; i--) {
4802 * Hides all Overlays in the manager.
4805 hideAll: function () {
4806 var overlays = this.overlays,
4807 n = overlays.length,
4810 for (i = n - 1; i >= 0; i--) {
4816 * Returns a string representation of the object.
4818 * @return {String} The string representation of the OverlayManager
4820 toString: function () {
4821 return "OverlayManager";
4829 * ContainerEffect encapsulates animation transitions that are executed when
4830 * an Overlay is shown or hidden.
4831 * @namespace YAHOO.widget
4832 * @class ContainerEffect
4834 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
4835 * should be associated with
4836 * @param {Object} attrIn The object literal representing the animation
4837 * arguments to be used for the animate-in transition. The arguments for
4838 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4839 * duration(Number), and method(i.e. Easing.easeIn).
4840 * @param {Object} attrOut The object literal representing the animation
4841 * arguments to be used for the animate-out transition. The arguments for
4842 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4843 * duration(Number), and method(i.e. Easing.easeIn).
4844 * @param {HTMLElement} targetElement Optional. The target element that
4845 * should be animated during the transition. Defaults to overlay.element.
4846 * @param {class} Optional. The animation class to instantiate. Defaults to
4847 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4849 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
4852 animClass = YAHOO.util.Anim;
4856 * The overlay to animate
4858 * @type YAHOO.widget.Overlay
4860 this.overlay = overlay;
4863 * The animation attributes to use when transitioning into view
4867 this.attrIn = attrIn;
4870 * The animation attributes to use when transitioning out of view
4874 this.attrOut = attrOut;
4877 * The target element to be animated
4878 * @property targetElement
4881 this.targetElement = targetElement || overlay.element;
4884 * The animation class to use for animating the overlay
4885 * @property animClass
4888 this.animClass = animClass;
4893 var Dom = YAHOO.util.Dom,
4894 CustomEvent = YAHOO.util.CustomEvent,
4895 ContainerEffect = YAHOO.widget.ContainerEffect;
4899 * A pre-configured ContainerEffect instance that can be used for fading
4900 * an overlay in and out.
4903 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4904 * @param {Number} dur The duration of the animation
4905 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4907 ContainerEffect.FADE = function (overlay, dur) {
4909 var Easing = YAHOO.util.Easing,
4911 attributes: {opacity:{from:0, to:1}},
4913 method: Easing.easeIn
4916 attributes: {opacity:{to:0}},
4918 method: Easing.easeOut
4920 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
4922 fade.handleUnderlayStart = function() {
4923 var underlay = this.overlay.underlay;
4924 if (underlay && YAHOO.env.ua.ie) {
4925 var hasFilters = (underlay.filters && underlay.filters.length > 0);
4927 Dom.addClass(overlay.element, "yui-effect-fade");
4932 fade.handleUnderlayComplete = function() {
4933 var underlay = this.overlay.underlay;
4934 if (underlay && YAHOO.env.ua.ie) {
4935 Dom.removeClass(overlay.element, "yui-effect-fade");
4939 fade.handleStartAnimateIn = function (type, args, obj) {
4940 Dom.addClass(obj.overlay.element, "hide-select");
4942 if (!obj.overlay.underlay) {
4943 obj.overlay.cfg.refireEvent("underlay");
4946 obj.handleUnderlayStart();
4948 obj.overlay._setDomVisibility(true);
4949 Dom.setStyle(obj.overlay.element, "opacity", 0);
4952 fade.handleCompleteAnimateIn = function (type,args,obj) {
4953 Dom.removeClass(obj.overlay.element, "hide-select");
4955 if (obj.overlay.element.style.filter) {
4956 obj.overlay.element.style.filter = null;
4959 obj.handleUnderlayComplete();
4961 obj.overlay.cfg.refireEvent("iframe");
4962 obj.animateInCompleteEvent.fire();
4965 fade.handleStartAnimateOut = function (type, args, obj) {
4966 Dom.addClass(obj.overlay.element, "hide-select");
4967 obj.handleUnderlayStart();
4970 fade.handleCompleteAnimateOut = function (type, args, obj) {
4971 Dom.removeClass(obj.overlay.element, "hide-select");
4972 if (obj.overlay.element.style.filter) {
4973 obj.overlay.element.style.filter = null;
4975 obj.overlay._setDomVisibility(false);
4976 Dom.setStyle(obj.overlay.element, "opacity", 1);
4978 obj.handleUnderlayComplete();
4980 obj.overlay.cfg.refireEvent("iframe");
4981 obj.animateOutCompleteEvent.fire();
4990 * A pre-configured ContainerEffect instance that can be used for sliding an
4991 * overlay in and out.
4994 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4995 * @param {Number} dur The duration of the animation
4996 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4998 ContainerEffect.SLIDE = function (overlay, dur) {
4999 var Easing = YAHOO.util.Easing,
5001 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
5002 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
5003 clientWidth = Dom.getClientWidth(),
5004 offsetWidth = overlay.element.offsetWidth,
5007 attributes: { points: { to: [x, y] } },
5009 method: Easing.easeIn
5013 attributes: { points: { to: [(clientWidth + 25), y] } },
5015 method: Easing.easeOut
5018 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
5020 slide.handleStartAnimateIn = function (type,args,obj) {
5021 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
5022 obj.overlay.element.style.top = y + "px";
5025 slide.handleTweenAnimateIn = function (type, args, obj) {
5027 var pos = Dom.getXY(obj.overlay.element),
5031 if (Dom.getStyle(obj.overlay.element, "visibility") ==
5032 "hidden" && currentX < x) {
5034 obj.overlay._setDomVisibility(true);
5038 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
5039 obj.overlay.cfg.refireEvent("iframe");
5042 slide.handleCompleteAnimateIn = function (type, args, obj) {
5043 obj.overlay.cfg.setProperty("xy", [x, y], true);
5046 obj.overlay.cfg.refireEvent("iframe");
5047 obj.animateInCompleteEvent.fire();
5050 slide.handleStartAnimateOut = function (type, args, obj) {
5052 var vw = Dom.getViewportWidth(),
5053 pos = Dom.getXY(obj.overlay.element),
5056 obj.animOut.attributes.points.to = [(vw + 25), yso];
5059 slide.handleTweenAnimateOut = function (type, args, obj) {
5061 var pos = Dom.getXY(obj.overlay.element),
5065 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
5066 obj.overlay.cfg.refireEvent("iframe");
5069 slide.handleCompleteAnimateOut = function (type, args, obj) {
5070 obj.overlay._setDomVisibility(false);
5072 obj.overlay.cfg.setProperty("xy", [x, y]);
5073 obj.animateOutCompleteEvent.fire();
5080 ContainerEffect.prototype = {
5083 * Initializes the animation classes and events.
5088 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
5089 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
5091 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
5092 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
5094 this.animateInCompleteEvent = this.createEvent("animateInComplete");
5095 this.animateInCompleteEvent.signature = CustomEvent.LIST;
5097 this.animateOutCompleteEvent =
5098 this.createEvent("animateOutComplete");
5099 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
5101 this.animIn = new this.animClass(this.targetElement,
5102 this.attrIn.attributes, this.attrIn.duration,
5103 this.attrIn.method);
5105 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
5106 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
5108 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
5111 this.animOut = new this.animClass(this.targetElement,
5112 this.attrOut.attributes, this.attrOut.duration,
5113 this.attrOut.method);
5115 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
5116 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
5117 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
5123 * Triggers the in-animation.
5126 animateIn: function () {
5127 this.beforeAnimateInEvent.fire();
5128 this.animIn.animate();
5132 * Triggers the out-animation.
5133 * @method animateOut
5135 animateOut: function () {
5136 this.beforeAnimateOutEvent.fire();
5137 this.animOut.animate();
5141 * The default onStart handler for the in-animation.
5142 * @method handleStartAnimateIn
5143 * @param {String} type The CustomEvent type
5144 * @param {Object[]} args The CustomEvent arguments
5145 * @param {Object} obj The scope object
5147 handleStartAnimateIn: function (type, args, obj) { },
5150 * The default onTween handler for the in-animation.
5151 * @method handleTweenAnimateIn
5152 * @param {String} type The CustomEvent type
5153 * @param {Object[]} args The CustomEvent arguments
5154 * @param {Object} obj The scope object
5156 handleTweenAnimateIn: function (type, args, obj) { },
5159 * The default onComplete handler for the in-animation.
5160 * @method handleCompleteAnimateIn
5161 * @param {String} type The CustomEvent type
5162 * @param {Object[]} args The CustomEvent arguments
5163 * @param {Object} obj The scope object
5165 handleCompleteAnimateIn: function (type, args, obj) { },
5168 * The default onStart handler for the out-animation.
5169 * @method handleStartAnimateOut
5170 * @param {String} type The CustomEvent type
5171 * @param {Object[]} args The CustomEvent arguments
5172 * @param {Object} obj The scope object
5174 handleStartAnimateOut: function (type, args, obj) { },
5177 * The default onTween handler for the out-animation.
5178 * @method handleTweenAnimateOut
5179 * @param {String} type The CustomEvent type
5180 * @param {Object[]} args The CustomEvent arguments
5181 * @param {Object} obj The scope object
5183 handleTweenAnimateOut: function (type, args, obj) { },
5186 * The default onComplete handler for the out-animation.
5187 * @method handleCompleteAnimateOut
5188 * @param {String} type The CustomEvent type
5189 * @param {Object[]} args The CustomEvent arguments
5190 * @param {Object} obj The scope object
5192 handleCompleteAnimateOut: function (type, args, obj) { },
5195 * Returns a string representation of the object.
5197 * @return {String} The string representation of the ContainerEffect
5199 toString: function () {
5200 var output = "ContainerEffect";
5202 output += " [" + this.overlay.toString() + "]";
5208 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
5212 YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.7.0", build: "1799"});