2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
10 * Config is a utility used within an Object to allow the implementer to
11 * maintain a list of local configuration properties and listen for changes
12 * to those properties dynamically using CustomEvent. The initial values are
13 * also maintained so that the configuration can be reset at any given point
14 * to its initial state.
15 * @namespace YAHOO.util
18 * @param {Object} owner The owner Object to which this Config Object belongs
20 YAHOO.util.Config = function (owner) {
26 if (!owner) { YAHOO.log("No owner specified for Config object", "error", "Config"); }
31 var Lang = YAHOO.lang,
32 CustomEvent = YAHOO.util.CustomEvent,
33 Config = YAHOO.util.Config;
37 * Constant representing the CustomEvent type for the config changed event.
38 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
43 Config.CONFIG_CHANGED_EVENT = "configChanged";
46 * Constant representing the boolean type string
47 * @property YAHOO.util.Config.BOOLEAN_TYPE
52 Config.BOOLEAN_TYPE = "boolean";
57 * Object reference to the owner of this Config Object
64 * Boolean flag that specifies whether a queue is currently
66 * @property queueInProgress
69 queueInProgress: false,
72 * Maintains the local collection of configuration property objects and
73 * their specified values
81 * Maintains the local collection of configuration property objects as
82 * they were initially applied.
83 * This object is used when resetting a property.
84 * @property initialConfig
91 * Maintains the local, normalized CustomEvent queue
92 * @property eventQueue
99 * Custom Event, notifying subscribers when Config properties are set
100 * (setProperty is called without the silent flag
101 * @event configChangedEvent
103 configChangedEvent: null,
106 * Initializes the configuration Object and all of its local members.
108 * @param {Object} owner The owner Object to which this Config
111 init: function (owner) {
115 this.configChangedEvent =
116 this.createEvent(Config.CONFIG_CHANGED_EVENT);
118 this.configChangedEvent.signature = CustomEvent.LIST;
119 this.queueInProgress = false;
121 this.initialConfig = {};
122 this.eventQueue = [];
127 * Validates that the value passed in is a Boolean.
128 * @method checkBoolean
129 * @param {Object} val The value to validate
130 * @return {Boolean} true, if the value is valid
132 checkBoolean: function (val) {
133 return (typeof val == Config.BOOLEAN_TYPE);
137 * Validates that the value passed in is a number.
138 * @method checkNumber
139 * @param {Object} val The value to validate
140 * @return {Boolean} true, if the value is valid
142 checkNumber: function (val) {
143 return (!isNaN(val));
147 * Fires a configuration property event using the specified value.
150 * @param {String} key The configuration property's name
151 * @param {value} Object The value of the correct type for the property
153 fireEvent: function ( key, value ) {
154 YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
155 var property = this.config[key];
157 if (property && property.event) {
158 property.event.fire(value);
163 * Adds a property to the Config Object's private config hash.
164 * @method addProperty
165 * @param {String} key The configuration property's name
166 * @param {Object} propertyObject The Object containing all of this
167 * property's arguments
169 addProperty: function ( key, propertyObject ) {
170 key = key.toLowerCase();
171 YAHOO.log("Added property: " + key, "info", "Config");
173 this.config[key] = propertyObject;
175 propertyObject.event = this.createEvent(key, { scope: this.owner });
176 propertyObject.event.signature = CustomEvent.LIST;
179 propertyObject.key = key;
181 if (propertyObject.handler) {
182 propertyObject.event.subscribe(propertyObject.handler,
186 this.setProperty(key, propertyObject.value, true);
188 if (! propertyObject.suppressEvent) {
189 this.queueProperty(key, propertyObject.value);
195 * Returns a key-value configuration map of the values currently set in
198 * @return {Object} The current config, represented in a key-value map
200 getConfig: function () {
203 currCfg = this.config,
207 for (prop in currCfg) {
208 if (Lang.hasOwnProperty(currCfg, prop)) {
209 property = currCfg[prop];
210 if (property && property.event) {
211 cfg[prop] = property.value;
220 * Returns the value of specified property.
221 * @method getProperty
222 * @param {String} key The name of the property
223 * @return {Object} The value of the specified property
225 getProperty: function (key) {
226 var property = this.config[key.toLowerCase()];
227 if (property && property.event) {
228 return property.value;
235 * Resets the specified property's value to its initial value.
236 * @method resetProperty
237 * @param {String} key The name of the property
238 * @return {Boolean} True is the property was reset, false if not
240 resetProperty: function (key) {
242 key = key.toLowerCase();
244 var property = this.config[key];
246 if (property && property.event) {
248 if (this.initialConfig[key] &&
249 !Lang.isUndefined(this.initialConfig[key])) {
251 this.setProperty(key, this.initialConfig[key]);
265 * Sets the value of a property. If the silent property is passed as
266 * true, the property's event will not be fired.
267 * @method setProperty
268 * @param {String} key The name of the property
269 * @param {String} value The value to set the property to
270 * @param {Boolean} silent Whether the value should be set silently,
271 * without firing the property event.
272 * @return {Boolean} True, if the set was successful, false if it failed.
274 setProperty: function (key, value, silent) {
278 key = key.toLowerCase();
279 YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
281 if (this.queueInProgress && ! silent) {
282 // Currently running through a queue...
283 this.queueProperty(key,value);
287 property = this.config[key];
288 if (property && property.event) {
289 if (property.validator && !property.validator(value)) {
292 property.value = value;
294 this.fireEvent(key, value);
295 this.configChangedEvent.fire([key, value]);
306 * Sets the value of a property and queues its event to execute. If the
307 * event is already scheduled to execute, it is
308 * moved from its current position to the end of the queue.
309 * @method queueProperty
310 * @param {String} key The name of the property
311 * @param {String} value The value to set the property to
312 * @return {Boolean} true, if the set was successful, false if
315 queueProperty: function (key, value) {
317 key = key.toLowerCase();
318 YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
320 var property = this.config[key],
321 foundDuplicate = false,
336 if (property && property.event) {
338 if (!Lang.isUndefined(value) && property.validator &&
339 !property.validator(value)) { // validator
343 if (!Lang.isUndefined(value)) {
344 property.value = value;
346 value = property.value;
349 foundDuplicate = false;
350 iLen = this.eventQueue.length;
352 for (i = 0; i < iLen; i++) {
353 queueItem = this.eventQueue[i];
356 queueItemKey = queueItem[0];
357 queueItemValue = queueItem[1];
359 if (queueItemKey == key) {
362 found a dupe... push to end of queue, null
363 current item, and break
366 this.eventQueue[i] = null;
368 this.eventQueue.push(
369 [key, (!Lang.isUndefined(value) ?
370 value : queueItemValue)]);
372 foundDuplicate = true;
378 // this is a refire, or a new property in the queue
380 if (! foundDuplicate && !Lang.isUndefined(value)) {
381 this.eventQueue.push([key, value]);
385 if (property.supercedes) {
387 sLen = property.supercedes.length;
389 for (s = 0; s < sLen; s++) {
391 supercedesCheck = property.supercedes[s];
392 qLen = this.eventQueue.length;
394 for (q = 0; q < qLen; q++) {
395 queueItemCheck = this.eventQueue[q];
397 if (queueItemCheck) {
398 queueItemCheckKey = queueItemCheck[0];
399 queueItemCheckValue = queueItemCheck[1];
401 if (queueItemCheckKey ==
402 supercedesCheck.toLowerCase() ) {
404 this.eventQueue.push([queueItemCheckKey,
405 queueItemCheckValue]);
407 this.eventQueue[q] = null;
416 YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
425 * Fires the event for a property using the property's current value.
426 * @method refireEvent
427 * @param {String} key The name of the property
429 refireEvent: function (key) {
431 key = key.toLowerCase();
433 var property = this.config[key];
435 if (property && property.event &&
437 !Lang.isUndefined(property.value)) {
439 if (this.queueInProgress) {
441 this.queueProperty(key);
445 this.fireEvent(key, property.value);
453 * Applies a key-value Object literal to the configuration, replacing
454 * any existing values, and queueing the property events.
455 * Although the values will be set, fireQueue() must be called for their
456 * associated events to execute.
457 * @method applyConfig
458 * @param {Object} userConfig The configuration Object literal
459 * @param {Boolean} init When set to true, the initialConfig will
460 * be set to the userConfig passed in, so that calling a reset will
461 * reset the properties to the passed values.
463 applyConfig: function (userConfig, init) {
470 for (sKey in userConfig) {
471 if (Lang.hasOwnProperty(userConfig, sKey)) {
472 oConfig[sKey.toLowerCase()] = userConfig[sKey];
475 this.initialConfig = oConfig;
478 for (sKey in userConfig) {
479 if (Lang.hasOwnProperty(userConfig, sKey)) {
480 this.queueProperty(sKey, userConfig[sKey]);
486 * Refires the events for all configuration properties using their
490 refresh: function () {
494 for (prop in this.config) {
495 if (Lang.hasOwnProperty(this.config, prop)) {
496 this.refireEvent(prop);
502 * Fires the normalized list of queued property change events
505 fireQueue: function () {
513 this.queueInProgress = true;
514 for (i = 0;i < this.eventQueue.length; i++) {
515 queueItem = this.eventQueue[i];
519 value = queueItem[1];
520 property = this.config[key];
522 property.value = value;
524 // Clear out queue entry, to avoid it being
525 // re-added to the queue by any queueProperty/supercedes
526 // calls which are invoked during fireEvent
527 this.eventQueue[i] = null;
529 this.fireEvent(key,value);
533 this.queueInProgress = false;
534 this.eventQueue = [];
538 * Subscribes an external handler to the change event for any
540 * @method subscribeToConfigEvent
541 * @param {String} key The property name
542 * @param {Function} handler The handler function to use subscribe to
543 * the property's event
544 * @param {Object} obj The Object to use for scoping the event handler
545 * (see CustomEvent documentation)
546 * @param {Boolean} overrideContext Optional. If true, will override
547 * "this" within the handler to map to the scope Object passed into the
549 * @return {Boolean} True, if the subscription was successful,
552 subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
554 var property = this.config[key.toLowerCase()];
556 if (property && property.event) {
557 if (!Config.alreadySubscribed(property.event, handler, obj)) {
558 property.event.subscribe(handler, obj, overrideContext);
568 * Unsubscribes an external handler from the change event for any
570 * @method unsubscribeFromConfigEvent
571 * @param {String} key The property name
572 * @param {Function} handler The handler function to use subscribe to
573 * the property's event
574 * @param {Object} obj The Object to use for scoping the event
575 * handler (see CustomEvent documentation)
576 * @return {Boolean} True, if the unsubscription was successful,
579 unsubscribeFromConfigEvent: function (key, handler, obj) {
580 var property = this.config[key.toLowerCase()];
581 if (property && property.event) {
582 return property.event.unsubscribe(handler, obj);
589 * Returns a string representation of the Config object
591 * @return {String} The Config object in string format.
593 toString: function () {
594 var output = "Config";
596 output += " [" + this.owner.toString() + "]";
602 * Returns a string representation of the Config object's current
604 * @method outputEventQueue
605 * @return {String} The string list of CustomEvents currently queued
608 outputEventQueue: function () {
613 nQueue = this.eventQueue.length;
615 for (q = 0; q < nQueue; q++) {
616 queueItem = this.eventQueue[q];
618 output += queueItem[0] + "=" + queueItem[1] + ", ";
625 * Sets all properties to null, unsubscribes all listeners from each
626 * property's change event and all listeners from the configChangedEvent.
629 destroy: function () {
631 var oConfig = this.config,
636 for (sProperty in oConfig) {
638 if (Lang.hasOwnProperty(oConfig, sProperty)) {
640 oProperty = oConfig[sProperty];
642 oProperty.event.unsubscribeAll();
643 oProperty.event = null;
649 this.configChangedEvent.unsubscribeAll();
651 this.configChangedEvent = null;
654 this.initialConfig = null;
655 this.eventQueue = null;
664 * Checks to determine if a particular function/Object pair are already
665 * subscribed to the specified CustomEvent
666 * @method YAHOO.util.Config.alreadySubscribed
668 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
670 * @param {Function} fn The function to look for in the subscribers list
671 * @param {Object} obj The execution scope Object for the subscription
672 * @return {Boolean} true, if the function/Object pair is already subscribed
673 * to the CustomEvent passed in
675 Config.alreadySubscribed = function (evt, fn, obj) {
677 var nSubscribers = evt.subscribers.length,
681 if (nSubscribers > 0) {
682 i = nSubscribers - 1;
684 subsc = evt.subscribers[i];
685 if (subsc && subsc.obj == obj && subsc.fn == fn) {
696 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
702 * The Container family of components is designed to enable developers to
703 * create different kinds of content-containing modules on the web. Module
704 * and Overlay are the most basic containers, and they can be used directly
705 * or extended to build custom containers. Also part of the Container family
706 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
707 * Dialog, and SimpleDialog.
710 * @requires yahoo, dom, event
711 * @optional dragdrop, animation, button
715 * Module is a JavaScript representation of the Standard Module Format.
716 * Standard Module Format is a simple standard for markup containers where
717 * child nodes representing the header, body, and footer of the content are
718 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
719 * Module is the base class for all other classes in the YUI
721 * @namespace YAHOO.widget
724 * @param {String} el The element ID representing the Module <em>OR</em>
725 * @param {HTMLElement} el The element representing the Module
726 * @param {Object} userConfig The configuration Object literal containing
727 * the configuration that should be set for this module. See configuration
728 * documentation for more details.
730 YAHOO.widget.Module = function (el, userConfig) {
732 this.init(el, userConfig);
734 YAHOO.log("No element or element ID specified" +
735 " for Module instantiation", "error");
739 var Dom = YAHOO.util.Dom,
740 Config = YAHOO.util.Config,
741 Event = YAHOO.util.Event,
742 CustomEvent = YAHOO.util.CustomEvent,
743 Module = YAHOO.widget.Module,
752 * Constant representing the name of the Module's events
753 * @property EVENT_TYPES
759 "BEFORE_INIT": "beforeInit",
762 "BEFORE_RENDER": "beforeRender",
764 "CHANGE_HEADER": "changeHeader",
765 "CHANGE_BODY": "changeBody",
766 "CHANGE_FOOTER": "changeFooter",
767 "CHANGE_CONTENT": "changeContent",
768 "DESTROY": "destroy",
769 "BEFORE_SHOW": "beforeShow",
771 "BEFORE_HIDE": "beforeHide",
776 * Constant representing the Module's configuration properties
777 * @property DEFAULT_CONFIG
787 validator: YAHOO.lang.isBoolean
793 supercedes: ["visible"]
797 key: "monitorresize",
801 "APPEND_TO_DOCUMENT_BODY": {
802 key: "appendtodocumentbody",
808 * Constant representing the prefix path to use for non-secure images
809 * @property YAHOO.widget.Module.IMG_ROOT
814 Module.IMG_ROOT = null;
817 * Constant representing the prefix path to use for securely served images
818 * @property YAHOO.widget.Module.IMG_ROOT_SSL
823 Module.IMG_ROOT_SSL = null;
826 * Constant for the default CSS class name that represents a Module
827 * @property YAHOO.widget.Module.CSS_MODULE
832 Module.CSS_MODULE = "yui-module";
835 * Constant representing the module header
836 * @property YAHOO.widget.Module.CSS_HEADER
841 Module.CSS_HEADER = "hd";
844 * Constant representing the module body
845 * @property YAHOO.widget.Module.CSS_BODY
850 Module.CSS_BODY = "bd";
853 * Constant representing the module footer
854 * @property YAHOO.widget.Module.CSS_FOOTER
859 Module.CSS_FOOTER = "ft";
862 * Constant representing the url for the "src" attribute of the iframe
863 * used to monitor changes to the browser's base font size
864 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
869 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
872 * Constant representing the buffer amount (in pixels) to use when positioning
873 * the text resize monitor offscreen. The resize monitor is positioned
874 * offscreen by an amount eqaul to its offsetHeight + the buffer value.
876 * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
880 // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
881 Module.RESIZE_MONITOR_BUFFER = 1;
884 * Singleton CustomEvent fired when the font size is changed in the browser.
885 * Opera's "zoom" functionality currently does not support text
887 * @event YAHOO.widget.Module.textResizeEvent
889 Module.textResizeEvent = new CustomEvent("textResize");
892 * Helper utility method, which forces a document level
893 * redraw for Opera, which can help remove repaint
894 * irregularities after applying DOM changes.
896 * @method YAHOO.widget.Module.forceDocumentRedraw
899 Module.forceDocumentRedraw = function() {
900 var docEl = document.documentElement;
902 docEl.className += " ";
903 docEl.className = YAHOO.lang.trim(docEl.className);
907 function createModuleTemplate() {
909 if (!m_oModuleTemplate) {
910 m_oModuleTemplate = document.createElement("div");
912 m_oModuleTemplate.innerHTML = ("<div class=\"" +
913 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
914 Module.CSS_BODY + "\"></div><div class=\"" +
915 Module.CSS_FOOTER + "\"></div>");
917 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
918 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
919 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
922 return m_oModuleTemplate;
925 function createHeader() {
926 if (!m_oHeaderTemplate) {
927 createModuleTemplate();
929 return (m_oHeaderTemplate.cloneNode(false));
932 function createBody() {
933 if (!m_oBodyTemplate) {
934 createModuleTemplate();
936 return (m_oBodyTemplate.cloneNode(false));
939 function createFooter() {
940 if (!m_oFooterTemplate) {
941 createModuleTemplate();
943 return (m_oFooterTemplate.cloneNode(false));
949 * The class's constructor function
950 * @property contructor
956 * The main module element that contains the header, body, and footer
963 * The header element, denoted with CSS class "hd"
970 * The body element, denoted with CSS class "bd"
977 * The footer element, denoted with CSS class "ft"
984 * The id of the element
991 * A string representing the root path for all images created by
993 * @deprecated It is recommend that any images for a Module be applied
994 * via CSS using the "background-image" property.
995 * @property imageRoot
998 imageRoot: Module.IMG_ROOT,
1001 * Initializes the custom events for Module which are fired
1002 * automatically at appropriate times by the Module class.
1003 * @method initEvents
1005 initEvents: function () {
1007 var SIGNATURE = CustomEvent.LIST;
1010 * CustomEvent fired prior to class initalization.
1011 * @event beforeInitEvent
1012 * @param {class} classRef class reference of the initializing
1013 * class, such as this.beforeInitEvent.fire(Module)
1015 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1016 this.beforeInitEvent.signature = SIGNATURE;
1019 * CustomEvent fired after class initalization.
1021 * @param {class} classRef class reference of the initializing
1022 * class, such as this.beforeInitEvent.fire(Module)
1024 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1025 this.initEvent.signature = SIGNATURE;
1028 * CustomEvent fired when the Module is appended to the DOM
1029 * @event appendEvent
1031 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1032 this.appendEvent.signature = SIGNATURE;
1035 * CustomEvent fired before the Module is rendered
1036 * @event beforeRenderEvent
1038 this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1039 this.beforeRenderEvent.signature = SIGNATURE;
1042 * CustomEvent fired after the Module is rendered
1043 * @event renderEvent
1045 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1046 this.renderEvent.signature = SIGNATURE;
1049 * CustomEvent fired when the header content of the Module
1051 * @event changeHeaderEvent
1052 * @param {String/HTMLElement} content String/element representing
1053 * the new header content
1055 this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1056 this.changeHeaderEvent.signature = SIGNATURE;
1059 * CustomEvent fired when the body content of the Module is modified
1060 * @event changeBodyEvent
1061 * @param {String/HTMLElement} content String/element representing
1062 * the new body content
1064 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1065 this.changeBodyEvent.signature = SIGNATURE;
1068 * CustomEvent fired when the footer content of the Module
1070 * @event changeFooterEvent
1071 * @param {String/HTMLElement} content String/element representing
1072 * the new footer content
1074 this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1075 this.changeFooterEvent.signature = SIGNATURE;
1078 * CustomEvent fired when the content of the Module is modified
1079 * @event changeContentEvent
1081 this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1082 this.changeContentEvent.signature = SIGNATURE;
1085 * CustomEvent fired when the Module is destroyed
1086 * @event destroyEvent
1088 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
1089 this.destroyEvent.signature = SIGNATURE;
1092 * CustomEvent fired before the Module is shown
1093 * @event beforeShowEvent
1095 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1096 this.beforeShowEvent.signature = SIGNATURE;
1099 * CustomEvent fired after the Module is shown
1102 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1103 this.showEvent.signature = SIGNATURE;
1106 * CustomEvent fired before the Module is hidden
1107 * @event beforeHideEvent
1109 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1110 this.beforeHideEvent.signature = SIGNATURE;
1113 * CustomEvent fired after the Module is hidden
1116 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1117 this.hideEvent.signature = SIGNATURE;
1121 * String representing the current user-agent platform
1122 * @property platform
1125 platform: function () {
1126 var ua = navigator.userAgent.toLowerCase();
1128 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1130 } else if (ua.indexOf("macintosh") != -1) {
1138 * String representing the user-agent of the browser
1139 * @deprecated Use YAHOO.env.ua
1143 browser: function () {
1144 var ua = navigator.userAgent.toLowerCase();
1146 Check Opera first in case of spoof and check Safari before
1147 Gecko since Safari's user agent string includes "like Gecko"
1149 if (ua.indexOf('opera') != -1) {
1151 } else if (ua.indexOf('msie 7') != -1) {
1153 } else if (ua.indexOf('msie') != -1) {
1155 } else if (ua.indexOf('safari') != -1) {
1157 } else if (ua.indexOf('gecko') != -1) {
1165 * Boolean representing whether or not the current browsing context is
1167 * @property isSecure
1170 isSecure: function () {
1171 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1179 * Initializes the custom events for Module which are fired
1180 * automatically at appropriate times by the Module class.
1182 initDefaultConfig: function () {
1183 // Add properties //
1185 * Specifies whether the Module is visible on the page.
1190 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1191 handler: this.configVisible,
1192 value: DEFAULT_CONFIG.VISIBLE.value,
1193 validator: DEFAULT_CONFIG.VISIBLE.validator
1198 * Object or array of objects representing the ContainerEffect
1199 * classes that are active for animating the container.
1202 * <strong>NOTE:</strong> Although this configuration
1203 * property is introduced at the Module level, an out of the box
1204 * implementation is not shipped for the Module class so setting
1205 * the proroperty on the Module class has no effect. The Overlay
1206 * class is the first class to provide out of the box ContainerEffect
1213 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1214 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1215 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1219 * Specifies whether to create a special proxy iframe to monitor
1220 * for user font resizing in the document
1221 * @config monitorresize
1225 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1226 handler: this.configMonitorResize,
1227 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1231 * Specifies if the module should be rendered as the first child
1232 * of document.body or appended as the last child when render is called
1233 * with document.body as the "appendToNode".
1235 * Appending to the body while the DOM is still being constructed can
1236 * lead to Operation Aborted errors in IE hence this flag is set to
1240 * @config appendtodocumentbody
1244 this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1245 value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1250 * The Module class's initialization method, which is executed for
1251 * Module and all of its subclasses. This method is automatically
1252 * called by the constructor, and sets up all DOM references for
1253 * pre-existing markup, and creates required markup if it is not
1256 * If the element passed in does not have an id, one will be generated
1260 * @param {String} el The element ID representing the Module <em>OR</em>
1261 * @param {HTMLElement} el The element representing the Module
1262 * @param {Object} userConfig The configuration Object literal
1263 * containing the configuration that should be set for this module.
1264 * See configuration documentation for more details.
1266 init: function (el, userConfig) {
1271 this.beforeInitEvent.fire(Module);
1274 * The Module's Config object used for monitoring
1275 * configuration properties.
1277 * @type YAHOO.util.Config
1279 this.cfg = new Config(this);
1281 if (this.isSecure) {
1282 this.imageRoot = Module.IMG_ROOT_SSL;
1285 if (typeof el == "string") {
1287 el = document.getElementById(el);
1289 el = (createModuleTemplate()).cloneNode(false);
1294 this.id = Dom.generateId(el);
1297 child = this.element.firstChild;
1300 var fndHd = false, fndBd = false, fndFt = false;
1302 // We're looking for elements
1303 if (1 == child.nodeType) {
1304 if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1305 this.header = child;
1307 } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1310 } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1311 this.footer = child;
1315 } while ((child = child.nextSibling));
1318 this.initDefaultConfig();
1320 Dom.addClass(this.element, Module.CSS_MODULE);
1323 this.cfg.applyConfig(userConfig, true);
1327 Subscribe to the fireQueue() method of Config so that any
1328 queued configuration changes are excecuted upon render of
1332 if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1333 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1336 this.initEvent.fire(Module);
1340 * Initialize an empty IFRAME that is placed out of the visible area
1341 * that can be used to detect text resize.
1342 * @method initResizeMonitor
1344 initResizeMonitor: function () {
1346 var isGeckoWin = (UA.gecko && this.platform == "windows");
1348 // Help prevent spinning loading icon which
1349 // started with FireFox 2.0.0.8/Win
1351 setTimeout(function(){self._initResizeMonitor();}, 0);
1353 this._initResizeMonitor();
1358 * Create and initialize the text resize monitoring iframe.
1361 * @method _initResizeMonitor
1363 _initResizeMonitor : function() {
1369 function fireTextResize() {
1370 Module.textResizeEvent.fire();
1374 oIFrame = Dom.get("_yuiResizeMonitor");
1376 var supportsCWResize = this._supportsCWResize();
1379 oIFrame = document.createElement("iframe");
1381 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1382 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1385 if (!supportsCWResize) {
1386 // Can't monitor on contentWindow, so fire from inside iframe
1387 sHTML = ["<html><head><script ",
1388 "type=\"text/javascript\">",
1389 "window.onresize=function(){window.parent.",
1390 "YAHOO.widget.Module.textResizeEvent.",
1393 "<body></body></html>"].join('');
1395 oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1398 oIFrame.id = "_yuiResizeMonitor";
1399 oIFrame.title = "Text Resize Monitor";
1401 Need to set "position" property before inserting the
1402 iframe into the document or Safari's status bar will
1403 forever indicate the iframe is loading
1404 (See YUILibrary bug #1723064)
1406 oIFrame.style.position = "absolute";
1407 oIFrame.style.visibility = "hidden";
1409 var db = document.body,
1412 db.insertBefore(oIFrame, fc);
1414 db.appendChild(oIFrame);
1417 // Setting the background color fixes an issue with IE6/IE7, where
1418 // elements in the DOM, with -ve margin-top which positioned them
1419 // offscreen (so they would be overlapped by the iframe and its -ve top
1420 // setting), would have their -ve margin-top ignored, when the iframe
1422 oIFrame.style.backgroundColor = "transparent";
1424 oIFrame.style.borderWidth = "0";
1425 oIFrame.style.width = "2em";
1426 oIFrame.style.height = "2em";
1427 oIFrame.style.left = "0";
1428 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1429 oIFrame.style.visibility = "visible";
1432 Don't open/close the document for Gecko like we used to, since it
1433 leads to duplicate cookies. (See YUILibrary bug #1721755)
1436 oDoc = oIFrame.contentWindow.document;
1442 if (oIFrame && oIFrame.contentWindow) {
1443 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1445 if (!Module.textResizeInitialized) {
1446 if (supportsCWResize) {
1447 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1449 This will fail in IE if document.domain has
1450 changed, so we must change the listener to
1451 use the oIFrame element instead
1453 Event.on(oIFrame, "resize", fireTextResize);
1456 Module.textResizeInitialized = true;
1458 this.resizeMonitor = oIFrame;
1464 * Text resize monitor helper method.
1465 * Determines if the browser supports resize events on iframe content windows.
1468 * @method _supportsCWResize
1470 _supportsCWResize : function() {
1472 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1473 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1475 We don't want to start sniffing for patch versions, so fire textResize the same
1476 way on all FF2 flavors
1478 var bSupported = true;
1479 if (UA.gecko && UA.gecko <= 1.8) {
1486 * Event handler fired when the resize monitor element is resized.
1487 * @method onDomResize
1488 * @param {DOMEvent} e The DOM resize event
1489 * @param {Object} obj The scope object passed to the handler
1491 onDomResize: function (e, obj) {
1493 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1495 this.resizeMonitor.style.top = nTop + "px";
1496 this.resizeMonitor.style.left = "0";
1500 * Sets the Module's header content to the string specified, or appends
1501 * the passed element to the header. If no header is present, one will
1502 * be automatically created. An empty string can be passed to the method
1503 * to clear the contents of the header.
1506 * @param {String} headerContent The string used to set the header.
1507 * As a convenience, non HTMLElement objects can also be passed into
1508 * the method, and will be treated as strings, with the header innerHTML
1509 * set to their default toString implementations.
1511 * @param {HTMLElement} headerContent The HTMLElement to append to
1513 * @param {DocumentFragment} headerContent The document fragment
1514 * containing elements which are to be added to the header
1516 setHeader: function (headerContent) {
1517 var oHeader = this.header || (this.header = createHeader());
1519 if (headerContent.nodeName) {
1520 oHeader.innerHTML = "";
1521 oHeader.appendChild(headerContent);
1523 oHeader.innerHTML = headerContent;
1526 if (this._rendered) {
1527 this._renderHeader();
1530 this.changeHeaderEvent.fire(headerContent);
1531 this.changeContentEvent.fire();
1536 * Appends the passed element to the header. If no header is present,
1537 * one will be automatically created.
1538 * @method appendToHeader
1539 * @param {HTMLElement | DocumentFragment} element The element to
1540 * append to the header. In the case of a document fragment, the
1541 * children of the fragment will be appended to the header.
1543 appendToHeader: function (element) {
1544 var oHeader = this.header || (this.header = createHeader());
1546 oHeader.appendChild(element);
1548 this.changeHeaderEvent.fire(element);
1549 this.changeContentEvent.fire();
1554 * Sets the Module's body content to the HTML specified.
1556 * If no body is present, one will be automatically created.
1558 * An empty string can be passed to the method to clear the contents of the body.
1560 * @param {String} bodyContent The HTML used to set the body.
1561 * As a convenience, non HTMLElement objects can also be passed into
1562 * the method, and will be treated as strings, with the body innerHTML
1563 * set to their default toString implementations.
1565 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1566 * child of the body element.
1568 * @param {DocumentFragment} bodyContent The document fragment
1569 * containing elements which are to be added to the body
1571 setBody: function (bodyContent) {
1572 var oBody = this.body || (this.body = createBody());
1574 if (bodyContent.nodeName) {
1575 oBody.innerHTML = "";
1576 oBody.appendChild(bodyContent);
1578 oBody.innerHTML = bodyContent;
1581 if (this._rendered) {
1585 this.changeBodyEvent.fire(bodyContent);
1586 this.changeContentEvent.fire();
1590 * Appends the passed element to the body. If no body is present, one
1591 * will be automatically created.
1592 * @method appendToBody
1593 * @param {HTMLElement | DocumentFragment} element The element to
1594 * append to the body. In the case of a document fragment, the
1595 * children of the fragment will be appended to the body.
1598 appendToBody: function (element) {
1599 var oBody = this.body || (this.body = createBody());
1601 oBody.appendChild(element);
1603 this.changeBodyEvent.fire(element);
1604 this.changeContentEvent.fire();
1609 * Sets the Module's footer content to the HTML specified, or appends
1610 * the passed element to the footer. If no footer is present, one will
1611 * be automatically created. An empty string can be passed to the method
1612 * to clear the contents of the footer.
1614 * @param {String} footerContent The HTML used to set the footer
1615 * As a convenience, non HTMLElement objects can also be passed into
1616 * the method, and will be treated as strings, with the footer innerHTML
1617 * set to their default toString implementations.
1619 * @param {HTMLElement} footerContent The HTMLElement to append to
1622 * @param {DocumentFragment} footerContent The document fragment containing
1623 * elements which are to be added to the footer
1625 setFooter: function (footerContent) {
1627 var oFooter = this.footer || (this.footer = createFooter());
1629 if (footerContent.nodeName) {
1630 oFooter.innerHTML = "";
1631 oFooter.appendChild(footerContent);
1633 oFooter.innerHTML = footerContent;
1636 if (this._rendered) {
1637 this._renderFooter();
1640 this.changeFooterEvent.fire(footerContent);
1641 this.changeContentEvent.fire();
1645 * Appends the passed element to the footer. If no footer is present,
1646 * one will be automatically created.
1647 * @method appendToFooter
1648 * @param {HTMLElement | DocumentFragment} element The element to
1649 * append to the footer. In the case of a document fragment, the
1650 * children of the fragment will be appended to the footer
1652 appendToFooter: function (element) {
1654 var oFooter = this.footer || (this.footer = createFooter());
1656 oFooter.appendChild(element);
1658 this.changeFooterEvent.fire(element);
1659 this.changeContentEvent.fire();
1664 * Renders the Module by inserting the elements that are not already
1665 * in the main Module into their correct places. Optionally appends
1666 * the Module to the specified node prior to the render's execution.
1668 * For Modules without existing markup, the appendToNode argument
1669 * is REQUIRED. If this argument is ommitted and the current element is
1670 * not present in the document, the function will return false,
1671 * indicating that the render was a failure.
1674 * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1675 * then the module is rendered as the first child of the body element,
1676 * and not appended to it, to avoid Operation Aborted errors in IE when
1677 * rendering the module before window's load event is fired. You can
1678 * use the appendtodocumentbody configuration property to change this
1679 * to append to document.body if required.
1682 * @param {String} appendToNode The element id to which the Module
1683 * should be appended to prior to rendering <em>OR</em>
1684 * @param {HTMLElement} appendToNode The element to which the Module
1685 * should be appended to prior to rendering
1686 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1687 * represents the actual Standard Module container.
1688 * @return {Boolean} Success or failure of the render
1690 render: function (appendToNode, moduleElement) {
1694 function appendTo(parentNode) {
1695 if (typeof parentNode == "string") {
1696 parentNode = document.getElementById(parentNode);
1700 me._addToParent(parentNode, me.element);
1701 me.appendEvent.fire();
1705 this.beforeRenderEvent.fire();
1707 if (! moduleElement) {
1708 moduleElement = this.element;
1712 appendTo(appendToNode);
1714 // No node was passed in. If the element is not already in the Dom, this fails
1715 if (! Dom.inDocument(this.element)) {
1716 YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
1721 this._renderHeader(moduleElement);
1722 this._renderBody(moduleElement);
1723 this._renderFooter(moduleElement);
1725 this._rendered = true;
1727 this.renderEvent.fire();
1732 * Renders the currently set header into it's proper position under the
1733 * module element. If the module element is not provided, "this.element"
1736 * @method _renderHeader
1738 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1740 _renderHeader: function(moduleElement){
1741 moduleElement = moduleElement || this.element;
1743 // Need to get everything into the DOM if it isn't already
1744 if (this.header && !Dom.inDocument(this.header)) {
1745 // There is a header, but it's not in the DOM yet. Need to add it.
1746 var firstChild = moduleElement.firstChild;
1748 moduleElement.insertBefore(this.header, firstChild);
1750 moduleElement.appendChild(this.header);
1756 * Renders the currently set body into it's proper position under the
1757 * module element. If the module element is not provided, "this.element"
1760 * @method _renderBody
1762 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1764 _renderBody: function(moduleElement){
1765 moduleElement = moduleElement || this.element;
1767 if (this.body && !Dom.inDocument(this.body)) {
1768 // There is a body, but it's not in the DOM yet. Need to add it.
1769 if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1770 moduleElement.insertBefore(this.body, this.footer);
1772 moduleElement.appendChild(this.body);
1778 * Renders the currently set footer into it's proper position under the
1779 * module element. If the module element is not provided, "this.element"
1782 * @method _renderFooter
1784 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1786 _renderFooter: function(moduleElement){
1787 moduleElement = moduleElement || this.element;
1789 if (this.footer && !Dom.inDocument(this.footer)) {
1790 // There is a footer, but it's not in the DOM yet. Need to add it.
1791 moduleElement.appendChild(this.footer);
1796 * Removes the Module element from the DOM and sets all child elements
1800 destroy: function () {
1805 Event.purgeElement(this.element, true);
1806 parent = this.element.parentNode;
1810 parent.removeChild(this.element);
1813 this.element = null;
1818 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1823 this.destroyEvent.fire();
1827 * Shows the Module element by setting the visible configuration
1828 * property to true. Also fires two events: beforeShowEvent prior to
1829 * the visibility change, and showEvent after.
1833 this.cfg.setProperty("visible", true);
1837 * Hides the Module element by setting the visible configuration
1838 * property to false. Also fires two events: beforeHideEvent prior to
1839 * the visibility change, and hideEvent after.
1843 this.cfg.setProperty("visible", false);
1846 // BUILT-IN EVENT HANDLERS FOR MODULE //
1848 * Default event handler for changing the visibility property of a
1849 * Module. By default, this is achieved by switching the "display" style
1850 * between "block" and "none".
1851 * This method is responsible for firing showEvent and hideEvent.
1852 * @param {String} type The CustomEvent type (usually the property name)
1853 * @param {Object[]} args The CustomEvent arguments. For configuration
1854 * handlers, args[0] will equal the newly applied value for the property.
1855 * @param {Object} obj The scope object. For configuration handlers,
1856 * this will usually equal the owner.
1857 * @method configVisible
1859 configVisible: function (type, args, obj) {
1860 var visible = args[0];
1862 this.beforeShowEvent.fire();
1863 Dom.setStyle(this.element, "display", "block");
1864 this.showEvent.fire();
1866 this.beforeHideEvent.fire();
1867 Dom.setStyle(this.element, "display", "none");
1868 this.hideEvent.fire();
1873 * Default event handler for the "monitorresize" configuration property
1874 * @param {String} type The CustomEvent type (usually the property name)
1875 * @param {Object[]} args The CustomEvent arguments. For configuration
1876 * handlers, args[0] will equal the newly applied value for the property.
1877 * @param {Object} obj The scope object. For configuration handlers,
1878 * this will usually equal the owner.
1879 * @method configMonitorResize
1881 configMonitorResize: function (type, args, obj) {
1882 var monitor = args[0];
1884 this.initResizeMonitor();
1886 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1887 this.resizeMonitor = null;
1892 * This method is a protected helper, used when constructing the DOM structure for the module
1893 * to account for situations which may cause Operation Aborted errors in IE. It should not
1894 * be used for general DOM construction.
1896 * If the parentNode is not document.body, the element is appended as the last element.
1899 * If the parentNode is document.body the element is added as the first child to help
1900 * prevent Operation Aborted errors in IE.
1903 * @param {parentNode} The HTML element to which the element will be added
1904 * @param {element} The HTML element to be added to parentNode's children
1905 * @method _addToParent
1908 _addToParent: function(parentNode, element) {
1909 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1910 parentNode.insertBefore(element, parentNode.firstChild);
1912 parentNode.appendChild(element);
1917 * Returns a String representation of the Object.
1919 * @return {String} The string representation of the Module
1921 toString: function () {
1922 return "Module " + this.id;
1926 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1932 * Overlay is a Module that is absolutely positioned above the page flow. It
1933 * has convenience methods for positioning and sizing, as well as options for
1934 * controlling zIndex and constraining the Overlay's position to the current
1935 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1936 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1937 * properly rendered above SELECT elements.
1938 * @namespace YAHOO.widget
1940 * @extends YAHOO.widget.Module
1941 * @param {String} el The element ID representing the Overlay <em>OR</em>
1942 * @param {HTMLElement} el The element representing the Overlay
1943 * @param {Object} userConfig The configuration object literal containing
1944 * the configuration that should be set for this Overlay. See configuration
1945 * documentation for more details.
1948 YAHOO.widget.Overlay = function (el, userConfig) {
1949 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1952 var Lang = YAHOO.lang,
1953 CustomEvent = YAHOO.util.CustomEvent,
1954 Module = YAHOO.widget.Module,
1955 Event = YAHOO.util.Event,
1956 Dom = YAHOO.util.Dom,
1957 Config = YAHOO.util.Config,
1959 Overlay = YAHOO.widget.Overlay,
1961 _SUBSCRIBE = "subscribe",
1962 _UNSUBSCRIBE = "unsubscribe",
1963 _CONTAINED = "contained",
1968 * Constant representing the name of the Overlay's events
1969 * @property EVENT_TYPES
1975 "BEFORE_MOVE": "beforeMove",
1980 * Constant representing the Overlay's configuration properties
1981 * @property DEFAULT_CONFIG
1990 validator: Lang.isNumber,
1991 suppressEvent: true,
1992 supercedes: ["iframe"]
1997 validator: Lang.isNumber,
1998 suppressEvent: true,
1999 supercedes: ["iframe"]
2004 suppressEvent: true,
2005 supercedes: ["iframe"]
2010 suppressEvent: true,
2011 supercedes: ["iframe"]
2017 supercedes: ["iframe", "visible"]
2022 suppressEvent: true,
2023 supercedes: ["context", "fixedcenter", "iframe"]
2028 suppressEvent: true,
2029 supercedes: ["context", "fixedcenter", "iframe"]
2032 "AUTO_FILL_HEIGHT" : {
2033 key: "autofillheight",
2034 supercedes: ["height"],
2043 "CONSTRAIN_TO_VIEWPORT": {
2044 key: "constraintoviewport",
2046 validator: Lang.isBoolean,
2047 supercedes: ["iframe", "x", "y", "xy"]
2052 value: (UA.ie == 6 ? true : false),
2053 validator: Lang.isBoolean,
2054 supercedes: ["zindex"]
2057 "PREVENT_CONTEXT_OVERLAP": {
2058 key: "preventcontextoverlap",
2060 validator: Lang.isBoolean,
2061 supercedes: ["constraintoviewport"]
2067 * The URL that will be placed in the iframe
2068 * @property YAHOO.widget.Overlay.IFRAME_SRC
2073 Overlay.IFRAME_SRC = "javascript:false;";
2076 * Number representing how much the iframe shim should be offset from each
2077 * side of an Overlay instance, in pixels.
2078 * @property YAHOO.widget.Overlay.IFRAME_SRC
2084 Overlay.IFRAME_OFFSET = 3;
2087 * Number representing the minimum distance an Overlay instance should be
2088 * positioned relative to the boundaries of the browser's viewport, in pixels.
2089 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2095 Overlay.VIEWPORT_OFFSET = 10;
2098 * Constant representing the top left corner of an element, used for
2099 * configuring the context element alignment
2100 * @property YAHOO.widget.Overlay.TOP_LEFT
2105 Overlay.TOP_LEFT = "tl";
2108 * Constant representing the top right corner of an element, used for
2109 * configuring the context element alignment
2110 * @property YAHOO.widget.Overlay.TOP_RIGHT
2115 Overlay.TOP_RIGHT = "tr";
2118 * Constant representing the top bottom left corner of an element, used for
2119 * configuring the context element alignment
2120 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2125 Overlay.BOTTOM_LEFT = "bl";
2128 * Constant representing the bottom right corner of an element, used for
2129 * configuring the context element alignment
2130 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2135 Overlay.BOTTOM_RIGHT = "br";
2137 Overlay.PREVENT_OVERLAP_X = {
2144 Overlay.PREVENT_OVERLAP_Y = {
2152 * Constant representing the default CSS class used for an Overlay
2153 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2158 Overlay.CSS_OVERLAY = "yui-overlay";
2161 * Constant representing the default hidden CSS class used for an Overlay. This class is
2162 * applied to the overlay's outer DIV whenever it's hidden.
2164 * @property YAHOO.widget.Overlay.CSS_HIDDEN
2169 Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2172 * Constant representing the default CSS class used for an Overlay iframe shim.
2174 * @property YAHOO.widget.Overlay.CSS_IFRAME
2179 Overlay.CSS_IFRAME = "yui-overlay-iframe";
2182 * Constant representing the names of the standard module elements
2183 * used in the overlay.
2184 * @property YAHOO.widget.Overlay.STD_MOD_RE
2189 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2192 * A singleton CustomEvent used for reacting to the DOM event for
2194 * @event YAHOO.widget.Overlay.windowScrollEvent
2196 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2199 * A singleton CustomEvent used for reacting to the DOM event for
2201 * @event YAHOO.widget.Overlay.windowResizeEvent
2203 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2206 * The DOM event handler used to fire the CustomEvent for window scroll
2207 * @method YAHOO.widget.Overlay.windowScrollHandler
2209 * @param {DOMEvent} e The DOM scroll event
2211 Overlay.windowScrollHandler = function (e) {
2212 var t = Event.getTarget(e);
2214 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2215 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2216 // - IE doesn't recognize scroll registered on the document.
2218 // Also, when document view is scrolled, IE doesn't provide a target,
2219 // rest of the browsers set target to window.document, apart from opera
2220 // which sets target to window.
2221 if (!t || t === window || t === window.document) {
2224 if (! window.scrollEnd) {
2225 window.scrollEnd = -1;
2228 clearTimeout(window.scrollEnd);
2230 window.scrollEnd = setTimeout(function () {
2231 Overlay.windowScrollEvent.fire();
2235 Overlay.windowScrollEvent.fire();
2241 * The DOM event handler used to fire the CustomEvent for window resize
2242 * @method YAHOO.widget.Overlay.windowResizeHandler
2244 * @param {DOMEvent} e The DOM resize event
2246 Overlay.windowResizeHandler = function (e) {
2249 if (! window.resizeEnd) {
2250 window.resizeEnd = -1;
2253 clearTimeout(window.resizeEnd);
2255 window.resizeEnd = setTimeout(function () {
2256 Overlay.windowResizeEvent.fire();
2259 Overlay.windowResizeEvent.fire();
2264 * A boolean that indicated whether the window resize and scroll events have
2265 * already been subscribed to.
2266 * @property YAHOO.widget.Overlay._initialized
2270 Overlay._initialized = null;
2272 if (Overlay._initialized === null) {
2273 Event.on(window, "scroll", Overlay.windowScrollHandler);
2274 Event.on(window, "resize", Overlay.windowResizeHandler);
2275 Overlay._initialized = true;
2279 * Internal map of special event types, which are provided
2280 * by the instance. It maps the event type to the custom event
2281 * instance. Contains entries for the "windowScroll", "windowResize" and
2282 * "textResize" static container events.
2284 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2289 Overlay._TRIGGER_MAP = {
2290 "windowScroll" : Overlay.windowScrollEvent,
2291 "windowResize" : Overlay.windowResizeEvent,
2292 "textResize" : Module.textResizeEvent
2295 YAHOO.extend(Overlay, Module, {
2299 * Array of default event types which will trigger
2300 * context alignment for the Overlay class.
2302 * <p>The array is empty by default for Overlay,
2303 * but maybe populated in future releases, so classes extending
2304 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2305 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2306 * value with their own array of values.
2310 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2313 * @property CONTEXT_TRIGGERS
2317 CONTEXT_TRIGGERS : [],
2320 * The Overlay initialization method, which is executed for Overlay and
2321 * all of its subclasses. This method is automatically called by the
2322 * constructor, and sets up all DOM references for pre-existing markup,
2323 * and creates required markup if it is not already present.
2325 * @param {String} el The element ID representing the Overlay <em>OR</em>
2326 * @param {HTMLElement} el The element representing the Overlay
2327 * @param {Object} userConfig The configuration object literal
2328 * containing the configuration that should be set for this Overlay.
2329 * See configuration documentation for more details.
2331 init: function (el, userConfig) {
2334 Note that we don't pass the user config in here yet because we
2335 only want it executed once, at the lowest subclass level
2338 Overlay.superclass.init.call(this, el/*, userConfig*/);
2340 this.beforeInitEvent.fire(Overlay);
2342 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2345 this.cfg.applyConfig(userConfig, true);
2348 if (this.platform == "mac" && UA.gecko) {
2350 if (! Config.alreadySubscribed(this.showEvent,
2351 this.showMacGeckoScrollbars, this)) {
2353 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2358 if (! Config.alreadySubscribed(this.hideEvent,
2359 this.hideMacGeckoScrollbars, this)) {
2361 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2367 this.initEvent.fire(Overlay);
2371 * Initializes the custom events for Overlay which are fired
2372 * automatically at appropriate times by the Overlay class.
2373 * @method initEvents
2375 initEvents: function () {
2377 Overlay.superclass.initEvents.call(this);
2379 var SIGNATURE = CustomEvent.LIST;
2382 * CustomEvent fired before the Overlay is moved.
2383 * @event beforeMoveEvent
2384 * @param {Number} x x coordinate
2385 * @param {Number} y y coordinate
2387 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2388 this.beforeMoveEvent.signature = SIGNATURE;
2391 * CustomEvent fired after the Overlay is moved.
2393 * @param {Number} x x coordinate
2394 * @param {Number} y y coordinate
2396 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2397 this.moveEvent.signature = SIGNATURE;
2402 * Initializes the class's configurable properties which can be changed
2403 * using the Overlay's Config object (cfg).
2404 * @method initDefaultConfig
2406 initDefaultConfig: function () {
2408 Overlay.superclass.initDefaultConfig.call(this);
2412 // Add overlay config properties //
2415 * The absolute x-coordinate position of the Overlay
2420 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2422 handler: this.configX,
2423 validator: DEFAULT_CONFIG.X.validator,
2424 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2425 supercedes: DEFAULT_CONFIG.X.supercedes
2430 * The absolute y-coordinate position of the Overlay
2435 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2437 handler: this.configY,
2438 validator: DEFAULT_CONFIG.Y.validator,
2439 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2440 supercedes: DEFAULT_CONFIG.Y.supercedes
2445 * An array with the absolute x and y positions of the Overlay
2450 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2451 handler: this.configXY,
2452 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2453 supercedes: DEFAULT_CONFIG.XY.supercedes
2458 * The array of context arguments for context-sensitive positioning.
2462 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2463 * the 5 array elements described in detail below:
2467 * <dt>contextElementOrId <String|HTMLElement></dt>
2468 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2469 * <dt>overlayCorner <String></dt>
2470 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2471 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2472 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2473 * <dt>contextCorner <String></dt>
2474 * <dd>The corner of the context element which is to be used for alignment. Supported string values are the same ones listed for the "overlayCorner" entry above.</dd>
2475 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2478 * By default, context alignment is a one time operation, aligning the Overlay to the context element when context configuration property is set, or when the <a href="#method_align">align</a>
2479 * method is invoked. However, you can use the optional "arrayOfTriggerEvents" entry to define the list of events which should force the overlay to re-align itself with the context element.
2480 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2483 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2484 * 3 static container event types are also currently supported : <code>"windowResize", "windowScroll", "textResize"</code> (defined in <a href="#property__TRIGGER_MAP">_TRIGGER_MAP</a> private property).
2487 * <dt>xyOffset <Number[]></dt>
2489 * A 2 element Array specifying the X and Y pixel amounts by which the Overlay should be offset from the aligned corner. e.g. [5,0] offsets the Overlay 5 pixels to the left, <em>after</em> aligning the given context corners.
2490 * NOTE: If using this property and no triggers need to be defined, the arrayOfTriggerEvents property should be set to null to maintain correct array positions for the arguments.
2495 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2496 * align the Overlay's top left corner to the bottom left corner of the
2497 * context element with id "img1".
2500 * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
2501 * align the Overlay's top left corner to the bottom left corner of the
2502 * context element with id "img1", and then offset it by 5 pixels on the Y axis (providing a 5 pixel gap between the bottom of the context element and top of the overlay).
2505 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2506 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2513 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2514 handler: this.configContext,
2515 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2516 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2520 * Determines whether or not the Overlay should be anchored
2521 * to the center of the viewport.
2523 * <p>This property can be set to:</p>
2528 * To enable fixed center positioning
2530 * When enabled, the overlay will
2531 * be positioned in the center of viewport when initially displayed, and
2532 * will remain in the center of the viewport whenever the window is
2533 * scrolled or resized.
2536 * If the overlay is too big for the viewport,
2537 * it's top left corner will be aligned with the top left corner of the viewport.
2542 * To disable fixed center positioning.
2543 * <p>In this case the overlay can still be
2544 * centered as a one-off operation, by invoking the <code>center()</code> method,
2545 * however it will not remain centered when the window is scrolled/resized.
2547 * <dt>"contained"<dt>
2548 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2549 * <p>However, unlike setting the property to <code>true</code>,
2550 * when the property is set to <code>"contained"</code>, if the overlay is
2551 * too big for the viewport, it will not get automatically centered when the
2552 * user scrolls or resizes the window (until the window is large enough to contain the
2553 * overlay). This is useful in cases where the Overlay has both header and footer
2554 * UI controls which the user may need to access.
2559 * @config fixedcenter
2560 * @type Boolean | String
2563 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2564 handler: this.configFixedCenter,
2565 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2566 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2567 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2571 * CSS width of the Overlay.
2576 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2577 handler: this.configWidth,
2578 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2579 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2583 * CSS height of the Overlay.
2588 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2589 handler: this.configHeight,
2590 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2591 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2595 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2596 * Supported values are "header", "body", "footer".
2598 * @config autofillheight
2602 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2603 handler: this.configAutoFillHeight,
2604 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2605 validator : this._validateAutoFill,
2606 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2610 * CSS z-index of the Overlay.
2615 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2616 handler: this.configzIndex,
2617 value: DEFAULT_CONFIG.ZINDEX.value
2621 * True if the Overlay should be prevented from being positioned
2622 * out of the viewport.
2623 * @config constraintoviewport
2627 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2629 handler: this.configConstrainToViewport,
2630 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2631 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2632 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2638 * @description Boolean indicating whether or not the Overlay should
2639 * have an IFRAME shim; used to prevent SELECT elements from
2640 * poking through an Overlay instance in IE6. When set to "true",
2641 * the iframe shim is created when the Overlay instance is intially
2644 * @default true for IE6 and below, false for all other browsers.
2646 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2648 handler: this.configIframe,
2649 value: DEFAULT_CONFIG.IFRAME.value,
2650 validator: DEFAULT_CONFIG.IFRAME.validator,
2651 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2656 * @config preventcontextoverlap
2657 * @description Boolean indicating whether or not the Overlay should overlap its
2658 * context element (defined using the "context" configuration property) when the
2659 * "constraintoviewport" configuration property is set to "true".
2663 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2664 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2665 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2666 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2671 * Moves the Overlay to the specified position. This function is
2672 * identical to calling this.cfg.setProperty("xy", [x,y]);
2674 * @param {Number} x The Overlay's new x position
2675 * @param {Number} y The Overlay's new y position
2677 moveTo: function (x, y) {
2678 this.cfg.setProperty("xy", [x, y]);
2682 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2683 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2684 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2685 * @method hideMacGeckoScrollbars
2687 hideMacGeckoScrollbars: function () {
2688 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2692 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2693 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2694 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2695 * @method showMacGeckoScrollbars
2697 showMacGeckoScrollbars: function () {
2698 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2702 * Internal implementation to set the visibility of the overlay in the DOM.
2704 * @method _setDomVisibility
2705 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2708 _setDomVisibility : function(show) {
2709 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2710 var hiddenClass = Overlay.CSS_HIDDEN;
2713 Dom.removeClass(this.element, hiddenClass);
2715 Dom.addClass(this.element, hiddenClass);
2719 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2721 * The default event handler fired when the "visible" property is
2722 * changed. This method is responsible for firing showEvent
2724 * @method configVisible
2725 * @param {String} type The CustomEvent type (usually the property name)
2726 * @param {Object[]} args The CustomEvent arguments. For configuration
2727 * handlers, args[0] will equal the newly applied value for the property.
2728 * @param {Object} obj The scope object. For configuration handlers,
2729 * this will usually equal the owner.
2731 configVisible: function (type, args, obj) {
2733 var visible = args[0],
2734 currentVis = Dom.getStyle(this.element, "visibility"),
2735 effect = this.cfg.getProperty("effect"),
2736 effectInstances = [],
2737 isMacGecko = (this.platform == "mac" && UA.gecko),
2738 alreadySubscribed = Config.alreadySubscribed,
2739 eff, ei, e, i, j, k, h,
2743 if (currentVis == "inherit") {
2744 e = this.element.parentNode;
2746 while (e.nodeType != 9 && e.nodeType != 11) {
2747 currentVis = Dom.getStyle(e, "visibility");
2749 if (currentVis != "inherit") {
2756 if (currentVis == "inherit") {
2757 currentVis = "visible";
2762 if (effect instanceof Array) {
2763 nEffects = effect.length;
2765 for (i = 0; i < nEffects; i++) {
2767 effectInstances[effectInstances.length] =
2768 eff.effect(this, eff.duration);
2772 effectInstances[effectInstances.length] =
2773 effect.effect(this, effect.duration);
2777 if (visible) { // Show
2779 this.showMacGeckoScrollbars();
2782 if (effect) { // Animate in
2783 if (visible) { // Animate in if not showing
2784 if (currentVis != "visible" || currentVis === "") {
2785 this.beforeShowEvent.fire();
2786 nEffectInstances = effectInstances.length;
2788 for (j = 0; j < nEffectInstances; j++) {
2789 ei = effectInstances[j];
2790 if (j === 0 && !alreadySubscribed(
2791 ei.animateInCompleteEvent,
2792 this.showEvent.fire, this.showEvent)) {
2795 Delegate showEvent until end
2796 of animateInComplete
2799 ei.animateInCompleteEvent.subscribe(
2800 this.showEvent.fire, this.showEvent, true);
2807 if (currentVis != "visible" || currentVis === "") {
2808 this.beforeShowEvent.fire();
2810 this._setDomVisibility(true);
2812 this.cfg.refireEvent("iframe");
2813 this.showEvent.fire();
2815 this._setDomVisibility(true);
2821 this.hideMacGeckoScrollbars();
2824 if (effect) { // Animate out if showing
2825 if (currentVis == "visible") {
2826 this.beforeHideEvent.fire();
2828 nEffectInstances = effectInstances.length;
2829 for (k = 0; k < nEffectInstances; k++) {
2830 h = effectInstances[k];
2832 if (k === 0 && !alreadySubscribed(
2833 h.animateOutCompleteEvent, this.hideEvent.fire,
2837 Delegate hideEvent until end
2838 of animateOutComplete
2841 h.animateOutCompleteEvent.subscribe(
2842 this.hideEvent.fire, this.hideEvent, true);
2848 } else if (currentVis === "") {
2849 this._setDomVisibility(false);
2852 } else { // Simple hide
2854 if (currentVis == "visible" || currentVis === "") {
2855 this.beforeHideEvent.fire();
2856 this._setDomVisibility(false);
2857 this.hideEvent.fire();
2859 this._setDomVisibility(false);
2866 * Fixed center event handler used for centering on scroll/resize, but only if
2867 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2868 * the overlay fits within the viewport.
2870 * @method doCenterOnDOMEvent
2872 doCenterOnDOMEvent: function () {
2874 fc = cfg.getProperty("fixedcenter");
2876 if (cfg.getProperty("visible")) {
2877 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2884 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2885 * will fit entirely inside the viewport, in both dimensions - width and height.
2887 * @method fitsInViewport
2888 * @return boolean true if the Overlay will fit, false if not
2890 fitsInViewport : function() {
2891 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2892 element = this.element,
2893 elementWidth = element.offsetWidth,
2894 elementHeight = element.offsetHeight,
2895 viewportWidth = Dom.getViewportWidth(),
2896 viewportHeight = Dom.getViewportHeight();
2898 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2902 * The default event handler fired when the "fixedcenter" property
2904 * @method configFixedCenter
2905 * @param {String} type The CustomEvent type (usually the property name)
2906 * @param {Object[]} args The CustomEvent arguments. For configuration
2907 * handlers, args[0] will equal the newly applied value for the property.
2908 * @param {Object} obj The scope object. For configuration handlers,
2909 * this will usually equal the owner.
2911 configFixedCenter: function (type, args, obj) {
2914 alreadySubscribed = Config.alreadySubscribed,
2915 windowResizeEvent = Overlay.windowResizeEvent,
2916 windowScrollEvent = Overlay.windowScrollEvent;
2921 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2922 this.beforeShowEvent.subscribe(this.center);
2925 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2926 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2929 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2930 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2934 this.beforeShowEvent.unsubscribe(this.center);
2936 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2937 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2942 * The default event handler fired when the "height" property is changed.
2943 * @method configHeight
2944 * @param {String} type The CustomEvent type (usually the property name)
2945 * @param {Object[]} args The CustomEvent arguments. For configuration
2946 * handlers, args[0] will equal the newly applied value for the property.
2947 * @param {Object} obj The scope object. For configuration handlers,
2948 * this will usually equal the owner.
2950 configHeight: function (type, args, obj) {
2952 var height = args[0],
2955 Dom.setStyle(el, "height", height);
2956 this.cfg.refireEvent("iframe");
2960 * The default event handler fired when the "autofillheight" property is changed.
2961 * @method configAutoFillHeight
2963 * @param {String} type The CustomEvent type (usually the property name)
2964 * @param {Object[]} args The CustomEvent arguments. For configuration
2965 * handlers, args[0] will equal the newly applied value for the property.
2966 * @param {Object} obj The scope object. For configuration handlers,
2967 * this will usually equal the owner.
2969 configAutoFillHeight: function (type, args, obj) {
2970 var fillEl = args[0],
2972 autoFillHeight = "autofillheight",
2974 currEl = cfg.getProperty(autoFillHeight),
2975 autoFill = this._autoFillOnHeightChange;
2977 cfg.unsubscribeFromConfigEvent(height, autoFill);
2978 Module.textResizeEvent.unsubscribe(autoFill);
2979 this.changeContentEvent.unsubscribe(autoFill);
2981 if (currEl && fillEl !== currEl && this[currEl]) {
2982 Dom.setStyle(this[currEl], height, "");
2986 fillEl = Lang.trim(fillEl.toLowerCase());
2988 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
2989 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
2990 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
2992 cfg.setProperty(autoFillHeight, fillEl, true);
2997 * The default event handler fired when the "width" property is changed.
2998 * @method configWidth
2999 * @param {String} type The CustomEvent type (usually the property name)
3000 * @param {Object[]} args The CustomEvent arguments. For configuration
3001 * handlers, args[0] will equal the newly applied value for the property.
3002 * @param {Object} obj The scope object. For configuration handlers,
3003 * this will usually equal the owner.
3005 configWidth: function (type, args, obj) {
3007 var width = args[0],
3010 Dom.setStyle(el, "width", width);
3011 this.cfg.refireEvent("iframe");
3015 * The default event handler fired when the "zIndex" property is changed.
3016 * @method configzIndex
3017 * @param {String} type The CustomEvent type (usually the property name)
3018 * @param {Object[]} args The CustomEvent arguments. For configuration
3019 * handlers, args[0] will equal the newly applied value for the property.
3020 * @param {Object} obj The scope object. For configuration handlers,
3021 * this will usually equal the owner.
3023 configzIndex: function (type, args, obj) {
3025 var zIndex = args[0],
3029 zIndex = Dom.getStyle(el, "zIndex");
3030 if (! zIndex || isNaN(zIndex)) {
3035 if (this.iframe || this.cfg.getProperty("iframe") === true) {
3041 Dom.setStyle(el, "zIndex", zIndex);
3042 this.cfg.setProperty("zIndex", zIndex, true);
3050 * The default event handler fired when the "xy" property is changed.
3052 * @param {String} type The CustomEvent type (usually the property name)
3053 * @param {Object[]} args The CustomEvent arguments. For configuration
3054 * handlers, args[0] will equal the newly applied value for the property.
3055 * @param {Object} obj The scope object. For configuration handlers,
3056 * this will usually equal the owner.
3058 configXY: function (type, args, obj) {
3064 this.cfg.setProperty("x", x);
3065 this.cfg.setProperty("y", y);
3067 this.beforeMoveEvent.fire([x, y]);
3069 x = this.cfg.getProperty("x");
3070 y = this.cfg.getProperty("y");
3072 YAHOO.log(("xy: " + [x, y]), "iframe");
3074 this.cfg.refireEvent("iframe");
3075 this.moveEvent.fire([x, y]);
3079 * The default event handler fired when the "x" property is changed.
3081 * @param {String} type The CustomEvent type (usually the property name)
3082 * @param {Object[]} args The CustomEvent arguments. For configuration
3083 * handlers, args[0] will equal the newly applied value for the property.
3084 * @param {Object} obj The scope object. For configuration handlers,
3085 * this will usually equal the owner.
3087 configX: function (type, args, obj) {
3090 y = this.cfg.getProperty("y");
3092 this.cfg.setProperty("x", x, true);
3093 this.cfg.setProperty("y", y, true);
3095 this.beforeMoveEvent.fire([x, y]);
3097 x = this.cfg.getProperty("x");
3098 y = this.cfg.getProperty("y");
3100 Dom.setX(this.element, x, true);
3102 this.cfg.setProperty("xy", [x, y], true);
3104 this.cfg.refireEvent("iframe");
3105 this.moveEvent.fire([x, y]);
3109 * The default event handler fired when the "y" property is changed.
3111 * @param {String} type The CustomEvent type (usually the property name)
3112 * @param {Object[]} args The CustomEvent arguments. For configuration
3113 * handlers, args[0] will equal the newly applied value for the property.
3114 * @param {Object} obj The scope object. For configuration handlers,
3115 * this will usually equal the owner.
3117 configY: function (type, args, obj) {
3119 var x = this.cfg.getProperty("x"),
3122 this.cfg.setProperty("x", x, true);
3123 this.cfg.setProperty("y", y, true);
3125 this.beforeMoveEvent.fire([x, y]);
3127 x = this.cfg.getProperty("x");
3128 y = this.cfg.getProperty("y");
3130 Dom.setY(this.element, y, true);
3132 this.cfg.setProperty("xy", [x, y], true);
3134 this.cfg.refireEvent("iframe");
3135 this.moveEvent.fire([x, y]);
3139 * Shows the iframe shim, if it has been enabled.
3140 * @method showIframe
3142 showIframe: function () {
3144 var oIFrame = this.iframe,
3148 oParentNode = this.element.parentNode;
3150 if (oParentNode != oIFrame.parentNode) {
3151 this._addToParent(oParentNode, oIFrame);
3153 oIFrame.style.display = "block";
3158 * Hides the iframe shim, if it has been enabled.
3159 * @method hideIframe
3161 hideIframe: function () {
3163 this.iframe.style.display = "none";
3168 * Syncronizes the size and position of iframe shim to that of its
3169 * corresponding Overlay instance.
3170 * @method syncIframe
3172 syncIframe: function () {
3174 var oIFrame = this.iframe,
3175 oElement = this.element,
3176 nOffset = Overlay.IFRAME_OFFSET,
3177 nDimensionOffset = (nOffset * 2),
3182 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3183 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3185 // Position <iframe>
3186 aXY = this.cfg.getProperty("xy");
3188 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3189 this.syncPosition();
3190 aXY = this.cfg.getProperty("xy");
3192 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3197 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3198 * the Overlay element. The zindex of the iframe is set to be one less
3199 * than the Overlay element's zindex.
3201 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3202 * to ensure that the iframe shim has a non-negative zindex.
3203 * If you require the iframe zindex to be 0 or higher, the zindex of
3204 * the Overlay element should be set to a value greater than 0, before
3205 * this method is called.
3207 * @method stackIframe
3209 stackIframe: function () {
3211 var overlayZ = Dom.getStyle(this.element, "zIndex");
3212 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3213 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3219 * The default event handler fired when the "iframe" property is changed.
3220 * @method configIframe
3221 * @param {String} type The CustomEvent type (usually the property name)
3222 * @param {Object[]} args The CustomEvent arguments. For configuration
3223 * handlers, args[0] will equal the newly applied value for the property.
3224 * @param {Object} obj The scope object. For configuration handlers,
3225 * this will usually equal the owner.
3227 configIframe: function (type, args, obj) {
3229 var bIFrame = args[0];
3231 function createIFrame() {
3233 var oIFrame = this.iframe,
3234 oElement = this.element,
3238 if (!m_oIFrameTemplate) {
3239 m_oIFrameTemplate = document.createElement("iframe");
3241 if (this.isSecure) {
3242 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3246 Set the opacity of the <iframe> to 0 so that it
3247 doesn't modify the opacity of any transparent
3248 elements that may be on top of it (like a shadow).
3251 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3253 Need to set the "frameBorder" property to 0
3254 supress the default <iframe> border in IE.
3255 Setting the CSS "border" property alone
3258 m_oIFrameTemplate.frameBorder = 0;
3261 m_oIFrameTemplate.style.opacity = "0";
3264 m_oIFrameTemplate.style.position = "absolute";
3265 m_oIFrameTemplate.style.border = "none";
3266 m_oIFrameTemplate.style.margin = "0";
3267 m_oIFrameTemplate.style.padding = "0";
3268 m_oIFrameTemplate.style.display = "none";
3269 m_oIFrameTemplate.tabIndex = -1;
3270 m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3273 oIFrame = m_oIFrameTemplate.cloneNode(false);
3274 oIFrame.id = this.id + "_f";
3275 oParent = oElement.parentNode;
3277 var parentNode = oParent || document.body;
3279 this._addToParent(parentNode, oIFrame);
3280 this.iframe = oIFrame;
3284 Show the <iframe> before positioning it since the "setXY"
3285 method of DOM requires the element be in the document
3291 Syncronize the size and position of the <iframe> to that
3297 // Add event listeners to update the <iframe> when necessary
3298 if (!this._hasIframeEventListeners) {
3299 this.showEvent.subscribe(this.showIframe);
3300 this.hideEvent.subscribe(this.hideIframe);
3301 this.changeContentEvent.subscribe(this.syncIframe);
3303 this._hasIframeEventListeners = true;
3307 function onBeforeShow() {
3308 createIFrame.call(this);
3309 this.beforeShowEvent.unsubscribe(onBeforeShow);
3310 this._iframeDeferred = false;
3313 if (bIFrame) { // <iframe> shim is enabled
3315 if (this.cfg.getProperty("visible")) {
3316 createIFrame.call(this);
3318 if (!this._iframeDeferred) {
3319 this.beforeShowEvent.subscribe(onBeforeShow);
3320 this._iframeDeferred = true;
3324 } else { // <iframe> shim is disabled
3327 if (this._hasIframeEventListeners) {
3328 this.showEvent.unsubscribe(this.showIframe);
3329 this.hideEvent.unsubscribe(this.hideIframe);
3330 this.changeContentEvent.unsubscribe(this.syncIframe);
3332 this._hasIframeEventListeners = false;
3338 * Set's the container's XY value from DOM if not already set.
3340 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3341 * not already set. The method also refire's the XY config property event, so any
3342 * beforeMove, Move event listeners are invoked.
3344 * @method _primeXYFromDOM
3347 _primeXYFromDOM : function() {
3348 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3349 // Set CFG XY based on DOM XY
3350 this.syncPosition();
3351 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3352 this.cfg.refireEvent("xy");
3353 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3358 * The default event handler fired when the "constraintoviewport"
3359 * property is changed.
3360 * @method configConstrainToViewport
3361 * @param {String} type The CustomEvent type (usually the property name)
3362 * @param {Object[]} args The CustomEvent arguments. For configuration
3363 * handlers, args[0] will equal the newly applied value for
3365 * @param {Object} obj The scope object. For configuration handlers,
3366 * this will usually equal the owner.
3368 configConstrainToViewport: function (type, args, obj) {
3372 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3373 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3375 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3376 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3379 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3380 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3385 * The default event handler fired when the "context" property
3388 * @method configContext
3389 * @param {String} type The CustomEvent type (usually the property name)
3390 * @param {Object[]} args The CustomEvent arguments. For configuration
3391 * handlers, args[0] will equal the newly applied value for the property.
3392 * @param {Object} obj The scope object. For configuration handlers,
3393 * this will usually equal the owner.
3395 configContext: function (type, args, obj) {
3397 var contextArgs = args[0],
3399 elementMagnetCorner,
3400 contextMagnetCorner,
3403 defTriggers = this.CONTEXT_TRIGGERS;
3407 contextEl = contextArgs[0];
3408 elementMagnetCorner = contextArgs[1];
3409 contextMagnetCorner = contextArgs[2];
3410 triggers = contextArgs[3];
3411 offset = contextArgs[4];
3413 if (defTriggers && defTriggers.length > 0) {
3414 triggers = (triggers || []).concat(defTriggers);
3418 if (typeof contextEl == "string") {
3419 this.cfg.setProperty("context", [
3420 document.getElementById(contextEl),
3421 elementMagnetCorner,
3422 contextMagnetCorner,
3428 if (elementMagnetCorner && contextMagnetCorner) {
3429 this.align(elementMagnetCorner, contextMagnetCorner, offset);
3432 if (this._contextTriggers) {
3433 // Unsubscribe Old Set
3434 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3438 // Subscribe New Set
3439 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3440 this._contextTriggers = triggers;
3447 * Custom Event handler for context alignment triggers. Invokes the align method
3449 * @method _alignOnTrigger
3452 * @param {String} type The event type (not used by the default implementation)
3453 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3455 _alignOnTrigger: function(type, args) {
3460 * Helper method to locate the custom event instance for the event name string
3461 * passed in. As a convenience measure, any custom events passed in are returned.
3463 * @method _findTriggerCE
3466 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3467 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3469 _findTriggerCE : function(t) {
3471 if (t instanceof CustomEvent) {
3473 } else if (Overlay._TRIGGER_MAP[t]) {
3474 tce = Overlay._TRIGGER_MAP[t];
3480 * Utility method that subscribes or unsubscribes the given
3481 * function from the list of trigger events provided.
3483 * @method _processTriggers
3486 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3487 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3488 * subscribed/unsubscribed respectively.
3490 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3491 * we are subscribing or unsubscribing trigger listeners
3493 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3494 * Context is always set to the overlay instance, and no additional object argument
3495 * get passed to the subscribed function.
3497 _processTriggers : function(triggers, mode, fn) {
3500 for (var i = 0, l = triggers.length; i < l; ++i) {
3502 tce = this._findTriggerCE(t);
3504 tce[mode](fn, this, true);
3511 // END BUILT-IN PROPERTY EVENT HANDLERS //
3513 * Aligns the Overlay to its context element using the specified corner
3514 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3517 * @param {String} elementAlign The String representing the corner of
3518 * the Overlay that should be aligned to the context element
3519 * @param {String} contextAlign The corner of the context element
3520 * that the elementAlign corner should stick to.
3521 * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3522 * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
3523 * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3525 align: function (elementAlign, contextAlign, xyOffset) {
3527 var contextArgs = this.cfg.getProperty("context"),
3533 function doAlign(v, h) {
3535 var alignX = null, alignY = null;
3537 switch (elementAlign) {
3539 case Overlay.TOP_LEFT:
3544 case Overlay.TOP_RIGHT:
3545 alignX = h - element.offsetWidth;
3549 case Overlay.BOTTOM_LEFT:
3551 alignY = v - element.offsetHeight;
3554 case Overlay.BOTTOM_RIGHT:
3555 alignX = h - element.offsetWidth;
3556 alignY = v - element.offsetHeight;
3560 if (alignX !== null && alignY !== null) {
3562 alignX += xyOffset[0];
3563 alignY += xyOffset[1];
3565 me.moveTo(alignX, alignY);
3570 context = contextArgs[0];
3571 element = this.element;
3574 if (! elementAlign) {
3575 elementAlign = contextArgs[1];
3578 if (! contextAlign) {
3579 contextAlign = contextArgs[2];
3582 if (!xyOffset && contextArgs[4]) {
3583 xyOffset = contextArgs[4];
3586 if (element && context) {
3587 contextRegion = Dom.getRegion(context);
3589 switch (contextAlign) {
3591 case Overlay.TOP_LEFT:
3592 doAlign(contextRegion.top, contextRegion.left);
3595 case Overlay.TOP_RIGHT:
3596 doAlign(contextRegion.top, contextRegion.right);
3599 case Overlay.BOTTOM_LEFT:
3600 doAlign(contextRegion.bottom, contextRegion.left);
3603 case Overlay.BOTTOM_RIGHT:
3604 doAlign(contextRegion.bottom, contextRegion.right);
3612 * The default event handler executed when the moveEvent is fired, if the
3613 * "constraintoviewport" is set to true.
3614 * @method enforceConstraints
3615 * @param {String} type The CustomEvent type (usually the property name)
3616 * @param {Object[]} args The CustomEvent arguments. For configuration
3617 * handlers, args[0] will equal the newly applied value for the property.
3618 * @param {Object} obj The scope object. For configuration handlers,
3619 * this will usually equal the owner.
3621 enforceConstraints: function (type, args, obj) {
3624 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3625 this.cfg.setProperty("x", cXY[0], true);
3626 this.cfg.setProperty("y", cXY[1], true);
3627 this.cfg.setProperty("xy", cXY, true);
3631 * Shared implementation method for getConstrainedX and getConstrainedY.
3634 * Given a coordinate value, returns the calculated coordinate required to
3635 * position the Overlay if it is to be constrained to the viewport, based on the
3636 * current element size, viewport dimensions, scroll values and preventoverlap
3640 * @method _getConstrainedPos
3642 * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3643 * @param {Number} The coordinate value which needs to be constrained
3644 * @return {Number} The constrained coordinate value
3646 _getConstrainedPos: function(pos, val) {
3648 var overlayEl = this.element,
3650 buffer = Overlay.VIEWPORT_OFFSET,
3654 overlaySize = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3655 viewportSize = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3656 docScroll = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3657 overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3659 context = this.cfg.getProperty("context"),
3661 bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3662 bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3664 minConstraint = docScroll + buffer,
3665 maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3667 constrainedVal = val;
3669 if (val < minConstraint || val > maxConstraint) {
3670 if (bPreventContextOverlap) {
3671 constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3673 if (bOverlayFitsInViewport) {
3674 if (val < minConstraint) {
3675 constrainedVal = minConstraint;
3676 } else if (val > maxConstraint) {
3677 constrainedVal = maxConstraint;
3680 constrainedVal = minConstraint;
3685 return constrainedVal;
3689 * Helper method, used to position the Overlap to prevent overlap with the
3690 * context element (used when preventcontextoverlap is enabled)
3692 * @method _preventOverlap
3694 * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3695 * @param {HTMLElement} contextEl The context element
3696 * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3697 * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3698 * @param {Object} docScroll The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3700 * @return {Number} The new coordinate value which was set to prevent overlap
3702 _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3704 var x = (pos == "x"),
3706 buffer = Overlay.VIEWPORT_OFFSET,
3710 contextElPos = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3711 contextElSize = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3713 minRegionSize = contextElPos - buffer,
3714 maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3718 flip = function () {
3721 if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3722 flippedVal = (contextElPos - overlaySize);
3724 flippedVal = (contextElPos + contextElSize);
3727 overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3732 setPosition = function () {
3734 var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3737 if (overlaySize > displayRegionSize) {
3740 All possible positions and values have been
3741 tried, but none were successful, so fall back
3742 to the original size and position.
3748 position = setPosition();
3757 return this.cfg.getProperty(pos);
3761 * Given x coordinate value, returns the calculated x coordinate required to
3762 * position the Overlay if it is to be constrained to the viewport, based on the
3763 * current element size, viewport dimensions and scroll values.
3765 * @param {Number} x The X coordinate value to be constrained
3766 * @return {Number} The constrained x coordinate
3768 getConstrainedX: function (x) {
3769 return this._getConstrainedPos("x", x);
3773 * Given y coordinate value, returns the calculated y coordinate required to
3774 * position the Overlay if it is to be constrained to the viewport, based on the
3775 * current element size, viewport dimensions and scroll values.
3777 * @param {Number} y The Y coordinate value to be constrained
3778 * @return {Number} The constrained y coordinate
3780 getConstrainedY : function (y) {
3781 return this._getConstrainedPos("y", y);
3785 * Given x, y coordinate values, returns the calculated coordinates required to
3786 * position the Overlay if it is to be constrained to the viewport, based on the
3787 * current element size, viewport dimensions and scroll values.
3789 * @param {Number} x The X coordinate value to be constrained
3790 * @param {Number} y The Y coordinate value to be constrained
3791 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3793 getConstrainedXY: function(x, y) {
3794 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3798 * Centers the container in the viewport.
3801 center: function () {
3803 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3804 elementWidth = this.element.offsetWidth,
3805 elementHeight = this.element.offsetHeight,
3806 viewPortWidth = Dom.getViewportWidth(),
3807 viewPortHeight = Dom.getViewportHeight(),
3811 if (elementWidth < viewPortWidth) {
3812 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3814 x = nViewportOffset + Dom.getDocumentScrollLeft();
3817 if (elementHeight < viewPortHeight) {
3818 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3820 y = nViewportOffset + Dom.getDocumentScrollTop();
3823 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3824 this.cfg.refireEvent("iframe");
3827 this.forceContainerRedraw();
3832 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3833 * Panel's position in the DOM. This is primarily used to update
3834 * position information during drag & drop.
3835 * @method syncPosition
3837 syncPosition: function () {
3839 var pos = Dom.getXY(this.element);
3841 this.cfg.setProperty("x", pos[0], true);
3842 this.cfg.setProperty("y", pos[1], true);
3843 this.cfg.setProperty("xy", pos, true);
3848 * Event handler fired when the resize monitor element is resized.
3849 * @method onDomResize
3850 * @param {DOMEvent} e The resize DOM event
3851 * @param {Object} obj The scope object
3853 onDomResize: function (e, obj) {
3857 Overlay.superclass.onDomResize.call(this, e, obj);
3859 setTimeout(function () {
3861 me.cfg.refireEvent("iframe");
3862 me.cfg.refireEvent("context");
3867 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3869 * @method _getComputedHeight
3871 * @param {HTMLElement} el The element for which the content height needs to be determined
3872 * @return {Number} The content box height of the given element, or null if it could not be determined.
3874 _getComputedHeight : (function() {
3876 if (document.defaultView && document.defaultView.getComputedStyle) {
3877 return function(el) {
3879 if (el.ownerDocument && el.ownerDocument.defaultView) {
3880 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3882 height = parseInt(computed.height, 10);
3885 return (Lang.isNumber(height)) ? height : null;
3888 return function(el) {
3890 if (el.style.pixelHeight) {
3891 height = el.style.pixelHeight;
3893 return (Lang.isNumber(height)) ? height : null;
3899 * autofillheight validator. Verifies that the autofill value is either null
3900 * or one of the strings : "body", "header" or "footer".
3902 * @method _validateAutoFillHeight
3904 * @param {String} val
3905 * @return true, if valid, false otherwise
3907 _validateAutoFillHeight : function(val) {
3908 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3912 * The default custom event handler executed when the overlay's height is changed,
3913 * if the autofillheight property has been set.
3915 * @method _autoFillOnHeightChange
3917 * @param {String} type The event type
3918 * @param {Array} args The array of arguments passed to event subscribers
3919 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3920 * out the containers height
3922 _autoFillOnHeightChange : function(type, args, el) {
3923 var height = this.cfg.getProperty("height");
3924 if ((height && height !== "auto") || (height === 0)) {
3925 this.fillHeight(el);
3930 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3931 * otherwise returns the offsetHeight
3932 * @method _getPreciseHeight
3934 * @param {HTMLElement} el
3935 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3937 _getPreciseHeight : function(el) {
3938 var height = el.offsetHeight;
3940 if (el.getBoundingClientRect) {
3941 var rect = el.getBoundingClientRect();
3942 height = rect.bottom - rect.top;
3950 * Sets the height on the provided header, body or footer element to
3951 * fill out the height of the container. It determines the height of the
3952 * containers content box, based on it's configured height value, and
3953 * sets the height of the autofillheight element to fill out any
3954 * space remaining after the other standard module element heights
3955 * have been accounted for.
3957 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
3958 * height has not been set on the container, since for an "auto" height container,
3959 * the heights of the header/body/footer will drive the height of the container.</p>
3961 * @method fillHeight
3962 * @param {HTMLElement} el The element which should be resized to fill out the height
3963 * of the container element.
3965 fillHeight : function(el) {
3967 var container = this.innerElement || this.element,
3968 containerEls = [this.header, this.body, this.footer],
3975 for (var i = 0, l = containerEls.length; i < l; i++) {
3976 containerEl = containerEls[i];
3978 if (el !== containerEl) {
3979 filled += this._getPreciseHeight(containerEl);
3988 if (UA.ie || UA.opera) {
3989 // Need to set height to 0, to allow height to be reduced
3990 Dom.setStyle(el, 'height', 0 + 'px');
3993 total = this._getComputedHeight(container);
3995 // Fallback, if we can't get computed value for content height
3996 if (total === null) {
3997 Dom.addClass(container, "yui-override-padding");
3998 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
3999 Dom.removeClass(container, "yui-override-padding");
4002 remaining = Math.max(total - filled, 0);
4004 Dom.setStyle(el, "height", remaining + "px");
4006 // Re-adjust height if required, to account for el padding and border
4007 if (el.offsetHeight != remaining) {
4008 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4010 Dom.setStyle(el, "height", remaining + "px");
4016 * Places the Overlay on top of all other instances of
4017 * YAHOO.widget.Overlay.
4018 * @method bringToTop
4020 bringToTop: function () {
4023 oElement = this.element;
4025 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4027 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4028 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4030 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4031 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4033 if (nZIndex1 > nZIndex2) {
4035 } else if (nZIndex1 < nZIndex2) {
4042 function isOverlayElement(p_oElement) {
4044 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4045 Panel = YAHOO.widget.Panel;
4047 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4048 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4049 aOverlays[aOverlays.length] = p_oElement.parentNode;
4051 aOverlays[aOverlays.length] = p_oElement;
4056 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
4058 aOverlays.sort(compareZIndexDesc);
4060 var oTopOverlay = aOverlays[0],
4064 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4066 if (!isNaN(nTopZIndex)) {
4067 var bRequiresBump = false;
4069 if (oTopOverlay != oElement) {
4070 bRequiresBump = true;
4071 } else if (aOverlays.length > 1) {
4072 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4073 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4074 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4075 bRequiresBump = true;
4078 if (bRequiresBump) {
4079 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4086 * Removes the Overlay element from the DOM and sets all child
4090 destroy: function () {
4093 this.iframe.parentNode.removeChild(this.iframe);
4098 Overlay.windowResizeEvent.unsubscribe(
4099 this.doCenterOnDOMEvent, this);
4101 Overlay.windowScrollEvent.unsubscribe(
4102 this.doCenterOnDOMEvent, this);
4104 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4106 if (this._contextTriggers) {
4107 // Unsubscribe context triggers - to cover context triggers which listen for global
4108 // events such as windowResize and windowScroll. Easier just to unsubscribe all
4109 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4112 Overlay.superclass.destroy.call(this);
4116 * Can be used to force the container to repaint/redraw it's contents.
4118 * By default applies and then removes a 1px bottom margin through the
4119 * application/removal of a "yui-force-redraw" class.
4122 * It is currently used by Overlay to force a repaint for webkit
4123 * browsers, when centering.
4125 * @method forceContainerRedraw
4127 forceContainerRedraw : function() {
4129 Dom.addClass(c.element, "yui-force-redraw");
4130 setTimeout(function() {
4131 Dom.removeClass(c.element, "yui-force-redraw");
4136 * Returns a String representation of the object.
4138 * @return {String} The string representation of the Overlay.
4140 toString: function () {
4141 return "Overlay " + this.id;
4149 * OverlayManager is used for maintaining the focus status of
4150 * multiple Overlays.
4151 * @namespace YAHOO.widget
4152 * @namespace YAHOO.widget
4153 * @class OverlayManager
4155 * @param {Array} overlays Optional. A collection of Overlays to register
4157 * @param {Object} userConfig The object literal representing the user
4158 * configuration of the OverlayManager
4160 YAHOO.widget.OverlayManager = function (userConfig) {
4161 this.init(userConfig);
4164 var Overlay = YAHOO.widget.Overlay,
4165 Event = YAHOO.util.Event,
4166 Dom = YAHOO.util.Dom,
4167 Config = YAHOO.util.Config,
4168 CustomEvent = YAHOO.util.CustomEvent,
4169 OverlayManager = YAHOO.widget.OverlayManager;
4172 * The CSS class representing a focused Overlay
4173 * @property OverlayManager.CSS_FOCUSED
4178 OverlayManager.CSS_FOCUSED = "focused";
4180 OverlayManager.prototype = {
4183 * The class's constructor function
4184 * @property contructor
4187 constructor: OverlayManager,
4190 * The array of Overlays that are currently registered
4191 * @property overlays
4192 * @type YAHOO.widget.Overlay[]
4197 * Initializes the default configuration of the OverlayManager
4198 * @method initDefaultConfig
4200 initDefaultConfig: function () {
4202 * The collection of registered Overlays in use by
4203 * the OverlayManager
4205 * @type YAHOO.widget.Overlay[]
4208 this.cfg.addProperty("overlays", { suppressEvent: true } );
4211 * The default DOM event that should be used to focus an Overlay
4212 * @config focusevent
4214 * @default "mousedown"
4216 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4220 * Initializes the OverlayManager
4222 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4223 * register with the manager.
4224 * @param {Object} userConfig The object literal representing the user
4225 * configuration of the OverlayManager
4227 init: function (userConfig) {
4230 * The OverlayManager's Config object used for monitoring
4231 * configuration properties.
4235 this.cfg = new Config(this);
4237 this.initDefaultConfig();
4240 this.cfg.applyConfig(userConfig, true);
4242 this.cfg.fireQueue();
4245 * The currently activated Overlay
4246 * @property activeOverlay
4248 * @type YAHOO.widget.Overlay
4250 var activeOverlay = null;
4253 * Returns the currently focused Overlay
4255 * @return {Overlay} The currently focused Overlay
4257 this.getActive = function () {
4258 return activeOverlay;
4262 * Focuses the specified Overlay
4264 * @param {Overlay} overlay The Overlay to focus
4265 * @param {String} overlay The id of the Overlay to focus
4267 this.focus = function (overlay) {
4268 var o = this.find(overlay);
4275 * Removes the specified Overlay from the manager
4277 * @param {Overlay} overlay The Overlay to remove
4278 * @param {String} overlay The id of the Overlay to remove
4280 this.remove = function (overlay) {
4282 var o = this.find(overlay),
4286 if (activeOverlay == o) {
4287 activeOverlay = null;
4290 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4293 // Set it's zindex so that it's sorted to the end.
4294 originalZ = Dom.getStyle(o.element, "zIndex");
4295 o.cfg.setProperty("zIndex", -1000, true);
4298 this.overlays.sort(this.compareZIndexDesc);
4299 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4301 o.hideEvent.unsubscribe(o.blur);
4302 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4303 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4304 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4307 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4308 o.cfg.setProperty("zIndex", originalZ, true);
4309 o.cfg.setProperty("manager", null);
4312 /* _managed Flag for custom or existing. Don't want to remove existing */
4313 if (o.focusEvent._managed) { o.focusEvent = null; }
4314 if (o.blurEvent._managed) { o.blurEvent = null; }
4316 if (o.focus._managed) { o.focus = null; }
4317 if (o.blur._managed) { o.blur = null; }
4322 * Removes focus from all registered Overlays in the manager
4325 this.blurAll = function () {
4327 var nOverlays = this.overlays.length,
4330 if (nOverlays > 0) {
4333 this.overlays[i].blur();
4340 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4343 * @method _manageBlur
4344 * @param {Overlay} overlay The overlay instance which got blurred.
4347 this._manageBlur = function (overlay) {
4348 var changed = false;
4349 if (activeOverlay == overlay) {
4350 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4351 activeOverlay = null;
4358 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4361 * @method _manageFocus
4362 * @param {Overlay} overlay The overlay instance which got focus.
4365 this._manageFocus = function(overlay) {
4366 var changed = false;
4367 if (activeOverlay != overlay) {
4368 if (activeOverlay) {
4369 activeOverlay.blur();
4371 activeOverlay = overlay;
4372 this.bringToTop(activeOverlay);
4373 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4379 var overlays = this.cfg.getProperty("overlays");
4381 if (! this.overlays) {
4386 this.register(overlays);
4387 this.overlays.sort(this.compareZIndexDesc);
4392 * @method _onOverlayElementFocus
4393 * @description Event handler for the DOM event that is used to focus
4394 * the Overlay instance as specified by the "focusevent"
4395 * configuration property.
4397 * @param {Event} p_oEvent Object representing the DOM event
4398 * object passed back by the event utility (Event).
4400 _onOverlayElementFocus: function (p_oEvent) {
4402 var oTarget = Event.getTarget(p_oEvent),
4403 oClose = this.close;
4405 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4413 * @method _onOverlayDestroy
4414 * @description "destroy" event handler for the Overlay.
4416 * @param {String} p_sType String representing the name of the event
4418 * @param {Array} p_aArgs Array of arguments sent when the event
4420 * @param {Overlay} p_oOverlay Object representing the overlay that
4423 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4424 this.remove(p_oOverlay);
4428 * @method _onOverlayFocusHandler
4430 * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4433 * @param {String} p_sType String representing the name of the event
4435 * @param {Array} p_aArgs Array of arguments sent when the event
4437 * @param {Overlay} p_oOverlay Object representing the overlay that
4440 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4441 this._manageFocus(p_oOverlay);
4445 * @method _onOverlayBlurHandler
4446 * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4449 * @param {String} p_sType String representing the name of the event
4451 * @param {Array} p_aArgs Array of arguments sent when the event
4453 * @param {Overlay} p_oOverlay Object representing the overlay that
4456 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4457 this._manageBlur(p_oOverlay);
4461 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4462 * monitor focus state.
4464 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4465 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4466 * on the instance, the _bindFocus method will add them, and the focus method will
4467 * update the OverlayManager's state directly.
4469 * @method _bindFocus
4470 * @param {Overlay} overlay The overlay for which focus needs to be managed
4473 _bindFocus : function(overlay) {
4476 if (!overlay.focusEvent) {
4477 overlay.focusEvent = overlay.createEvent("focus");
4478 overlay.focusEvent.signature = CustomEvent.LIST;
4479 overlay.focusEvent._managed = true;
4481 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4484 if (!overlay.focus) {
4485 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4486 overlay.focus = function () {
4487 if (mgr._manageFocus(this)) {
4489 if (this.cfg.getProperty("visible") && this.focusFirst) {
4492 this.focusEvent.fire();
4495 overlay.focus._managed = true;
4500 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4501 * monitor blur state.
4503 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4504 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4505 * on the instance, the _bindBlur method will add them, and the blur method
4506 * update the OverlayManager's state directly.
4509 * @param {Overlay} overlay The overlay for which blur needs to be managed
4512 _bindBlur : function(overlay) {
4515 if (!overlay.blurEvent) {
4516 overlay.blurEvent = overlay.createEvent("blur");
4517 overlay.blurEvent.signature = CustomEvent.LIST;
4518 overlay.focusEvent._managed = true;
4520 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4523 if (!overlay.blur) {
4524 overlay.blur = function () {
4525 if (mgr._manageBlur(this)) {
4526 this.blurEvent.fire();
4529 overlay.blur._managed = true;
4532 overlay.hideEvent.subscribe(overlay.blur);
4536 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4537 * to be removed for the OverlayManager when destroyed.
4539 * @method _bindDestroy
4540 * @param {Overlay} overlay The overlay instance being managed
4543 _bindDestroy : function(overlay) {
4545 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4549 * Ensures the zIndex configuration property on the managed overlay based instance
4550 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4552 * @method _syncZIndex
4553 * @param {Overlay} overlay The overlay instance being managed
4556 _syncZIndex : function(overlay) {
4557 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4558 if (!isNaN(zIndex)) {
4559 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4561 overlay.cfg.setProperty("zIndex", 0);
4566 * Registers an Overlay or an array of Overlays with the manager. Upon
4567 * registration, the Overlay receives functions for focus and blur,
4568 * along with CustomEvents for each.
4571 * @param {Overlay} overlay An Overlay to register with the manager.
4572 * @param {Overlay[]} overlay An array of Overlays to register with
4574 * @return {boolean} true if any Overlays are registered.
4576 register: function (overlay) {
4578 var registered = false,
4582 if (overlay instanceof Overlay) {
4584 overlay.cfg.addProperty("manager", { value: this } );
4586 this._bindFocus(overlay);
4587 this._bindBlur(overlay);
4588 this._bindDestroy(overlay);
4589 this._syncZIndex(overlay);
4591 this.overlays.push(overlay);
4592 this.bringToTop(overlay);
4596 } else if (overlay instanceof Array) {
4598 for (i = 0, n = overlay.length; i < n; i++) {
4599 registered = this.register(overlay[i]) || registered;
4608 * Places the specified Overlay instance on top of all other
4609 * Overlay instances.
4610 * @method bringToTop
4611 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4613 * @param {String} p_oOverlay String representing the id of an
4616 bringToTop: function (p_oOverlay) {
4618 var oOverlay = this.find(p_oOverlay),
4625 aOverlays = this.overlays;
4626 aOverlays.sort(this.compareZIndexDesc);
4628 oTopOverlay = aOverlays[0];
4631 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4633 if (!isNaN(nTopZIndex)) {
4635 var bRequiresBump = false;
4637 if (oTopOverlay !== oOverlay) {
4638 bRequiresBump = true;
4639 } else if (aOverlays.length > 1) {
4640 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4641 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4642 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4643 bRequiresBump = true;
4647 if (bRequiresBump) {
4648 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4651 aOverlays.sort(this.compareZIndexDesc);
4657 * Attempts to locate an Overlay by instance or ID.
4659 * @param {Overlay} overlay An Overlay to locate within the manager
4660 * @param {String} overlay An Overlay id to locate within the manager
4661 * @return {Overlay} The requested Overlay, if found, or null if it
4662 * cannot be located.
4664 find: function (overlay) {
4666 var isInstance = overlay instanceof Overlay,
4667 overlays = this.overlays,
4668 n = overlays.length,
4673 if (isInstance || typeof overlay == "string") {
4674 for (i = n-1; i >= 0; i--) {
4676 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4687 * Used for sorting the manager's Overlays by z-index.
4688 * @method compareZIndexDesc
4690 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4691 * fall in the stacking order.
4693 compareZIndexDesc: function (o1, o2) {
4695 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4696 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4698 if (zIndex1 === null && zIndex2 === null) {
4700 } else if (zIndex1 === null){
4702 } else if (zIndex2 === null) {
4704 } else if (zIndex1 > zIndex2) {
4706 } else if (zIndex1 < zIndex2) {
4714 * Shows all Overlays in the manager.
4717 showAll: function () {
4718 var overlays = this.overlays,
4719 n = overlays.length,
4722 for (i = n - 1; i >= 0; i--) {
4728 * Hides all Overlays in the manager.
4731 hideAll: function () {
4732 var overlays = this.overlays,
4733 n = overlays.length,
4736 for (i = n - 1; i >= 0; i--) {
4742 * Returns a string representation of the object.
4744 * @return {String} The string representation of the OverlayManager
4746 toString: function () {
4747 return "OverlayManager";
4754 * ContainerEffect encapsulates animation transitions that are executed when
4755 * an Overlay is shown or hidden.
4756 * @namespace YAHOO.widget
4757 * @class ContainerEffect
4759 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
4760 * should be associated with
4761 * @param {Object} attrIn The object literal representing the animation
4762 * arguments to be used for the animate-in transition. The arguments for
4763 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4764 * duration(Number), and method(i.e. Easing.easeIn).
4765 * @param {Object} attrOut The object literal representing the animation
4766 * arguments to be used for the animate-out transition. The arguments for
4767 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4768 * duration(Number), and method(i.e. Easing.easeIn).
4769 * @param {HTMLElement} targetElement Optional. The target element that
4770 * should be animated during the transition. Defaults to overlay.element.
4771 * @param {class} Optional. The animation class to instantiate. Defaults to
4772 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4774 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
4777 animClass = YAHOO.util.Anim;
4781 * The overlay to animate
4783 * @type YAHOO.widget.Overlay
4785 this.overlay = overlay;
4788 * The animation attributes to use when transitioning into view
4792 this.attrIn = attrIn;
4795 * The animation attributes to use when transitioning out of view
4799 this.attrOut = attrOut;
4802 * The target element to be animated
4803 * @property targetElement
4806 this.targetElement = targetElement || overlay.element;
4809 * The animation class to use for animating the overlay
4810 * @property animClass
4813 this.animClass = animClass;
4818 var Dom = YAHOO.util.Dom,
4819 CustomEvent = YAHOO.util.CustomEvent,
4820 ContainerEffect = YAHOO.widget.ContainerEffect;
4824 * A pre-configured ContainerEffect instance that can be used for fading
4825 * an overlay in and out.
4828 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4829 * @param {Number} dur The duration of the animation
4830 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4832 ContainerEffect.FADE = function (overlay, dur) {
4834 var Easing = YAHOO.util.Easing,
4836 attributes: {opacity:{from:0, to:1}},
4838 method: Easing.easeIn
4841 attributes: {opacity:{to:0}},
4843 method: Easing.easeOut
4845 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
4847 fade.handleUnderlayStart = function() {
4848 var underlay = this.overlay.underlay;
4849 if (underlay && YAHOO.env.ua.ie) {
4850 var hasFilters = (underlay.filters && underlay.filters.length > 0);
4852 Dom.addClass(overlay.element, "yui-effect-fade");
4857 fade.handleUnderlayComplete = function() {
4858 var underlay = this.overlay.underlay;
4859 if (underlay && YAHOO.env.ua.ie) {
4860 Dom.removeClass(overlay.element, "yui-effect-fade");
4864 fade.handleStartAnimateIn = function (type, args, obj) {
4865 Dom.addClass(obj.overlay.element, "hide-select");
4867 if (!obj.overlay.underlay) {
4868 obj.overlay.cfg.refireEvent("underlay");
4871 obj.handleUnderlayStart();
4873 obj.overlay._setDomVisibility(true);
4874 Dom.setStyle(obj.overlay.element, "opacity", 0);
4877 fade.handleCompleteAnimateIn = function (type,args,obj) {
4878 Dom.removeClass(obj.overlay.element, "hide-select");
4880 if (obj.overlay.element.style.filter) {
4881 obj.overlay.element.style.filter = null;
4884 obj.handleUnderlayComplete();
4886 obj.overlay.cfg.refireEvent("iframe");
4887 obj.animateInCompleteEvent.fire();
4890 fade.handleStartAnimateOut = function (type, args, obj) {
4891 Dom.addClass(obj.overlay.element, "hide-select");
4892 obj.handleUnderlayStart();
4895 fade.handleCompleteAnimateOut = function (type, args, obj) {
4896 Dom.removeClass(obj.overlay.element, "hide-select");
4897 if (obj.overlay.element.style.filter) {
4898 obj.overlay.element.style.filter = null;
4900 obj.overlay._setDomVisibility(false);
4901 Dom.setStyle(obj.overlay.element, "opacity", 1);
4903 obj.handleUnderlayComplete();
4905 obj.overlay.cfg.refireEvent("iframe");
4906 obj.animateOutCompleteEvent.fire();
4915 * A pre-configured ContainerEffect instance that can be used for sliding an
4916 * overlay in and out.
4919 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4920 * @param {Number} dur The duration of the animation
4921 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4923 ContainerEffect.SLIDE = function (overlay, dur) {
4924 var Easing = YAHOO.util.Easing,
4926 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
4927 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
4928 clientWidth = Dom.getClientWidth(),
4929 offsetWidth = overlay.element.offsetWidth,
4932 attributes: { points: { to: [x, y] } },
4934 method: Easing.easeIn
4938 attributes: { points: { to: [(clientWidth + 25), y] } },
4940 method: Easing.easeOut
4943 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
4945 slide.handleStartAnimateIn = function (type,args,obj) {
4946 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
4947 obj.overlay.element.style.top = y + "px";
4950 slide.handleTweenAnimateIn = function (type, args, obj) {
4952 var pos = Dom.getXY(obj.overlay.element),
4956 if (Dom.getStyle(obj.overlay.element, "visibility") ==
4957 "hidden" && currentX < x) {
4959 obj.overlay._setDomVisibility(true);
4963 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
4964 obj.overlay.cfg.refireEvent("iframe");
4967 slide.handleCompleteAnimateIn = function (type, args, obj) {
4968 obj.overlay.cfg.setProperty("xy", [x, y], true);
4971 obj.overlay.cfg.refireEvent("iframe");
4972 obj.animateInCompleteEvent.fire();
4975 slide.handleStartAnimateOut = function (type, args, obj) {
4977 var vw = Dom.getViewportWidth(),
4978 pos = Dom.getXY(obj.overlay.element),
4981 obj.animOut.attributes.points.to = [(vw + 25), yso];
4984 slide.handleTweenAnimateOut = function (type, args, obj) {
4986 var pos = Dom.getXY(obj.overlay.element),
4990 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
4991 obj.overlay.cfg.refireEvent("iframe");
4994 slide.handleCompleteAnimateOut = function (type, args, obj) {
4995 obj.overlay._setDomVisibility(false);
4997 obj.overlay.cfg.setProperty("xy", [x, y]);
4998 obj.animateOutCompleteEvent.fire();
5005 ContainerEffect.prototype = {
5008 * Initializes the animation classes and events.
5013 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
5014 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
5016 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
5017 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
5019 this.animateInCompleteEvent = this.createEvent("animateInComplete");
5020 this.animateInCompleteEvent.signature = CustomEvent.LIST;
5022 this.animateOutCompleteEvent =
5023 this.createEvent("animateOutComplete");
5024 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
5026 this.animIn = new this.animClass(this.targetElement,
5027 this.attrIn.attributes, this.attrIn.duration,
5028 this.attrIn.method);
5030 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
5031 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
5033 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
5036 this.animOut = new this.animClass(this.targetElement,
5037 this.attrOut.attributes, this.attrOut.duration,
5038 this.attrOut.method);
5040 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
5041 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
5042 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
5048 * Triggers the in-animation.
5051 animateIn: function () {
5052 this.beforeAnimateInEvent.fire();
5053 this.animIn.animate();
5057 * Triggers the out-animation.
5058 * @method animateOut
5060 animateOut: function () {
5061 this.beforeAnimateOutEvent.fire();
5062 this.animOut.animate();
5066 * The default onStart handler for the in-animation.
5067 * @method handleStartAnimateIn
5068 * @param {String} type The CustomEvent type
5069 * @param {Object[]} args The CustomEvent arguments
5070 * @param {Object} obj The scope object
5072 handleStartAnimateIn: function (type, args, obj) { },
5075 * The default onTween handler for the in-animation.
5076 * @method handleTweenAnimateIn
5077 * @param {String} type The CustomEvent type
5078 * @param {Object[]} args The CustomEvent arguments
5079 * @param {Object} obj The scope object
5081 handleTweenAnimateIn: function (type, args, obj) { },
5084 * The default onComplete handler for the in-animation.
5085 * @method handleCompleteAnimateIn
5086 * @param {String} type The CustomEvent type
5087 * @param {Object[]} args The CustomEvent arguments
5088 * @param {Object} obj The scope object
5090 handleCompleteAnimateIn: function (type, args, obj) { },
5093 * The default onStart handler for the out-animation.
5094 * @method handleStartAnimateOut
5095 * @param {String} type The CustomEvent type
5096 * @param {Object[]} args The CustomEvent arguments
5097 * @param {Object} obj The scope object
5099 handleStartAnimateOut: function (type, args, obj) { },
5102 * The default onTween handler for the out-animation.
5103 * @method handleTweenAnimateOut
5104 * @param {String} type The CustomEvent type
5105 * @param {Object[]} args The CustomEvent arguments
5106 * @param {Object} obj The scope object
5108 handleTweenAnimateOut: function (type, args, obj) { },
5111 * The default onComplete handler for the out-animation.
5112 * @method handleCompleteAnimateOut
5113 * @param {String} type The CustomEvent type
5114 * @param {Object[]} args The CustomEvent arguments
5115 * @param {Object} obj The scope object
5117 handleCompleteAnimateOut: function (type, args, obj) { },
5120 * Returns a string representation of the object.
5122 * @return {String} The string representation of the ContainerEffect
5124 toString: function () {
5125 var output = "ContainerEffect";
5127 output += " [" + this.overlay.toString() + "]";
5133 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
5136 YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.8.0r4", build: "2449"});