2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
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) {
30 var Lang = YAHOO.lang,
31 CustomEvent = YAHOO.util.CustomEvent,
32 Config = YAHOO.util.Config;
36 * Constant representing the CustomEvent type for the config changed event.
37 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
42 Config.CONFIG_CHANGED_EVENT = "configChanged";
45 * Constant representing the boolean type string
46 * @property YAHOO.util.Config.BOOLEAN_TYPE
51 Config.BOOLEAN_TYPE = "boolean";
56 * Object reference to the owner of this Config Object
63 * Boolean flag that specifies whether a queue is currently
65 * @property queueInProgress
68 queueInProgress: false,
71 * Maintains the local collection of configuration property objects and
72 * their specified values
80 * Maintains the local collection of configuration property objects as
81 * they were initially applied.
82 * This object is used when resetting a property.
83 * @property initialConfig
90 * Maintains the local, normalized CustomEvent queue
91 * @property eventQueue
98 * Custom Event, notifying subscribers when Config properties are set
99 * (setProperty is called without the silent flag
100 * @event configChangedEvent
102 configChangedEvent: null,
105 * Initializes the configuration Object and all of its local members.
107 * @param {Object} owner The owner Object to which this Config
110 init: function (owner) {
114 this.configChangedEvent =
115 this.createEvent(Config.CONFIG_CHANGED_EVENT);
117 this.configChangedEvent.signature = CustomEvent.LIST;
118 this.queueInProgress = false;
120 this.initialConfig = {};
121 this.eventQueue = [];
126 * Validates that the value passed in is a Boolean.
127 * @method checkBoolean
128 * @param {Object} val The value to validate
129 * @return {Boolean} true, if the value is valid
131 checkBoolean: function (val) {
132 return (typeof val == Config.BOOLEAN_TYPE);
136 * Validates that the value passed in is a number.
137 * @method checkNumber
138 * @param {Object} val The value to validate
139 * @return {Boolean} true, if the value is valid
141 checkNumber: function (val) {
142 return (!isNaN(val));
146 * Fires a configuration property event using the specified value.
149 * @param {String} key The configuration property's name
150 * @param {value} Object The value of the correct type for the property
152 fireEvent: function ( key, value ) {
153 var property = this.config[key];
155 if (property && property.event) {
156 property.event.fire(value);
161 * Adds a property to the Config Object's private config hash.
162 * @method addProperty
163 * @param {String} key The configuration property's name
164 * @param {Object} propertyObject The Object containing all of this
165 * property's arguments
167 addProperty: function ( key, propertyObject ) {
168 key = key.toLowerCase();
170 this.config[key] = propertyObject;
172 propertyObject.event = this.createEvent(key, { scope: this.owner });
173 propertyObject.event.signature = CustomEvent.LIST;
176 propertyObject.key = key;
178 if (propertyObject.handler) {
179 propertyObject.event.subscribe(propertyObject.handler,
183 this.setProperty(key, propertyObject.value, true);
185 if (! propertyObject.suppressEvent) {
186 this.queueProperty(key, propertyObject.value);
192 * Returns a key-value configuration map of the values currently set in
195 * @return {Object} The current config, represented in a key-value map
197 getConfig: function () {
200 currCfg = this.config,
204 for (prop in currCfg) {
205 if (Lang.hasOwnProperty(currCfg, prop)) {
206 property = currCfg[prop];
207 if (property && property.event) {
208 cfg[prop] = property.value;
217 * Returns the value of specified property.
218 * @method getProperty
219 * @param {String} key The name of the property
220 * @return {Object} The value of the specified property
222 getProperty: function (key) {
223 var property = this.config[key.toLowerCase()];
224 if (property && property.event) {
225 return property.value;
232 * Resets the specified property's value to its initial value.
233 * @method resetProperty
234 * @param {String} key The name of the property
235 * @return {Boolean} True is the property was reset, false if not
237 resetProperty: function (key) {
238 key = key.toLowerCase();
240 var property = this.config[key];
242 if (property && property.event) {
243 if (key in this.initialConfig) {
244 this.setProperty(key, this.initialConfig[key]);
253 * Sets the value of a property. If the silent property is passed as
254 * true, the property's event will not be fired.
255 * @method setProperty
256 * @param {String} key The name of the property
257 * @param {String} value The value to set the property to
258 * @param {Boolean} silent Whether the value should be set silently,
259 * without firing the property event.
260 * @return {Boolean} True, if the set was successful, false if it failed.
262 setProperty: function (key, value, silent) {
266 key = key.toLowerCase();
268 if (this.queueInProgress && ! silent) {
269 // Currently running through a queue...
270 this.queueProperty(key,value);
274 property = this.config[key];
275 if (property && property.event) {
276 if (property.validator && !property.validator(value)) {
279 property.value = value;
281 this.fireEvent(key, value);
282 this.configChangedEvent.fire([key, value]);
293 * Sets the value of a property and queues its event to execute. If the
294 * event is already scheduled to execute, it is
295 * moved from its current position to the end of the queue.
296 * @method queueProperty
297 * @param {String} key The name of the property
298 * @param {String} value The value to set the property to
299 * @return {Boolean} true, if the set was successful, false if
302 queueProperty: function (key, value) {
304 key = key.toLowerCase();
306 var property = this.config[key],
307 foundDuplicate = false,
322 if (property && property.event) {
324 if (!Lang.isUndefined(value) && property.validator &&
325 !property.validator(value)) { // validator
329 if (!Lang.isUndefined(value)) {
330 property.value = value;
332 value = property.value;
335 foundDuplicate = false;
336 iLen = this.eventQueue.length;
338 for (i = 0; i < iLen; i++) {
339 queueItem = this.eventQueue[i];
342 queueItemKey = queueItem[0];
343 queueItemValue = queueItem[1];
345 if (queueItemKey == key) {
348 found a dupe... push to end of queue, null
349 current item, and break
352 this.eventQueue[i] = null;
354 this.eventQueue.push(
355 [key, (!Lang.isUndefined(value) ?
356 value : queueItemValue)]);
358 foundDuplicate = true;
364 // this is a refire, or a new property in the queue
366 if (! foundDuplicate && !Lang.isUndefined(value)) {
367 this.eventQueue.push([key, value]);
371 if (property.supercedes) {
373 sLen = property.supercedes.length;
375 for (s = 0; s < sLen; s++) {
377 supercedesCheck = property.supercedes[s];
378 qLen = this.eventQueue.length;
380 for (q = 0; q < qLen; q++) {
381 queueItemCheck = this.eventQueue[q];
383 if (queueItemCheck) {
384 queueItemCheckKey = queueItemCheck[0];
385 queueItemCheckValue = queueItemCheck[1];
387 if (queueItemCheckKey ==
388 supercedesCheck.toLowerCase() ) {
390 this.eventQueue.push([queueItemCheckKey,
391 queueItemCheckValue]);
393 this.eventQueue[q] = null;
410 * Fires the event for a property using the property's current value.
411 * @method refireEvent
412 * @param {String} key The name of the property
414 refireEvent: function (key) {
416 key = key.toLowerCase();
418 var property = this.config[key];
420 if (property && property.event &&
422 !Lang.isUndefined(property.value)) {
424 if (this.queueInProgress) {
426 this.queueProperty(key);
430 this.fireEvent(key, property.value);
438 * Applies a key-value Object literal to the configuration, replacing
439 * any existing values, and queueing the property events.
440 * Although the values will be set, fireQueue() must be called for their
441 * associated events to execute.
442 * @method applyConfig
443 * @param {Object} userConfig The configuration Object literal
444 * @param {Boolean} init When set to true, the initialConfig will
445 * be set to the userConfig passed in, so that calling a reset will
446 * reset the properties to the passed values.
448 applyConfig: function (userConfig, init) {
455 for (sKey in userConfig) {
456 if (Lang.hasOwnProperty(userConfig, sKey)) {
457 oConfig[sKey.toLowerCase()] = userConfig[sKey];
460 this.initialConfig = oConfig;
463 for (sKey in userConfig) {
464 if (Lang.hasOwnProperty(userConfig, sKey)) {
465 this.queueProperty(sKey, userConfig[sKey]);
471 * Refires the events for all configuration properties using their
475 refresh: function () {
479 for (prop in this.config) {
480 if (Lang.hasOwnProperty(this.config, prop)) {
481 this.refireEvent(prop);
487 * Fires the normalized list of queued property change events
490 fireQueue: function () {
498 this.queueInProgress = true;
499 for (i = 0;i < this.eventQueue.length; i++) {
500 queueItem = this.eventQueue[i];
504 value = queueItem[1];
505 property = this.config[key];
507 property.value = value;
509 // Clear out queue entry, to avoid it being
510 // re-added to the queue by any queueProperty/supercedes
511 // calls which are invoked during fireEvent
512 this.eventQueue[i] = null;
514 this.fireEvent(key,value);
518 this.queueInProgress = false;
519 this.eventQueue = [];
523 * Subscribes an external handler to the change event for any
525 * @method subscribeToConfigEvent
526 * @param {String} key The property name
527 * @param {Function} handler The handler function to use subscribe to
528 * the property's event
529 * @param {Object} obj The Object to use for scoping the event handler
530 * (see CustomEvent documentation)
531 * @param {Boolean} overrideContext Optional. If true, will override
532 * "this" within the handler to map to the scope Object passed into the
534 * @return {Boolean} True, if the subscription was successful,
537 subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
539 var property = this.config[key.toLowerCase()];
541 if (property && property.event) {
542 if (!Config.alreadySubscribed(property.event, handler, obj)) {
543 property.event.subscribe(handler, obj, overrideContext);
553 * Unsubscribes an external handler from the change event for any
555 * @method unsubscribeFromConfigEvent
556 * @param {String} key The property name
557 * @param {Function} handler The handler function to use subscribe to
558 * the property's event
559 * @param {Object} obj The Object to use for scoping the event
560 * handler (see CustomEvent documentation)
561 * @return {Boolean} True, if the unsubscription was successful,
564 unsubscribeFromConfigEvent: function (key, handler, obj) {
565 var property = this.config[key.toLowerCase()];
566 if (property && property.event) {
567 return property.event.unsubscribe(handler, obj);
574 * Returns a string representation of the Config object
576 * @return {String} The Config object in string format.
578 toString: function () {
579 var output = "Config";
581 output += " [" + this.owner.toString() + "]";
587 * Returns a string representation of the Config object's current
589 * @method outputEventQueue
590 * @return {String} The string list of CustomEvents currently queued
593 outputEventQueue: function () {
598 nQueue = this.eventQueue.length;
600 for (q = 0; q < nQueue; q++) {
601 queueItem = this.eventQueue[q];
603 output += queueItem[0] + "=" + queueItem[1] + ", ";
610 * Sets all properties to null, unsubscribes all listeners from each
611 * property's change event and all listeners from the configChangedEvent.
614 destroy: function () {
616 var oConfig = this.config,
621 for (sProperty in oConfig) {
623 if (Lang.hasOwnProperty(oConfig, sProperty)) {
625 oProperty = oConfig[sProperty];
627 oProperty.event.unsubscribeAll();
628 oProperty.event = null;
634 this.configChangedEvent.unsubscribeAll();
636 this.configChangedEvent = null;
639 this.initialConfig = null;
640 this.eventQueue = null;
649 * Checks to determine if a particular function/Object pair are already
650 * subscribed to the specified CustomEvent
651 * @method YAHOO.util.Config.alreadySubscribed
653 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
655 * @param {Function} fn The function to look for in the subscribers list
656 * @param {Object} obj The execution scope Object for the subscription
657 * @return {Boolean} true, if the function/Object pair is already subscribed
658 * to the CustomEvent passed in
660 Config.alreadySubscribed = function (evt, fn, obj) {
662 var nSubscribers = evt.subscribers.length,
666 if (nSubscribers > 0) {
667 i = nSubscribers - 1;
669 subsc = evt.subscribers[i];
670 if (subsc && subsc.obj == obj && subsc.fn == fn) {
681 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
687 * The Container family of components is designed to enable developers to
688 * create different kinds of content-containing modules on the web. Module
689 * and Overlay are the most basic containers, and they can be used directly
690 * or extended to build custom containers. Also part of the Container family
691 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
692 * Dialog, and SimpleDialog.
695 * @requires yahoo, dom, event
696 * @optional dragdrop, animation, button
700 * Module is a JavaScript representation of the Standard Module Format.
701 * Standard Module Format is a simple standard for markup containers where
702 * child nodes representing the header, body, and footer of the content are
703 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
704 * Module is the base class for all other classes in the YUI
706 * @namespace YAHOO.widget
709 * @param {String} el The element ID representing the Module <em>OR</em>
710 * @param {HTMLElement} el The element representing the Module
711 * @param {Object} userConfig The configuration Object literal containing
712 * the configuration that should be set for this module. See configuration
713 * documentation for more details.
715 YAHOO.widget.Module = function (el, userConfig) {
717 this.init(el, userConfig);
722 var Dom = YAHOO.util.Dom,
723 Config = YAHOO.util.Config,
724 Event = YAHOO.util.Event,
725 CustomEvent = YAHOO.util.CustomEvent,
726 Module = YAHOO.widget.Module,
735 * Constant representing the name of the Module's events
736 * @property EVENT_TYPES
742 "BEFORE_INIT": "beforeInit",
745 "BEFORE_RENDER": "beforeRender",
747 "CHANGE_HEADER": "changeHeader",
748 "CHANGE_BODY": "changeBody",
749 "CHANGE_FOOTER": "changeFooter",
750 "CHANGE_CONTENT": "changeContent",
751 "DESTROY": "destroy",
752 "BEFORE_SHOW": "beforeShow",
754 "BEFORE_HIDE": "beforeHide",
759 * Constant representing the Module's configuration properties
760 * @property DEFAULT_CONFIG
770 validator: YAHOO.lang.isBoolean
776 supercedes: ["visible"]
780 key: "monitorresize",
784 "APPEND_TO_DOCUMENT_BODY": {
785 key: "appendtodocumentbody",
791 * Constant representing the prefix path to use for non-secure images
792 * @property YAHOO.widget.Module.IMG_ROOT
797 Module.IMG_ROOT = null;
800 * Constant representing the prefix path to use for securely served images
801 * @property YAHOO.widget.Module.IMG_ROOT_SSL
806 Module.IMG_ROOT_SSL = null;
809 * Constant for the default CSS class name that represents a Module
810 * @property YAHOO.widget.Module.CSS_MODULE
815 Module.CSS_MODULE = "yui-module";
818 * CSS classname representing the module header. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
819 * @property YAHOO.widget.Module.CSS_HEADER
824 Module.CSS_HEADER = "hd";
827 * CSS classname representing the module body. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
828 * @property YAHOO.widget.Module.CSS_BODY
833 Module.CSS_BODY = "bd";
836 * CSS classname representing the module footer. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
837 * @property YAHOO.widget.Module.CSS_FOOTER
842 Module.CSS_FOOTER = "ft";
845 * Constant representing the url for the "src" attribute of the iframe
846 * used to monitor changes to the browser's base font size
847 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
852 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
855 * Constant representing the buffer amount (in pixels) to use when positioning
856 * the text resize monitor offscreen. The resize monitor is positioned
857 * offscreen by an amount eqaul to its offsetHeight + the buffer value.
859 * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
863 // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
864 Module.RESIZE_MONITOR_BUFFER = 1;
867 * Singleton CustomEvent fired when the font size is changed in the browser.
868 * Opera's "zoom" functionality currently does not support text
870 * @event YAHOO.widget.Module.textResizeEvent
872 Module.textResizeEvent = new CustomEvent("textResize");
875 * Helper utility method, which forces a document level
876 * redraw for Opera, which can help remove repaint
877 * irregularities after applying DOM changes.
879 * @method YAHOO.widget.Module.forceDocumentRedraw
882 Module.forceDocumentRedraw = function() {
883 var docEl = document.documentElement;
885 docEl.className += " ";
886 docEl.className = YAHOO.lang.trim(docEl.className);
890 function createModuleTemplate() {
892 if (!m_oModuleTemplate) {
893 m_oModuleTemplate = document.createElement("div");
895 m_oModuleTemplate.innerHTML = ("<div class=\"" +
896 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
897 Module.CSS_BODY + "\"></div><div class=\"" +
898 Module.CSS_FOOTER + "\"></div>");
900 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
901 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
902 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
905 return m_oModuleTemplate;
908 function createHeader() {
909 if (!m_oHeaderTemplate) {
910 createModuleTemplate();
912 return (m_oHeaderTemplate.cloneNode(false));
915 function createBody() {
916 if (!m_oBodyTemplate) {
917 createModuleTemplate();
919 return (m_oBodyTemplate.cloneNode(false));
922 function createFooter() {
923 if (!m_oFooterTemplate) {
924 createModuleTemplate();
926 return (m_oFooterTemplate.cloneNode(false));
932 * The class's constructor function
933 * @property contructor
939 * The main module element that contains the header, body, and footer
946 * The header element, denoted with CSS class "hd"
953 * The body element, denoted with CSS class "bd"
960 * The footer element, denoted with CSS class "ft"
967 * The id of the element
974 * A string representing the root path for all images created by
976 * @deprecated It is recommend that any images for a Module be applied
977 * via CSS using the "background-image" property.
978 * @property imageRoot
981 imageRoot: Module.IMG_ROOT,
984 * Initializes the custom events for Module which are fired
985 * automatically at appropriate times by the Module class.
988 initEvents: function () {
990 var SIGNATURE = CustomEvent.LIST;
993 * CustomEvent fired prior to class initalization.
994 * @event beforeInitEvent
995 * @param {class} classRef class reference of the initializing
996 * class, such as this.beforeInitEvent.fire(Module)
998 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
999 this.beforeInitEvent.signature = SIGNATURE;
1002 * CustomEvent fired after class initalization.
1004 * @param {class} classRef class reference of the initializing
1005 * class, such as this.beforeInitEvent.fire(Module)
1007 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1008 this.initEvent.signature = SIGNATURE;
1011 * CustomEvent fired when the Module is appended to the DOM
1012 * @event appendEvent
1014 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1015 this.appendEvent.signature = SIGNATURE;
1018 * CustomEvent fired before the Module is rendered
1019 * @event beforeRenderEvent
1021 this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1022 this.beforeRenderEvent.signature = SIGNATURE;
1025 * CustomEvent fired after the Module is rendered
1026 * @event renderEvent
1028 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1029 this.renderEvent.signature = SIGNATURE;
1032 * CustomEvent fired when the header content of the Module
1034 * @event changeHeaderEvent
1035 * @param {String/HTMLElement} content String/element representing
1036 * the new header content
1038 this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1039 this.changeHeaderEvent.signature = SIGNATURE;
1042 * CustomEvent fired when the body content of the Module is modified
1043 * @event changeBodyEvent
1044 * @param {String/HTMLElement} content String/element representing
1045 * the new body content
1047 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1048 this.changeBodyEvent.signature = SIGNATURE;
1051 * CustomEvent fired when the footer content of the Module
1053 * @event changeFooterEvent
1054 * @param {String/HTMLElement} content String/element representing
1055 * the new footer content
1057 this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1058 this.changeFooterEvent.signature = SIGNATURE;
1061 * CustomEvent fired when the content of the Module is modified
1062 * @event changeContentEvent
1064 this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1065 this.changeContentEvent.signature = SIGNATURE;
1068 * CustomEvent fired when the Module is destroyed
1069 * @event destroyEvent
1071 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
1072 this.destroyEvent.signature = SIGNATURE;
1075 * CustomEvent fired before the Module is shown
1076 * @event beforeShowEvent
1078 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1079 this.beforeShowEvent.signature = SIGNATURE;
1082 * CustomEvent fired after the Module is shown
1085 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1086 this.showEvent.signature = SIGNATURE;
1089 * CustomEvent fired before the Module is hidden
1090 * @event beforeHideEvent
1092 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1093 this.beforeHideEvent.signature = SIGNATURE;
1096 * CustomEvent fired after the Module is hidden
1099 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1100 this.hideEvent.signature = SIGNATURE;
1104 * String identifying whether the current platform is windows or mac. This property
1105 * currently only identifies these 2 platforms, and returns false otherwise.
1106 * @property platform
1107 * @deprecated Use YAHOO.env.ua
1108 * @type {String|Boolean}
1110 platform: function () {
1111 var ua = navigator.userAgent.toLowerCase();
1113 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1115 } else if (ua.indexOf("macintosh") != -1) {
1123 * String representing the user-agent of the browser
1124 * @deprecated Use YAHOO.env.ua
1126 * @type {String|Boolean}
1128 browser: function () {
1129 var ua = navigator.userAgent.toLowerCase();
1131 Check Opera first in case of spoof and check Safari before
1132 Gecko since Safari's user agent string includes "like Gecko"
1134 if (ua.indexOf('opera') != -1) {
1136 } else if (ua.indexOf('msie 7') != -1) {
1138 } else if (ua.indexOf('msie') != -1) {
1140 } else if (ua.indexOf('safari') != -1) {
1142 } else if (ua.indexOf('gecko') != -1) {
1150 * Boolean representing whether or not the current browsing context is
1152 * @property isSecure
1155 isSecure: function () {
1156 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1164 * Initializes the custom events for Module which are fired
1165 * automatically at appropriate times by the Module class.
1167 initDefaultConfig: function () {
1168 // Add properties //
1170 * Specifies whether the Module is visible on the page.
1175 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1176 handler: this.configVisible,
1177 value: DEFAULT_CONFIG.VISIBLE.value,
1178 validator: DEFAULT_CONFIG.VISIBLE.validator
1183 * Object or array of objects representing the ContainerEffect
1184 * classes that are active for animating the container.
1187 * <strong>NOTE:</strong> Although this configuration
1188 * property is introduced at the Module level, an out of the box
1189 * implementation is not shipped for the Module class so setting
1190 * the proroperty on the Module class has no effect. The Overlay
1191 * class is the first class to provide out of the box ContainerEffect
1198 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1199 handler: this.configEffect,
1200 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1201 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1205 * Specifies whether to create a special proxy iframe to monitor
1206 * for user font resizing in the document
1207 * @config monitorresize
1211 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1212 handler: this.configMonitorResize,
1213 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1217 * Specifies if the module should be rendered as the first child
1218 * of document.body or appended as the last child when render is called
1219 * with document.body as the "appendToNode".
1221 * Appending to the body while the DOM is still being constructed can
1222 * lead to Operation Aborted errors in IE hence this flag is set to
1226 * @config appendtodocumentbody
1230 this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1231 value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1236 * The Module class's initialization method, which is executed for
1237 * Module and all of its subclasses. This method is automatically
1238 * called by the constructor, and sets up all DOM references for
1239 * pre-existing markup, and creates required markup if it is not
1242 * If the element passed in does not have an id, one will be generated
1246 * @param {String} el The element ID representing the Module <em>OR</em>
1247 * @param {HTMLElement} el The element representing the Module
1248 * @param {Object} userConfig The configuration Object literal
1249 * containing the configuration that should be set for this module.
1250 * See configuration documentation for more details.
1252 init: function (el, userConfig) {
1257 this.beforeInitEvent.fire(Module);
1260 * The Module's Config object used for monitoring
1261 * configuration properties.
1263 * @type YAHOO.util.Config
1265 this.cfg = new Config(this);
1267 if (this.isSecure) {
1268 this.imageRoot = Module.IMG_ROOT_SSL;
1271 if (typeof el == "string") {
1273 el = document.getElementById(el);
1275 el = (createModuleTemplate()).cloneNode(false);
1280 this.id = Dom.generateId(el);
1283 child = this.element.firstChild;
1286 var fndHd = false, fndBd = false, fndFt = false;
1288 // We're looking for elements
1289 if (1 == child.nodeType) {
1290 if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1291 this.header = child;
1293 } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1296 } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1297 this.footer = child;
1301 } while ((child = child.nextSibling));
1304 this.initDefaultConfig();
1306 Dom.addClass(this.element, Module.CSS_MODULE);
1309 this.cfg.applyConfig(userConfig, true);
1313 Subscribe to the fireQueue() method of Config so that any
1314 queued configuration changes are excecuted upon render of
1318 if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1319 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1322 this.initEvent.fire(Module);
1326 * Initialize an empty IFRAME that is placed out of the visible area
1327 * that can be used to detect text resize.
1328 * @method initResizeMonitor
1330 initResizeMonitor: function () {
1332 var isGeckoWin = (UA.gecko && this.platform == "windows");
1334 // Help prevent spinning loading icon which
1335 // started with FireFox 2.0.0.8/Win
1337 setTimeout(function(){self._initResizeMonitor();}, 0);
1339 this._initResizeMonitor();
1344 * Create and initialize the text resize monitoring iframe.
1347 * @method _initResizeMonitor
1349 _initResizeMonitor : function() {
1355 function fireTextResize() {
1356 Module.textResizeEvent.fire();
1360 oIFrame = Dom.get("_yuiResizeMonitor");
1362 var supportsCWResize = this._supportsCWResize();
1365 oIFrame = document.createElement("iframe");
1367 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1368 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1371 if (!supportsCWResize) {
1372 // Can't monitor on contentWindow, so fire from inside iframe
1373 sHTML = ["<html><head><script ",
1374 "type=\"text/javascript\">",
1375 "window.onresize=function(){window.parent.",
1376 "YAHOO.widget.Module.textResizeEvent.",
1379 "<body></body></html>"].join('');
1381 oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1384 oIFrame.id = "_yuiResizeMonitor";
1385 oIFrame.title = "Text Resize Monitor";
1386 oIFrame.tabIndex = -1;
1387 oIFrame.setAttribute("role", "presentation");
1390 Need to set "position" property before inserting the
1391 iframe into the document or Safari's status bar will
1392 forever indicate the iframe is loading
1393 (See YUILibrary bug #1723064)
1395 oIFrame.style.position = "absolute";
1396 oIFrame.style.visibility = "hidden";
1398 var db = document.body,
1401 db.insertBefore(oIFrame, fc);
1403 db.appendChild(oIFrame);
1406 // Setting the background color fixes an issue with IE6/IE7, where
1407 // elements in the DOM, with -ve margin-top which positioned them
1408 // offscreen (so they would be overlapped by the iframe and its -ve top
1409 // setting), would have their -ve margin-top ignored, when the iframe
1411 oIFrame.style.backgroundColor = "transparent";
1413 oIFrame.style.borderWidth = "0";
1414 oIFrame.style.width = "2em";
1415 oIFrame.style.height = "2em";
1416 oIFrame.style.left = "0";
1417 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1418 oIFrame.style.visibility = "visible";
1421 Don't open/close the document for Gecko like we used to, since it
1422 leads to duplicate cookies. (See YUILibrary bug #1721755)
1425 oDoc = oIFrame.contentWindow.document;
1431 if (oIFrame && oIFrame.contentWindow) {
1432 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1434 if (!Module.textResizeInitialized) {
1435 if (supportsCWResize) {
1436 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1438 This will fail in IE if document.domain has
1439 changed, so we must change the listener to
1440 use the oIFrame element instead
1442 Event.on(oIFrame, "resize", fireTextResize);
1445 Module.textResizeInitialized = true;
1447 this.resizeMonitor = oIFrame;
1453 * Text resize monitor helper method.
1454 * Determines if the browser supports resize events on iframe content windows.
1457 * @method _supportsCWResize
1459 _supportsCWResize : function() {
1461 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1462 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1464 We don't want to start sniffing for patch versions, so fire textResize the same
1465 way on all FF2 flavors
1467 var bSupported = true;
1468 if (UA.gecko && UA.gecko <= 1.8) {
1475 * Event handler fired when the resize monitor element is resized.
1476 * @method onDomResize
1477 * @param {DOMEvent} e The DOM resize event
1478 * @param {Object} obj The scope object passed to the handler
1480 onDomResize: function (e, obj) {
1482 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1484 this.resizeMonitor.style.top = nTop + "px";
1485 this.resizeMonitor.style.left = "0";
1489 * Sets the Module's header content to the markup specified, or appends
1490 * the passed element to the header.
1492 * If no header is present, one will
1493 * be automatically created. An empty string can be passed to the method
1494 * to clear the contents of the header.
1497 * @param {HTML} headerContent The markup used to set the header content.
1498 * As a convenience, non HTMLElement objects can also be passed into
1499 * the method, and will be treated as strings, with the header innerHTML
1500 * set to their default toString implementations.
1502 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1505 * @param {HTMLElement} headerContent The HTMLElement to append to
1507 * @param {DocumentFragment} headerContent The document fragment
1508 * containing elements which are to be added to the header
1510 setHeader: function (headerContent) {
1511 var oHeader = this.header || (this.header = createHeader());
1513 if (headerContent.nodeName) {
1514 oHeader.innerHTML = "";
1515 oHeader.appendChild(headerContent);
1517 oHeader.innerHTML = headerContent;
1520 if (this._rendered) {
1521 this._renderHeader();
1524 this.changeHeaderEvent.fire(headerContent);
1525 this.changeContentEvent.fire();
1530 * Appends the passed element to the header. If no header is present,
1531 * one will be automatically created.
1532 * @method appendToHeader
1533 * @param {HTMLElement | DocumentFragment} element The element to
1534 * append to the header. In the case of a document fragment, the
1535 * children of the fragment will be appended to the header.
1537 appendToHeader: function (element) {
1538 var oHeader = this.header || (this.header = createHeader());
1540 oHeader.appendChild(element);
1542 this.changeHeaderEvent.fire(element);
1543 this.changeContentEvent.fire();
1548 * Sets the Module's body content to the HTML specified.
1550 * If no body is present, one will be automatically created.
1552 * An empty string can be passed to the method to clear the contents of the body.
1554 * @param {HTML} bodyContent The HTML used to set the body content
1555 * As a convenience, non HTMLElement objects can also be passed into
1556 * the method, and will be treated as strings, with the body innerHTML
1557 * set to their default toString implementations.
1559 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1562 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1563 * child of the body element.
1565 * @param {DocumentFragment} bodyContent The document fragment
1566 * containing elements which are to be added to the body
1568 setBody: function (bodyContent) {
1569 var oBody = this.body || (this.body = createBody());
1571 if (bodyContent.nodeName) {
1572 oBody.innerHTML = "";
1573 oBody.appendChild(bodyContent);
1575 oBody.innerHTML = bodyContent;
1578 if (this._rendered) {
1582 this.changeBodyEvent.fire(bodyContent);
1583 this.changeContentEvent.fire();
1587 * Appends the passed element to the body. If no body is present, one
1588 * will be automatically created.
1589 * @method appendToBody
1590 * @param {HTMLElement | DocumentFragment} element The element to
1591 * append to the body. In the case of a document fragment, the
1592 * children of the fragment will be appended to the body.
1595 appendToBody: function (element) {
1596 var oBody = this.body || (this.body = createBody());
1598 oBody.appendChild(element);
1600 this.changeBodyEvent.fire(element);
1601 this.changeContentEvent.fire();
1606 * Sets the Module's footer content to the HTML specified, or appends
1607 * the passed element to the footer. If no footer is present, one will
1608 * be automatically created. An empty string can be passed to the method
1609 * to clear the contents of the footer.
1611 * @param {HTML} footerContent The HTML used to set the footer
1612 * As a convenience, non HTMLElement objects can also be passed into
1613 * the method, and will be treated as strings, with the footer innerHTML
1614 * set to their default toString implementations.
1616 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
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)) {
1720 this._renderHeader(moduleElement);
1721 this._renderBody(moduleElement);
1722 this._renderFooter(moduleElement);
1724 this._rendered = true;
1726 this.renderEvent.fire();
1731 * Renders the currently set header into it's proper position under the
1732 * module element. If the module element is not provided, "this.element"
1735 * @method _renderHeader
1737 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1739 _renderHeader: function(moduleElement){
1740 moduleElement = moduleElement || this.element;
1742 // Need to get everything into the DOM if it isn't already
1743 if (this.header && !Dom.inDocument(this.header)) {
1744 // There is a header, but it's not in the DOM yet. Need to add it.
1745 var firstChild = moduleElement.firstChild;
1747 moduleElement.insertBefore(this.header, firstChild);
1749 moduleElement.appendChild(this.header);
1755 * Renders the currently set body into it's proper position under the
1756 * module element. If the module element is not provided, "this.element"
1759 * @method _renderBody
1761 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1763 _renderBody: function(moduleElement){
1764 moduleElement = moduleElement || this.element;
1766 if (this.body && !Dom.inDocument(this.body)) {
1767 // There is a body, but it's not in the DOM yet. Need to add it.
1768 if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1769 moduleElement.insertBefore(this.body, this.footer);
1771 moduleElement.appendChild(this.body);
1777 * Renders the currently set footer into it's proper position under the
1778 * module element. If the module element is not provided, "this.element"
1781 * @method _renderFooter
1783 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1785 _renderFooter: function(moduleElement){
1786 moduleElement = moduleElement || this.element;
1788 if (this.footer && !Dom.inDocument(this.footer)) {
1789 // There is a footer, but it's not in the DOM yet. Need to add it.
1790 moduleElement.appendChild(this.footer);
1795 * Removes the Module element from the DOM, sets all child elements to null, and purges the bounding element of event listeners.
1797 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
1798 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
1800 destroy: function (shallowPurge) {
1803 purgeChildren = !(shallowPurge);
1806 Event.purgeElement(this.element, purgeChildren);
1807 parent = this.element.parentNode;
1811 parent.removeChild(this.element);
1814 this.element = null;
1819 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1824 this.destroyEvent.fire();
1828 * Shows the Module element by setting the visible configuration
1829 * property to true. Also fires two events: beforeShowEvent prior to
1830 * the visibility change, and showEvent after.
1834 this.cfg.setProperty("visible", true);
1838 * Hides the Module element by setting the visible configuration
1839 * property to false. Also fires two events: beforeHideEvent prior to
1840 * the visibility change, and hideEvent after.
1844 this.cfg.setProperty("visible", false);
1847 // BUILT-IN EVENT HANDLERS FOR MODULE //
1849 * Default event handler for changing the visibility property of a
1850 * Module. By default, this is achieved by switching the "display" style
1851 * between "block" and "none".
1852 * This method is responsible for firing showEvent and hideEvent.
1853 * @param {String} type The CustomEvent type (usually the property name)
1854 * @param {Object[]} args The CustomEvent arguments. For configuration
1855 * handlers, args[0] will equal the newly applied value for the property.
1856 * @param {Object} obj The scope object. For configuration handlers,
1857 * this will usually equal the owner.
1858 * @method configVisible
1860 configVisible: function (type, args, obj) {
1861 var visible = args[0];
1863 if(this.beforeShowEvent.fire()) {
1864 Dom.setStyle(this.element, "display", "block");
1865 this.showEvent.fire();
1868 if (this.beforeHideEvent.fire()) {
1869 Dom.setStyle(this.element, "display", "none");
1870 this.hideEvent.fire();
1876 * Default event handler for the "effect" configuration property
1877 * @param {String} type The CustomEvent type (usually the property name)
1878 * @param {Object[]} args The CustomEvent arguments. For configuration
1879 * handlers, args[0] will equal the newly applied value for the property.
1880 * @param {Object} obj The scope object. For configuration handlers,
1881 * this will usually equal the owner.
1882 * @method configEffect
1884 configEffect: function (type, args, obj) {
1885 this._cachedEffects = (this.cacheEffects) ? this._createEffects(args[0]) : null;
1889 * If true, ContainerEffects (and Anim instances) are cached when "effect" is set, and reused.
1890 * If false, new instances are created each time the container is hidden or shown, as was the
1891 * behavior prior to 2.9.0.
1893 * @property cacheEffects
1898 cacheEffects : true,
1901 * Creates an array of ContainerEffect instances from the provided configs
1903 * @method _createEffects
1904 * @param {Array|Object} effectCfg An effect configuration or array of effect configurations
1905 * @return {Array} An array of ContainerEffect instances.
1908 _createEffects: function(effectCfg) {
1909 var effectInstances = null,
1915 if (effectCfg instanceof Array) {
1916 effectInstances = [];
1917 n = effectCfg.length;
1918 for (i = 0; i < n; i++) {
1921 effectInstances[effectInstances.length] = eff.effect(this, eff.duration);
1924 } else if (effectCfg.effect) {
1925 effectInstances = [effectCfg.effect(this, effectCfg.duration)];
1929 return effectInstances;
1933 * Default event handler for the "monitorresize" configuration property
1934 * @param {String} type The CustomEvent type (usually the property name)
1935 * @param {Object[]} args The CustomEvent arguments. For configuration
1936 * handlers, args[0] will equal the newly applied value for the property.
1937 * @param {Object} obj The scope object. For configuration handlers,
1938 * this will usually equal the owner.
1939 * @method configMonitorResize
1941 configMonitorResize: function (type, args, obj) {
1942 var monitor = args[0];
1944 this.initResizeMonitor();
1946 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1947 this.resizeMonitor = null;
1952 * This method is a protected helper, used when constructing the DOM structure for the module
1953 * to account for situations which may cause Operation Aborted errors in IE. It should not
1954 * be used for general DOM construction.
1956 * If the parentNode is not document.body, the element is appended as the last element.
1959 * If the parentNode is document.body the element is added as the first child to help
1960 * prevent Operation Aborted errors in IE.
1963 * @param {parentNode} The HTML element to which the element will be added
1964 * @param {element} The HTML element to be added to parentNode's children
1965 * @method _addToParent
1968 _addToParent: function(parentNode, element) {
1969 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1970 parentNode.insertBefore(element, parentNode.firstChild);
1972 parentNode.appendChild(element);
1977 * Returns a String representation of the Object.
1979 * @return {String} The string representation of the Module
1981 toString: function () {
1982 return "Module " + this.id;
1986 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1992 * Overlay is a Module that is absolutely positioned above the page flow. It
1993 * has convenience methods for positioning and sizing, as well as options for
1994 * controlling zIndex and constraining the Overlay's position to the current
1995 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1996 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1997 * properly rendered above SELECT elements.
1998 * @namespace YAHOO.widget
2000 * @extends YAHOO.widget.Module
2001 * @param {String} el The element ID representing the Overlay <em>OR</em>
2002 * @param {HTMLElement} el The element representing the Overlay
2003 * @param {Object} userConfig The configuration object literal containing
2004 * the configuration that should be set for this Overlay. See configuration
2005 * documentation for more details.
2008 YAHOO.widget.Overlay = function (el, userConfig) {
2009 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
2012 var Lang = YAHOO.lang,
2013 CustomEvent = YAHOO.util.CustomEvent,
2014 Module = YAHOO.widget.Module,
2015 Event = YAHOO.util.Event,
2016 Dom = YAHOO.util.Dom,
2017 Config = YAHOO.util.Config,
2019 Overlay = YAHOO.widget.Overlay,
2021 _SUBSCRIBE = "subscribe",
2022 _UNSUBSCRIBE = "unsubscribe",
2023 _CONTAINED = "contained",
2028 * Constant representing the name of the Overlay's events
2029 * @property EVENT_TYPES
2035 "BEFORE_MOVE": "beforeMove",
2040 * Constant representing the Overlay's configuration properties
2041 * @property DEFAULT_CONFIG
2050 validator: Lang.isNumber,
2051 suppressEvent: true,
2052 supercedes: ["iframe"]
2057 validator: Lang.isNumber,
2058 suppressEvent: true,
2059 supercedes: ["iframe"]
2064 suppressEvent: true,
2065 supercedes: ["iframe"]
2070 suppressEvent: true,
2071 supercedes: ["iframe"]
2077 supercedes: ["iframe", "visible"]
2082 suppressEvent: true,
2083 supercedes: ["context", "fixedcenter", "iframe"]
2088 suppressEvent: true,
2089 supercedes: ["context", "fixedcenter", "iframe"]
2092 "AUTO_FILL_HEIGHT" : {
2093 key: "autofillheight",
2094 supercedes: ["height"],
2103 "CONSTRAIN_TO_VIEWPORT": {
2104 key: "constraintoviewport",
2106 validator: Lang.isBoolean,
2107 supercedes: ["iframe", "x", "y", "xy"]
2112 value: (UA.ie == 6 ? true : false),
2113 validator: Lang.isBoolean,
2114 supercedes: ["zindex"]
2117 "PREVENT_CONTEXT_OVERLAP": {
2118 key: "preventcontextoverlap",
2120 validator: Lang.isBoolean,
2121 supercedes: ["constraintoviewport"]
2127 * The URL that will be placed in the iframe
2128 * @property YAHOO.widget.Overlay.IFRAME_SRC
2133 Overlay.IFRAME_SRC = "javascript:false;";
2136 * Number representing how much the iframe shim should be offset from each
2137 * side of an Overlay instance, in pixels.
2138 * @property YAHOO.widget.Overlay.IFRAME_SRC
2144 Overlay.IFRAME_OFFSET = 3;
2147 * Number representing the minimum distance an Overlay instance should be
2148 * positioned relative to the boundaries of the browser's viewport, in pixels.
2149 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2155 Overlay.VIEWPORT_OFFSET = 10;
2158 * Constant representing the top left corner of an element, used for
2159 * configuring the context element alignment
2160 * @property YAHOO.widget.Overlay.TOP_LEFT
2165 Overlay.TOP_LEFT = "tl";
2168 * Constant representing the top right corner of an element, used for
2169 * configuring the context element alignment
2170 * @property YAHOO.widget.Overlay.TOP_RIGHT
2175 Overlay.TOP_RIGHT = "tr";
2178 * Constant representing the top bottom left corner of an element, used for
2179 * configuring the context element alignment
2180 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2185 Overlay.BOTTOM_LEFT = "bl";
2188 * Constant representing the bottom right corner of an element, used for
2189 * configuring the context element alignment
2190 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2195 Overlay.BOTTOM_RIGHT = "br";
2197 Overlay.PREVENT_OVERLAP_X = {
2204 Overlay.PREVENT_OVERLAP_Y = {
2212 * Constant representing the default CSS class used for an Overlay
2213 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2218 Overlay.CSS_OVERLAY = "yui-overlay";
2221 * Constant representing the default hidden CSS class used for an Overlay. This class is
2222 * applied to the overlay's outer DIV whenever it's hidden.
2224 * @property YAHOO.widget.Overlay.CSS_HIDDEN
2229 Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2232 * Constant representing the default CSS class used for an Overlay iframe shim.
2234 * @property YAHOO.widget.Overlay.CSS_IFRAME
2239 Overlay.CSS_IFRAME = "yui-overlay-iframe";
2242 * Constant representing the names of the standard module elements
2243 * used in the overlay.
2244 * @property YAHOO.widget.Overlay.STD_MOD_RE
2249 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2252 * A singleton CustomEvent used for reacting to the DOM event for
2254 * @event YAHOO.widget.Overlay.windowScrollEvent
2256 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2259 * A singleton CustomEvent used for reacting to the DOM event for
2261 * @event YAHOO.widget.Overlay.windowResizeEvent
2263 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2266 * The DOM event handler used to fire the CustomEvent for window scroll
2267 * @method YAHOO.widget.Overlay.windowScrollHandler
2269 * @param {DOMEvent} e The DOM scroll event
2271 Overlay.windowScrollHandler = function (e) {
2272 var t = Event.getTarget(e);
2274 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2275 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2276 // - IE doesn't recognize scroll registered on the document.
2278 // Also, when document view is scrolled, IE doesn't provide a target,
2279 // rest of the browsers set target to window.document, apart from opera
2280 // which sets target to window.
2281 if (!t || t === window || t === window.document) {
2284 if (! window.scrollEnd) {
2285 window.scrollEnd = -1;
2288 clearTimeout(window.scrollEnd);
2290 window.scrollEnd = setTimeout(function () {
2291 Overlay.windowScrollEvent.fire();
2295 Overlay.windowScrollEvent.fire();
2301 * The DOM event handler used to fire the CustomEvent for window resize
2302 * @method YAHOO.widget.Overlay.windowResizeHandler
2304 * @param {DOMEvent} e The DOM resize event
2306 Overlay.windowResizeHandler = function (e) {
2309 if (! window.resizeEnd) {
2310 window.resizeEnd = -1;
2313 clearTimeout(window.resizeEnd);
2315 window.resizeEnd = setTimeout(function () {
2316 Overlay.windowResizeEvent.fire();
2319 Overlay.windowResizeEvent.fire();
2324 * A boolean that indicated whether the window resize and scroll events have
2325 * already been subscribed to.
2326 * @property YAHOO.widget.Overlay._initialized
2330 Overlay._initialized = null;
2332 if (Overlay._initialized === null) {
2333 Event.on(window, "scroll", Overlay.windowScrollHandler);
2334 Event.on(window, "resize", Overlay.windowResizeHandler);
2335 Overlay._initialized = true;
2339 * Internal map of special event types, which are provided
2340 * by the instance. It maps the event type to the custom event
2341 * instance. Contains entries for the "windowScroll", "windowResize" and
2342 * "textResize" static container events.
2344 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2349 Overlay._TRIGGER_MAP = {
2350 "windowScroll" : Overlay.windowScrollEvent,
2351 "windowResize" : Overlay.windowResizeEvent,
2352 "textResize" : Module.textResizeEvent
2355 YAHOO.extend(Overlay, Module, {
2359 * Array of default event types which will trigger
2360 * context alignment for the Overlay class.
2362 * <p>The array is empty by default for Overlay,
2363 * but maybe populated in future releases, so classes extending
2364 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2365 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2366 * value with their own array of values.
2370 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2373 * @property CONTEXT_TRIGGERS
2377 CONTEXT_TRIGGERS : [],
2380 * The Overlay initialization method, which is executed for Overlay and
2381 * all of its subclasses. This method is automatically called by the
2382 * constructor, and sets up all DOM references for pre-existing markup,
2383 * and creates required markup if it is not already present.
2385 * @param {String} el The element ID representing the Overlay <em>OR</em>
2386 * @param {HTMLElement} el The element representing the Overlay
2387 * @param {Object} userConfig The configuration object literal
2388 * containing the configuration that should be set for this Overlay.
2389 * See configuration documentation for more details.
2391 init: function (el, userConfig) {
2394 Note that we don't pass the user config in here yet because we
2395 only want it executed once, at the lowest subclass level
2398 Overlay.superclass.init.call(this, el/*, userConfig*/);
2400 this.beforeInitEvent.fire(Overlay);
2402 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2405 this.cfg.applyConfig(userConfig, true);
2408 if (this.platform == "mac" && UA.gecko) {
2410 if (! Config.alreadySubscribed(this.showEvent,
2411 this.showMacGeckoScrollbars, this)) {
2413 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2418 if (! Config.alreadySubscribed(this.hideEvent,
2419 this.hideMacGeckoScrollbars, this)) {
2421 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2427 this.initEvent.fire(Overlay);
2431 * Initializes the custom events for Overlay which are fired
2432 * automatically at appropriate times by the Overlay class.
2433 * @method initEvents
2435 initEvents: function () {
2437 Overlay.superclass.initEvents.call(this);
2439 var SIGNATURE = CustomEvent.LIST;
2442 * CustomEvent fired before the Overlay is moved.
2443 * @event beforeMoveEvent
2444 * @param {Number} x x coordinate
2445 * @param {Number} y y coordinate
2447 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2448 this.beforeMoveEvent.signature = SIGNATURE;
2451 * CustomEvent fired after the Overlay is moved.
2453 * @param {Number} x x coordinate
2454 * @param {Number} y y coordinate
2456 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2457 this.moveEvent.signature = SIGNATURE;
2462 * Initializes the class's configurable properties which can be changed
2463 * using the Overlay's Config object (cfg).
2464 * @method initDefaultConfig
2466 initDefaultConfig: function () {
2468 Overlay.superclass.initDefaultConfig.call(this);
2472 // Add overlay config properties //
2475 * The absolute x-coordinate position of the Overlay
2480 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2482 handler: this.configX,
2483 validator: DEFAULT_CONFIG.X.validator,
2484 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2485 supercedes: DEFAULT_CONFIG.X.supercedes
2490 * The absolute y-coordinate position of the Overlay
2495 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2497 handler: this.configY,
2498 validator: DEFAULT_CONFIG.Y.validator,
2499 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2500 supercedes: DEFAULT_CONFIG.Y.supercedes
2505 * An array with the absolute x and y positions of the Overlay
2510 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2511 handler: this.configXY,
2512 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2513 supercedes: DEFAULT_CONFIG.XY.supercedes
2518 * The array of context arguments for context-sensitive positioning.
2522 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2523 * the 5 array elements described in detail below:
2527 * <dt>contextElementOrId <String|HTMLElement></dt>
2528 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2529 * <dt>overlayCorner <String></dt>
2530 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2531 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2532 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2533 * <dt>contextCorner <String></dt>
2534 * <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>
2535 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2538 * 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>
2539 * 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.
2540 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2543 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2544 * 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).
2547 * <dt>xyOffset <Number[]></dt>
2549 * 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.
2550 * 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.
2555 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2556 * align the Overlay's top left corner to the bottom left corner of the
2557 * context element with id "img1".
2560 * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
2561 * align the Overlay's top left corner to the bottom left corner of the
2562 * 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).
2565 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2566 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2573 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2574 handler: this.configContext,
2575 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2576 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2580 * Determines whether or not the Overlay should be anchored
2581 * to the center of the viewport.
2583 * <p>This property can be set to:</p>
2588 * To enable fixed center positioning
2590 * When enabled, the overlay will
2591 * be positioned in the center of viewport when initially displayed, and
2592 * will remain in the center of the viewport whenever the window is
2593 * scrolled or resized.
2596 * If the overlay is too big for the viewport,
2597 * it's top left corner will be aligned with the top left corner of the viewport.
2602 * To disable fixed center positioning.
2603 * <p>In this case the overlay can still be
2604 * centered as a one-off operation, by invoking the <code>center()</code> method,
2605 * however it will not remain centered when the window is scrolled/resized.
2607 * <dt>"contained"<dt>
2608 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2609 * <p>However, unlike setting the property to <code>true</code>,
2610 * when the property is set to <code>"contained"</code>, if the overlay is
2611 * too big for the viewport, it will not get automatically centered when the
2612 * user scrolls or resizes the window (until the window is large enough to contain the
2613 * overlay). This is useful in cases where the Overlay has both header and footer
2614 * UI controls which the user may need to access.
2619 * @config fixedcenter
2620 * @type Boolean | String
2623 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2624 handler: this.configFixedCenter,
2625 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2626 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2627 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2631 * CSS width of the Overlay.
2636 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2637 handler: this.configWidth,
2638 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2639 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2643 * CSS height of the Overlay.
2648 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2649 handler: this.configHeight,
2650 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2651 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2655 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2656 * Supported values are "header", "body", "footer".
2658 * @config autofillheight
2662 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2663 handler: this.configAutoFillHeight,
2664 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2665 validator : this._validateAutoFill,
2666 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2670 * CSS z-index of the Overlay.
2675 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2676 handler: this.configzIndex,
2677 value: DEFAULT_CONFIG.ZINDEX.value
2681 * True if the Overlay should be prevented from being positioned
2682 * out of the viewport.
2683 * @config constraintoviewport
2687 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2689 handler: this.configConstrainToViewport,
2690 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2691 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2692 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2698 * @description Boolean indicating whether or not the Overlay should
2699 * have an IFRAME shim; used to prevent SELECT elements from
2700 * poking through an Overlay instance in IE6. When set to "true",
2701 * the iframe shim is created when the Overlay instance is intially
2704 * @default true for IE6 and below, false for all other browsers.
2706 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2708 handler: this.configIframe,
2709 value: DEFAULT_CONFIG.IFRAME.value,
2710 validator: DEFAULT_CONFIG.IFRAME.validator,
2711 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2716 * @config preventcontextoverlap
2717 * @description Boolean indicating whether or not the Overlay should overlap its
2718 * context element (defined using the "context" configuration property) when the
2719 * "constraintoviewport" configuration property is set to "true".
2723 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2724 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2725 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2726 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2731 * Moves the Overlay to the specified position. This function is
2732 * identical to calling this.cfg.setProperty("xy", [x,y]);
2734 * @param {Number} x The Overlay's new x position
2735 * @param {Number} y The Overlay's new y position
2737 moveTo: function (x, y) {
2738 this.cfg.setProperty("xy", [x, y]);
2742 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2743 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2744 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2745 * @method hideMacGeckoScrollbars
2747 hideMacGeckoScrollbars: function () {
2748 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2752 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2753 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2754 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2755 * @method showMacGeckoScrollbars
2757 showMacGeckoScrollbars: function () {
2758 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2762 * Internal implementation to set the visibility of the overlay in the DOM.
2764 * @method _setDomVisibility
2765 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2768 _setDomVisibility : function(show) {
2769 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2770 var hiddenClass = Overlay.CSS_HIDDEN;
2773 Dom.removeClass(this.element, hiddenClass);
2775 Dom.addClass(this.element, hiddenClass);
2779 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2781 * The default event handler fired when the "visible" property is
2782 * changed. This method is responsible for firing showEvent
2784 * @method configVisible
2785 * @param {String} type The CustomEvent type (usually the property name)
2786 * @param {Object[]} args The CustomEvent arguments. For configuration
2787 * handlers, args[0] will equal the newly applied value for the property.
2788 * @param {Object} obj The scope object. For configuration handlers,
2789 * this will usually equal the owner.
2791 configVisible: function (type, args, obj) {
2793 var visible = args[0],
2794 currentVis = Dom.getStyle(this.element, "visibility"),
2795 effects = this._cachedEffects || this._createEffects(this.cfg.getProperty("effect")),
2796 isMacGecko = (this.platform == "mac" && UA.gecko),
2797 alreadySubscribed = Config.alreadySubscribed,
2801 if (currentVis == "inherit") {
2802 e = this.element.parentNode;
2804 while (e.nodeType != 9 && e.nodeType != 11) {
2805 currentVis = Dom.getStyle(e, "visibility");
2807 if (currentVis != "inherit") {
2814 if (currentVis == "inherit") {
2815 currentVis = "visible";
2819 if (visible) { // Show
2822 this.showMacGeckoScrollbars();
2825 if (effects) { // Animate in
2826 if (visible) { // Animate in if not showing
2828 // Fading out is a bit of a hack, but didn't want to risk doing
2829 // something broader (e.g a generic this._animatingOut) for 2.9.0
2831 if (currentVis != "visible" || currentVis === "" || this._fadingOut) {
2832 if (this.beforeShowEvent.fire()) {
2834 nEffectInstances = effects.length;
2836 for (j = 0; j < nEffectInstances; j++) {
2838 if (j === 0 && !alreadySubscribed(ei.animateInCompleteEvent, this.showEvent.fire, this.showEvent)) {
2839 ei.animateInCompleteEvent.subscribe(this.showEvent.fire, this.showEvent, true);
2847 if (currentVis != "visible" || currentVis === "") {
2848 if (this.beforeShowEvent.fire()) {
2849 this._setDomVisibility(true);
2850 this.cfg.refireEvent("iframe");
2851 this.showEvent.fire();
2854 this._setDomVisibility(true);
2860 this.hideMacGeckoScrollbars();
2863 if (effects) { // Animate out if showing
2864 if (currentVis == "visible" || this._fadingIn) {
2865 if (this.beforeHideEvent.fire()) {
2866 nEffectInstances = effects.length;
2867 for (k = 0; k < nEffectInstances; k++) {
2870 if (k === 0 && !alreadySubscribed(h.animateOutCompleteEvent, this.hideEvent.fire, this.hideEvent)) {
2871 h.animateOutCompleteEvent.subscribe(this.hideEvent.fire, this.hideEvent, true);
2877 } else if (currentVis === "") {
2878 this._setDomVisibility(false);
2881 } else { // Simple hide
2883 if (currentVis == "visible" || currentVis === "") {
2884 if (this.beforeHideEvent.fire()) {
2885 this._setDomVisibility(false);
2886 this.hideEvent.fire();
2889 this._setDomVisibility(false);
2896 * Fixed center event handler used for centering on scroll/resize, but only if
2897 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2898 * the overlay fits within the viewport.
2900 * @method doCenterOnDOMEvent
2902 doCenterOnDOMEvent: function () {
2904 fc = cfg.getProperty("fixedcenter");
2906 if (cfg.getProperty("visible")) {
2907 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2914 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2915 * will fit entirely inside the viewport, in both dimensions - width and height.
2917 * @method fitsInViewport
2918 * @return boolean true if the Overlay will fit, false if not
2920 fitsInViewport : function() {
2921 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2922 element = this.element,
2923 elementWidth = element.offsetWidth,
2924 elementHeight = element.offsetHeight,
2925 viewportWidth = Dom.getViewportWidth(),
2926 viewportHeight = Dom.getViewportHeight();
2928 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2932 * The default event handler fired when the "fixedcenter" property
2934 * @method configFixedCenter
2935 * @param {String} type The CustomEvent type (usually the property name)
2936 * @param {Object[]} args The CustomEvent arguments. For configuration
2937 * handlers, args[0] will equal the newly applied value for the property.
2938 * @param {Object} obj The scope object. For configuration handlers,
2939 * this will usually equal the owner.
2941 configFixedCenter: function (type, args, obj) {
2944 alreadySubscribed = Config.alreadySubscribed,
2945 windowResizeEvent = Overlay.windowResizeEvent,
2946 windowScrollEvent = Overlay.windowScrollEvent;
2951 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2952 this.beforeShowEvent.subscribe(this.center);
2955 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2956 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2959 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2960 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2964 this.beforeShowEvent.unsubscribe(this.center);
2966 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2967 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2972 * The default event handler fired when the "height" property is changed.
2973 * @method configHeight
2974 * @param {String} type The CustomEvent type (usually the property name)
2975 * @param {Object[]} args The CustomEvent arguments. For configuration
2976 * handlers, args[0] will equal the newly applied value for the property.
2977 * @param {Object} obj The scope object. For configuration handlers,
2978 * this will usually equal the owner.
2980 configHeight: function (type, args, obj) {
2982 var height = args[0],
2985 Dom.setStyle(el, "height", height);
2986 this.cfg.refireEvent("iframe");
2990 * The default event handler fired when the "autofillheight" property is changed.
2991 * @method configAutoFillHeight
2993 * @param {String} type The CustomEvent type (usually the property name)
2994 * @param {Object[]} args The CustomEvent arguments. For configuration
2995 * handlers, args[0] will equal the newly applied value for the property.
2996 * @param {Object} obj The scope object. For configuration handlers,
2997 * this will usually equal the owner.
2999 configAutoFillHeight: function (type, args, obj) {
3000 var fillEl = args[0],
3002 autoFillHeight = "autofillheight",
3004 currEl = cfg.getProperty(autoFillHeight),
3005 autoFill = this._autoFillOnHeightChange;
3007 cfg.unsubscribeFromConfigEvent(height, autoFill);
3008 Module.textResizeEvent.unsubscribe(autoFill);
3009 this.changeContentEvent.unsubscribe(autoFill);
3011 if (currEl && fillEl !== currEl && this[currEl]) {
3012 Dom.setStyle(this[currEl], height, "");
3016 fillEl = Lang.trim(fillEl.toLowerCase());
3018 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
3019 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
3020 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
3022 cfg.setProperty(autoFillHeight, fillEl, true);
3027 * The default event handler fired when the "width" property is changed.
3028 * @method configWidth
3029 * @param {String} type The CustomEvent type (usually the property name)
3030 * @param {Object[]} args The CustomEvent arguments. For configuration
3031 * handlers, args[0] will equal the newly applied value for the property.
3032 * @param {Object} obj The scope object. For configuration handlers,
3033 * this will usually equal the owner.
3035 configWidth: function (type, args, obj) {
3037 var width = args[0],
3040 Dom.setStyle(el, "width", width);
3041 this.cfg.refireEvent("iframe");
3045 * The default event handler fired when the "zIndex" property is changed.
3046 * @method configzIndex
3047 * @param {String} type The CustomEvent type (usually the property name)
3048 * @param {Object[]} args The CustomEvent arguments. For configuration
3049 * handlers, args[0] will equal the newly applied value for the property.
3050 * @param {Object} obj The scope object. For configuration handlers,
3051 * this will usually equal the owner.
3053 configzIndex: function (type, args, obj) {
3055 var zIndex = args[0],
3059 zIndex = Dom.getStyle(el, "zIndex");
3060 if (! zIndex || isNaN(zIndex)) {
3065 if (this.iframe || this.cfg.getProperty("iframe") === true) {
3071 Dom.setStyle(el, "zIndex", zIndex);
3072 this.cfg.setProperty("zIndex", zIndex, true);
3080 * The default event handler fired when the "xy" property is changed.
3082 * @param {String} type The CustomEvent type (usually the property name)
3083 * @param {Object[]} args The CustomEvent arguments. For configuration
3084 * handlers, args[0] will equal the newly applied value for the property.
3085 * @param {Object} obj The scope object. For configuration handlers,
3086 * this will usually equal the owner.
3088 configXY: function (type, args, obj) {
3094 this.cfg.setProperty("x", x);
3095 this.cfg.setProperty("y", y);
3097 this.beforeMoveEvent.fire([x, y]);
3099 x = this.cfg.getProperty("x");
3100 y = this.cfg.getProperty("y");
3103 this.cfg.refireEvent("iframe");
3104 this.moveEvent.fire([x, y]);
3108 * The default event handler fired when the "x" property is changed.
3110 * @param {String} type The CustomEvent type (usually the property name)
3111 * @param {Object[]} args The CustomEvent arguments. For configuration
3112 * handlers, args[0] will equal the newly applied value for the property.
3113 * @param {Object} obj The scope object. For configuration handlers,
3114 * this will usually equal the owner.
3116 configX: function (type, args, obj) {
3119 y = this.cfg.getProperty("y");
3121 this.cfg.setProperty("x", x, true);
3122 this.cfg.setProperty("y", y, true);
3124 this.beforeMoveEvent.fire([x, y]);
3126 x = this.cfg.getProperty("x");
3127 y = this.cfg.getProperty("y");
3129 Dom.setX(this.element, x, true);
3131 this.cfg.setProperty("xy", [x, y], true);
3133 this.cfg.refireEvent("iframe");
3134 this.moveEvent.fire([x, y]);
3138 * The default event handler fired when the "y" property is changed.
3140 * @param {String} type The CustomEvent type (usually the property name)
3141 * @param {Object[]} args The CustomEvent arguments. For configuration
3142 * handlers, args[0] will equal the newly applied value for the property.
3143 * @param {Object} obj The scope object. For configuration handlers,
3144 * this will usually equal the owner.
3146 configY: function (type, args, obj) {
3148 var x = this.cfg.getProperty("x"),
3151 this.cfg.setProperty("x", x, true);
3152 this.cfg.setProperty("y", y, true);
3154 this.beforeMoveEvent.fire([x, y]);
3156 x = this.cfg.getProperty("x");
3157 y = this.cfg.getProperty("y");
3159 Dom.setY(this.element, y, true);
3161 this.cfg.setProperty("xy", [x, y], true);
3163 this.cfg.refireEvent("iframe");
3164 this.moveEvent.fire([x, y]);
3168 * Shows the iframe shim, if it has been enabled.
3169 * @method showIframe
3171 showIframe: function () {
3173 var oIFrame = this.iframe,
3177 oParentNode = this.element.parentNode;
3179 if (oParentNode != oIFrame.parentNode) {
3180 this._addToParent(oParentNode, oIFrame);
3182 oIFrame.style.display = "block";
3187 * Hides the iframe shim, if it has been enabled.
3188 * @method hideIframe
3190 hideIframe: function () {
3192 this.iframe.style.display = "none";
3197 * Syncronizes the size and position of iframe shim to that of its
3198 * corresponding Overlay instance.
3199 * @method syncIframe
3201 syncIframe: function () {
3203 var oIFrame = this.iframe,
3204 oElement = this.element,
3205 nOffset = Overlay.IFRAME_OFFSET,
3206 nDimensionOffset = (nOffset * 2),
3211 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3212 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3214 // Position <iframe>
3215 aXY = this.cfg.getProperty("xy");
3217 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3218 this.syncPosition();
3219 aXY = this.cfg.getProperty("xy");
3221 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3226 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3227 * the Overlay element. The zindex of the iframe is set to be one less
3228 * than the Overlay element's zindex.
3230 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3231 * to ensure that the iframe shim has a non-negative zindex.
3232 * If you require the iframe zindex to be 0 or higher, the zindex of
3233 * the Overlay element should be set to a value greater than 0, before
3234 * this method is called.
3236 * @method stackIframe
3238 stackIframe: function () {
3240 var overlayZ = Dom.getStyle(this.element, "zIndex");
3241 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3242 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3248 * The default event handler fired when the "iframe" property is changed.
3249 * @method configIframe
3250 * @param {String} type The CustomEvent type (usually the property name)
3251 * @param {Object[]} args The CustomEvent arguments. For configuration
3252 * handlers, args[0] will equal the newly applied value for the property.
3253 * @param {Object} obj The scope object. For configuration handlers,
3254 * this will usually equal the owner.
3256 configIframe: function (type, args, obj) {
3258 var bIFrame = args[0];
3260 function createIFrame() {
3262 var oIFrame = this.iframe,
3263 oElement = this.element,
3267 if (!m_oIFrameTemplate) {
3268 m_oIFrameTemplate = document.createElement("iframe");
3270 if (this.isSecure) {
3271 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3275 Set the opacity of the <iframe> to 0 so that it
3276 doesn't modify the opacity of any transparent
3277 elements that may be on top of it (like a shadow).
3280 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3282 Need to set the "frameBorder" property to 0
3283 supress the default <iframe> border in IE.
3284 Setting the CSS "border" property alone
3287 m_oIFrameTemplate.frameBorder = 0;
3290 m_oIFrameTemplate.style.opacity = "0";
3293 m_oIFrameTemplate.style.position = "absolute";
3294 m_oIFrameTemplate.style.border = "none";
3295 m_oIFrameTemplate.style.margin = "0";
3296 m_oIFrameTemplate.style.padding = "0";
3297 m_oIFrameTemplate.style.display = "none";
3298 m_oIFrameTemplate.tabIndex = -1;
3299 m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3302 oIFrame = m_oIFrameTemplate.cloneNode(false);
3303 oIFrame.id = this.id + "_f";
3304 oParent = oElement.parentNode;
3306 var parentNode = oParent || document.body;
3308 this._addToParent(parentNode, oIFrame);
3309 this.iframe = oIFrame;
3313 Show the <iframe> before positioning it since the "setXY"
3314 method of DOM requires the element be in the document
3320 Syncronize the size and position of the <iframe> to that
3326 // Add event listeners to update the <iframe> when necessary
3327 if (!this._hasIframeEventListeners) {
3328 this.showEvent.subscribe(this.showIframe);
3329 this.hideEvent.subscribe(this.hideIframe);
3330 this.changeContentEvent.subscribe(this.syncIframe);
3332 this._hasIframeEventListeners = true;
3336 function onBeforeShow() {
3337 createIFrame.call(this);
3338 this.beforeShowEvent.unsubscribe(onBeforeShow);
3339 this._iframeDeferred = false;
3342 if (bIFrame) { // <iframe> shim is enabled
3344 if (this.cfg.getProperty("visible")) {
3345 createIFrame.call(this);
3347 if (!this._iframeDeferred) {
3348 this.beforeShowEvent.subscribe(onBeforeShow);
3349 this._iframeDeferred = true;
3353 } else { // <iframe> shim is disabled
3356 if (this._hasIframeEventListeners) {
3357 this.showEvent.unsubscribe(this.showIframe);
3358 this.hideEvent.unsubscribe(this.hideIframe);
3359 this.changeContentEvent.unsubscribe(this.syncIframe);
3361 this._hasIframeEventListeners = false;
3367 * Set's the container's XY value from DOM if not already set.
3369 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3370 * not already set. The method also refire's the XY config property event, so any
3371 * beforeMove, Move event listeners are invoked.
3373 * @method _primeXYFromDOM
3376 _primeXYFromDOM : function() {
3377 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3378 // Set CFG XY based on DOM XY
3379 this.syncPosition();
3380 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3381 this.cfg.refireEvent("xy");
3382 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3387 * The default event handler fired when the "constraintoviewport"
3388 * property is changed.
3389 * @method configConstrainToViewport
3390 * @param {String} type The CustomEvent type (usually the property name)
3391 * @param {Object[]} args The CustomEvent arguments. For configuration
3392 * handlers, args[0] will equal the newly applied value for
3394 * @param {Object} obj The scope object. For configuration handlers,
3395 * this will usually equal the owner.
3397 configConstrainToViewport: function (type, args, obj) {
3401 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3402 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3404 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3405 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3408 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3409 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3414 * The default event handler fired when the "context" property
3417 * @method configContext
3418 * @param {String} type The CustomEvent type (usually the property name)
3419 * @param {Object[]} args The CustomEvent arguments. For configuration
3420 * handlers, args[0] will equal the newly applied value for the property.
3421 * @param {Object} obj The scope object. For configuration handlers,
3422 * this will usually equal the owner.
3424 configContext: function (type, args, obj) {
3426 var contextArgs = args[0],
3428 elementMagnetCorner,
3429 contextMagnetCorner,
3432 defTriggers = this.CONTEXT_TRIGGERS;
3436 contextEl = contextArgs[0];
3437 elementMagnetCorner = contextArgs[1];
3438 contextMagnetCorner = contextArgs[2];
3439 triggers = contextArgs[3];
3440 offset = contextArgs[4];
3442 if (defTriggers && defTriggers.length > 0) {
3443 triggers = (triggers || []).concat(defTriggers);
3447 if (typeof contextEl == "string") {
3448 this.cfg.setProperty("context", [
3449 document.getElementById(contextEl),
3450 elementMagnetCorner,
3451 contextMagnetCorner,
3457 if (elementMagnetCorner && contextMagnetCorner) {
3458 this.align(elementMagnetCorner, contextMagnetCorner, offset);
3461 if (this._contextTriggers) {
3462 // Unsubscribe Old Set
3463 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3467 // Subscribe New Set
3468 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3469 this._contextTriggers = triggers;
3476 * Custom Event handler for context alignment triggers. Invokes the align method
3478 * @method _alignOnTrigger
3481 * @param {String} type The event type (not used by the default implementation)
3482 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3484 _alignOnTrigger: function(type, args) {
3489 * Helper method to locate the custom event instance for the event name string
3490 * passed in. As a convenience measure, any custom events passed in are returned.
3492 * @method _findTriggerCE
3495 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3496 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3498 _findTriggerCE : function(t) {
3500 if (t instanceof CustomEvent) {
3502 } else if (Overlay._TRIGGER_MAP[t]) {
3503 tce = Overlay._TRIGGER_MAP[t];
3509 * Utility method that subscribes or unsubscribes the given
3510 * function from the list of trigger events provided.
3512 * @method _processTriggers
3515 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3516 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3517 * subscribed/unsubscribed respectively.
3519 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3520 * we are subscribing or unsubscribing trigger listeners
3522 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3523 * Context is always set to the overlay instance, and no additional object argument
3524 * get passed to the subscribed function.
3526 _processTriggers : function(triggers, mode, fn) {
3529 for (var i = 0, l = triggers.length; i < l; ++i) {
3531 tce = this._findTriggerCE(t);
3533 tce[mode](fn, this, true);
3540 // END BUILT-IN PROPERTY EVENT HANDLERS //
3542 * Aligns the Overlay to its context element using the specified corner
3543 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3546 * @param {String} elementAlign The String representing the corner of
3547 * the Overlay that should be aligned to the context element
3548 * @param {String} contextAlign The corner of the context element
3549 * that the elementAlign corner should stick to.
3550 * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3551 * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
3552 * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3554 align: function (elementAlign, contextAlign, xyOffset) {
3556 var contextArgs = this.cfg.getProperty("context"),
3562 function doAlign(v, h) {
3564 var alignX = null, alignY = null;
3566 switch (elementAlign) {
3568 case Overlay.TOP_LEFT:
3573 case Overlay.TOP_RIGHT:
3574 alignX = h - element.offsetWidth;
3578 case Overlay.BOTTOM_LEFT:
3580 alignY = v - element.offsetHeight;
3583 case Overlay.BOTTOM_RIGHT:
3584 alignX = h - element.offsetWidth;
3585 alignY = v - element.offsetHeight;
3589 if (alignX !== null && alignY !== null) {
3591 alignX += xyOffset[0];
3592 alignY += xyOffset[1];
3594 me.moveTo(alignX, alignY);
3599 context = contextArgs[0];
3600 element = this.element;
3603 if (! elementAlign) {
3604 elementAlign = contextArgs[1];
3607 if (! contextAlign) {
3608 contextAlign = contextArgs[2];
3611 if (!xyOffset && contextArgs[4]) {
3612 xyOffset = contextArgs[4];
3615 if (element && context) {
3616 contextRegion = Dom.getRegion(context);
3618 switch (contextAlign) {
3620 case Overlay.TOP_LEFT:
3621 doAlign(contextRegion.top, contextRegion.left);
3624 case Overlay.TOP_RIGHT:
3625 doAlign(contextRegion.top, contextRegion.right);
3628 case Overlay.BOTTOM_LEFT:
3629 doAlign(contextRegion.bottom, contextRegion.left);
3632 case Overlay.BOTTOM_RIGHT:
3633 doAlign(contextRegion.bottom, contextRegion.right);
3641 * The default event handler executed when the moveEvent is fired, if the
3642 * "constraintoviewport" is set to true.
3643 * @method enforceConstraints
3644 * @param {String} type The CustomEvent type (usually the property name)
3645 * @param {Object[]} args The CustomEvent arguments. For configuration
3646 * handlers, args[0] will equal the newly applied value for the property.
3647 * @param {Object} obj The scope object. For configuration handlers,
3648 * this will usually equal the owner.
3650 enforceConstraints: function (type, args, obj) {
3653 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3654 this.cfg.setProperty("x", cXY[0], true);
3655 this.cfg.setProperty("y", cXY[1], true);
3656 this.cfg.setProperty("xy", cXY, true);
3660 * Shared implementation method for getConstrainedX and getConstrainedY.
3663 * Given a coordinate value, returns the calculated coordinate required to
3664 * position the Overlay if it is to be constrained to the viewport, based on the
3665 * current element size, viewport dimensions, scroll values and preventoverlap
3669 * @method _getConstrainedPos
3671 * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3672 * @param {Number} The coordinate value which needs to be constrained
3673 * @return {Number} The constrained coordinate value
3675 _getConstrainedPos: function(pos, val) {
3677 var overlayEl = this.element,
3679 buffer = Overlay.VIEWPORT_OFFSET,
3683 overlaySize = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3684 viewportSize = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3685 docScroll = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3686 overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3688 context = this.cfg.getProperty("context"),
3690 bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3691 bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3693 minConstraint = docScroll + buffer,
3694 maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3696 constrainedVal = val;
3698 if (val < minConstraint || val > maxConstraint) {
3699 if (bPreventContextOverlap) {
3700 constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3702 if (bOverlayFitsInViewport) {
3703 if (val < minConstraint) {
3704 constrainedVal = minConstraint;
3705 } else if (val > maxConstraint) {
3706 constrainedVal = maxConstraint;
3709 constrainedVal = minConstraint;
3714 return constrainedVal;
3718 * Helper method, used to position the Overlap to prevent overlap with the
3719 * context element (used when preventcontextoverlap is enabled)
3721 * @method _preventOverlap
3723 * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3724 * @param {HTMLElement} contextEl The context element
3725 * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3726 * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3727 * @param {Object} docScroll The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3729 * @return {Number} The new coordinate value which was set to prevent overlap
3731 _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3733 var x = (pos == "x"),
3735 buffer = Overlay.VIEWPORT_OFFSET,
3739 contextElPos = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3740 contextElSize = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3742 minRegionSize = contextElPos - buffer,
3743 maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3747 flip = function () {
3750 if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3751 flippedVal = (contextElPos - overlaySize);
3753 flippedVal = (contextElPos + contextElSize);
3756 overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3761 setPosition = function () {
3763 var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3766 if (overlaySize > displayRegionSize) {
3769 All possible positions and values have been
3770 tried, but none were successful, so fall back
3771 to the original size and position.
3777 position = setPosition();
3786 return this.cfg.getProperty(pos);
3790 * Given x coordinate value, returns the calculated x coordinate required to
3791 * position the Overlay if it is to be constrained to the viewport, based on the
3792 * current element size, viewport dimensions and scroll values.
3794 * @param {Number} x The X coordinate value to be constrained
3795 * @return {Number} The constrained x coordinate
3797 getConstrainedX: function (x) {
3798 return this._getConstrainedPos("x", x);
3802 * Given y coordinate value, returns the calculated y coordinate required to
3803 * position the Overlay if it is to be constrained to the viewport, based on the
3804 * current element size, viewport dimensions and scroll values.
3806 * @param {Number} y The Y coordinate value to be constrained
3807 * @return {Number} The constrained y coordinate
3809 getConstrainedY : function (y) {
3810 return this._getConstrainedPos("y", y);
3814 * Given x, y coordinate values, returns the calculated coordinates required to
3815 * position the Overlay if it is to be constrained to the viewport, based on the
3816 * current element size, viewport dimensions and scroll values.
3818 * @param {Number} x The X coordinate value to be constrained
3819 * @param {Number} y The Y coordinate value to be constrained
3820 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3822 getConstrainedXY: function(x, y) {
3823 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3827 * Centers the container in the viewport.
3830 center: function () {
3832 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3833 elementWidth = this.element.offsetWidth,
3834 elementHeight = this.element.offsetHeight,
3835 viewPortWidth = Dom.getViewportWidth(),
3836 viewPortHeight = Dom.getViewportHeight(),
3840 if (elementWidth < viewPortWidth) {
3841 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3843 x = nViewportOffset + Dom.getDocumentScrollLeft();
3846 if (elementHeight < viewPortHeight) {
3847 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3849 y = nViewportOffset + Dom.getDocumentScrollTop();
3852 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3853 this.cfg.refireEvent("iframe");
3856 this.forceContainerRedraw();
3861 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3862 * Panel's position in the DOM. This is primarily used to update
3863 * position information during drag & drop.
3864 * @method syncPosition
3866 syncPosition: function () {
3868 var pos = Dom.getXY(this.element);
3870 this.cfg.setProperty("x", pos[0], true);
3871 this.cfg.setProperty("y", pos[1], true);
3872 this.cfg.setProperty("xy", pos, true);
3877 * Event handler fired when the resize monitor element is resized.
3878 * @method onDomResize
3879 * @param {DOMEvent} e The resize DOM event
3880 * @param {Object} obj The scope object
3882 onDomResize: function (e, obj) {
3886 Overlay.superclass.onDomResize.call(this, e, obj);
3888 setTimeout(function () {
3890 me.cfg.refireEvent("iframe");
3891 me.cfg.refireEvent("context");
3896 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3898 * @method _getComputedHeight
3900 * @param {HTMLElement} el The element for which the content height needs to be determined
3901 * @return {Number} The content box height of the given element, or null if it could not be determined.
3903 _getComputedHeight : (function() {
3905 if (document.defaultView && document.defaultView.getComputedStyle) {
3906 return function(el) {
3908 if (el.ownerDocument && el.ownerDocument.defaultView) {
3909 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3911 height = parseInt(computed.height, 10);
3914 return (Lang.isNumber(height)) ? height : null;
3917 return function(el) {
3919 if (el.style.pixelHeight) {
3920 height = el.style.pixelHeight;
3922 return (Lang.isNumber(height)) ? height : null;
3928 * autofillheight validator. Verifies that the autofill value is either null
3929 * or one of the strings : "body", "header" or "footer".
3931 * @method _validateAutoFillHeight
3933 * @param {String} val
3934 * @return true, if valid, false otherwise
3936 _validateAutoFillHeight : function(val) {
3937 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3941 * The default custom event handler executed when the overlay's height is changed,
3942 * if the autofillheight property has been set.
3944 * @method _autoFillOnHeightChange
3946 * @param {String} type The event type
3947 * @param {Array} args The array of arguments passed to event subscribers
3948 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3949 * out the containers height
3951 _autoFillOnHeightChange : function(type, args, el) {
3952 var height = this.cfg.getProperty("height");
3953 if ((height && height !== "auto") || (height === 0)) {
3954 this.fillHeight(el);
3959 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3960 * otherwise returns the offsetHeight
3961 * @method _getPreciseHeight
3963 * @param {HTMLElement} el
3964 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3966 _getPreciseHeight : function(el) {
3967 var height = el.offsetHeight;
3969 if (el.getBoundingClientRect) {
3970 var rect = el.getBoundingClientRect();
3971 height = rect.bottom - rect.top;
3979 * Sets the height on the provided header, body or footer element to
3980 * fill out the height of the container. It determines the height of the
3981 * containers content box, based on it's configured height value, and
3982 * sets the height of the autofillheight element to fill out any
3983 * space remaining after the other standard module element heights
3984 * have been accounted for.
3986 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
3987 * height has not been set on the container, since for an "auto" height container,
3988 * the heights of the header/body/footer will drive the height of the container.</p>
3990 * @method fillHeight
3991 * @param {HTMLElement} el The element which should be resized to fill out the height
3992 * of the container element.
3994 fillHeight : function(el) {
3996 var container = this.innerElement || this.element,
3997 containerEls = [this.header, this.body, this.footer],
4004 for (var i = 0, l = containerEls.length; i < l; i++) {
4005 containerEl = containerEls[i];
4007 if (el !== containerEl) {
4008 filled += this._getPreciseHeight(containerEl);
4017 if (UA.ie || UA.opera) {
4018 // Need to set height to 0, to allow height to be reduced
4019 Dom.setStyle(el, 'height', 0 + 'px');
4022 total = this._getComputedHeight(container);
4024 // Fallback, if we can't get computed value for content height
4025 if (total === null) {
4026 Dom.addClass(container, "yui-override-padding");
4027 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4028 Dom.removeClass(container, "yui-override-padding");
4031 remaining = Math.max(total - filled, 0);
4033 Dom.setStyle(el, "height", remaining + "px");
4035 // Re-adjust height if required, to account for el padding and border
4036 if (el.offsetHeight != remaining) {
4037 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4039 Dom.setStyle(el, "height", remaining + "px");
4045 * Places the Overlay on top of all other instances of
4046 * YAHOO.widget.Overlay.
4047 * @method bringToTop
4049 bringToTop: function () {
4052 oElement = this.element;
4054 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4056 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4057 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4059 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4060 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4062 if (nZIndex1 > nZIndex2) {
4064 } else if (nZIndex1 < nZIndex2) {
4071 function isOverlayElement(p_oElement) {
4073 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4074 Panel = YAHOO.widget.Panel;
4076 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4077 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4078 aOverlays[aOverlays.length] = p_oElement.parentNode;
4080 aOverlays[aOverlays.length] = p_oElement;
4085 Dom.getElementsBy(isOverlayElement, "div", document.body);
4087 aOverlays.sort(compareZIndexDesc);
4089 var oTopOverlay = aOverlays[0],
4093 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4095 if (!isNaN(nTopZIndex)) {
4096 var bRequiresBump = false;
4098 if (oTopOverlay != oElement) {
4099 bRequiresBump = true;
4100 } else if (aOverlays.length > 1) {
4101 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4102 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4103 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4104 bRequiresBump = true;
4107 if (bRequiresBump) {
4108 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4115 * Removes the Overlay element from the DOM and sets all child
4118 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
4119 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
4121 destroy: function (shallowPurge) {
4124 this.iframe.parentNode.removeChild(this.iframe);
4129 Overlay.windowResizeEvent.unsubscribe(
4130 this.doCenterOnDOMEvent, this);
4132 Overlay.windowScrollEvent.unsubscribe(
4133 this.doCenterOnDOMEvent, this);
4135 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4137 if (this._contextTriggers) {
4138 // Unsubscribe context triggers - to cover context triggers which listen for global
4139 // events such as windowResize and windowScroll. Easier just to unsubscribe all
4140 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4143 Overlay.superclass.destroy.call(this, shallowPurge);
4147 * Can be used to force the container to repaint/redraw it's contents.
4149 * By default applies and then removes a 1px bottom margin through the
4150 * application/removal of a "yui-force-redraw" class.
4153 * It is currently used by Overlay to force a repaint for webkit
4154 * browsers, when centering.
4156 * @method forceContainerRedraw
4158 forceContainerRedraw : function() {
4160 Dom.addClass(c.element, "yui-force-redraw");
4161 setTimeout(function() {
4162 Dom.removeClass(c.element, "yui-force-redraw");
4167 * Returns a String representation of the object.
4169 * @return {String} The string representation of the Overlay.
4171 toString: function () {
4172 return "Overlay " + this.id;
4180 * OverlayManager is used for maintaining the focus status of
4181 * multiple Overlays.
4182 * @namespace YAHOO.widget
4183 * @namespace YAHOO.widget
4184 * @class OverlayManager
4186 * @param {Array} overlays Optional. A collection of Overlays to register
4188 * @param {Object} userConfig The object literal representing the user
4189 * configuration of the OverlayManager
4191 YAHOO.widget.OverlayManager = function (userConfig) {
4192 this.init(userConfig);
4195 var Overlay = YAHOO.widget.Overlay,
4196 Event = YAHOO.util.Event,
4197 Dom = YAHOO.util.Dom,
4198 Config = YAHOO.util.Config,
4199 CustomEvent = YAHOO.util.CustomEvent,
4200 OverlayManager = YAHOO.widget.OverlayManager;
4203 * The CSS class representing a focused Overlay
4204 * @property OverlayManager.CSS_FOCUSED
4209 OverlayManager.CSS_FOCUSED = "focused";
4211 OverlayManager.prototype = {
4214 * The class's constructor function
4215 * @property contructor
4218 constructor: OverlayManager,
4221 * The array of Overlays that are currently registered
4222 * @property overlays
4223 * @type YAHOO.widget.Overlay[]
4228 * Initializes the default configuration of the OverlayManager
4229 * @method initDefaultConfig
4231 initDefaultConfig: function () {
4233 * The collection of registered Overlays in use by
4234 * the OverlayManager
4236 * @type YAHOO.widget.Overlay[]
4239 this.cfg.addProperty("overlays", { suppressEvent: true } );
4242 * The default DOM event that should be used to focus an Overlay
4243 * @config focusevent
4245 * @default "mousedown"
4247 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4251 * Initializes the OverlayManager
4253 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4254 * register with the manager.
4255 * @param {Object} userConfig The object literal representing the user
4256 * configuration of the OverlayManager
4258 init: function (userConfig) {
4261 * The OverlayManager's Config object used for monitoring
4262 * configuration properties.
4266 this.cfg = new Config(this);
4268 this.initDefaultConfig();
4271 this.cfg.applyConfig(userConfig, true);
4273 this.cfg.fireQueue();
4276 * The currently activated Overlay
4277 * @property activeOverlay
4279 * @type YAHOO.widget.Overlay
4281 var activeOverlay = null;
4284 * Returns the currently focused Overlay
4286 * @return {Overlay} The currently focused Overlay
4288 this.getActive = function () {
4289 return activeOverlay;
4293 * Focuses the specified Overlay
4295 * @param {Overlay} overlay The Overlay to focus
4296 * @param {String} overlay The id of the Overlay to focus
4298 this.focus = function (overlay) {
4299 var o = this.find(overlay);
4306 * Removes the specified Overlay from the manager
4308 * @param {Overlay} overlay The Overlay to remove
4309 * @param {String} overlay The id of the Overlay to remove
4311 this.remove = function (overlay) {
4313 var o = this.find(overlay),
4317 if (activeOverlay == o) {
4318 activeOverlay = null;
4321 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4324 // Set it's zindex so that it's sorted to the end.
4325 originalZ = Dom.getStyle(o.element, "zIndex");
4326 o.cfg.setProperty("zIndex", -1000, true);
4329 this.overlays.sort(this.compareZIndexDesc);
4330 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4332 o.hideEvent.unsubscribe(o.blur);
4333 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4334 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4335 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4338 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4339 o.cfg.setProperty("zIndex", originalZ, true);
4340 o.cfg.setProperty("manager", null);
4343 /* _managed Flag for custom or existing. Don't want to remove existing */
4344 if (o.focusEvent._managed) { o.focusEvent = null; }
4345 if (o.blurEvent._managed) { o.blurEvent = null; }
4347 if (o.focus._managed) { o.focus = null; }
4348 if (o.blur._managed) { o.blur = null; }
4353 * Removes focus from all registered Overlays in the manager
4356 this.blurAll = function () {
4358 var nOverlays = this.overlays.length,
4361 if (nOverlays > 0) {
4364 this.overlays[i].blur();
4371 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4374 * @method _manageBlur
4375 * @param {Overlay} overlay The overlay instance which got blurred.
4378 this._manageBlur = function (overlay) {
4379 var changed = false;
4380 if (activeOverlay == overlay) {
4381 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4382 activeOverlay = null;
4389 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4392 * @method _manageFocus
4393 * @param {Overlay} overlay The overlay instance which got focus.
4396 this._manageFocus = function(overlay) {
4397 var changed = false;
4398 if (activeOverlay != overlay) {
4399 if (activeOverlay) {
4400 activeOverlay.blur();
4402 activeOverlay = overlay;
4403 this.bringToTop(activeOverlay);
4404 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4410 var overlays = this.cfg.getProperty("overlays");
4412 if (! this.overlays) {
4417 this.register(overlays);
4418 this.overlays.sort(this.compareZIndexDesc);
4423 * @method _onOverlayElementFocus
4424 * @description Event handler for the DOM event that is used to focus
4425 * the Overlay instance as specified by the "focusevent"
4426 * configuration property.
4428 * @param {Event} p_oEvent Object representing the DOM event
4429 * object passed back by the event utility (Event).
4431 _onOverlayElementFocus: function (p_oEvent) {
4433 var oTarget = Event.getTarget(p_oEvent),
4434 oClose = this.close;
4436 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4444 * @method _onOverlayDestroy
4445 * @description "destroy" event handler for the Overlay.
4447 * @param {String} p_sType String representing the name of the event
4449 * @param {Array} p_aArgs Array of arguments sent when the event
4451 * @param {Overlay} p_oOverlay Object representing the overlay that
4454 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4455 this.remove(p_oOverlay);
4459 * @method _onOverlayFocusHandler
4461 * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4464 * @param {String} p_sType String representing the name of the event
4466 * @param {Array} p_aArgs Array of arguments sent when the event
4468 * @param {Overlay} p_oOverlay Object representing the overlay that
4471 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4472 this._manageFocus(p_oOverlay);
4476 * @method _onOverlayBlurHandler
4477 * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4480 * @param {String} p_sType String representing the name of the event
4482 * @param {Array} p_aArgs Array of arguments sent when the event
4484 * @param {Overlay} p_oOverlay Object representing the overlay that
4487 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4488 this._manageBlur(p_oOverlay);
4492 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4493 * monitor focus state.
4495 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4496 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4497 * on the instance, the _bindFocus method will add them, and the focus method will
4498 * update the OverlayManager's state directly.
4500 * @method _bindFocus
4501 * @param {Overlay} overlay The overlay for which focus needs to be managed
4504 _bindFocus : function(overlay) {
4507 if (!overlay.focusEvent) {
4508 overlay.focusEvent = overlay.createEvent("focus");
4509 overlay.focusEvent.signature = CustomEvent.LIST;
4510 overlay.focusEvent._managed = true;
4512 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4515 if (!overlay.focus) {
4516 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4517 overlay.focus = function () {
4518 if (mgr._manageFocus(this)) {
4520 if (this.cfg.getProperty("visible") && this.focusFirst) {
4523 this.focusEvent.fire();
4526 overlay.focus._managed = true;
4531 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4532 * monitor blur state.
4534 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4535 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4536 * on the instance, the _bindBlur method will add them, and the blur method
4537 * update the OverlayManager's state directly.
4540 * @param {Overlay} overlay The overlay for which blur needs to be managed
4543 _bindBlur : function(overlay) {
4546 if (!overlay.blurEvent) {
4547 overlay.blurEvent = overlay.createEvent("blur");
4548 overlay.blurEvent.signature = CustomEvent.LIST;
4549 overlay.focusEvent._managed = true;
4551 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4554 if (!overlay.blur) {
4555 overlay.blur = function () {
4556 if (mgr._manageBlur(this)) {
4557 this.blurEvent.fire();
4560 overlay.blur._managed = true;
4563 overlay.hideEvent.subscribe(overlay.blur);
4567 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4568 * to be removed for the OverlayManager when destroyed.
4570 * @method _bindDestroy
4571 * @param {Overlay} overlay The overlay instance being managed
4574 _bindDestroy : function(overlay) {
4576 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4580 * Ensures the zIndex configuration property on the managed overlay based instance
4581 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4583 * @method _syncZIndex
4584 * @param {Overlay} overlay The overlay instance being managed
4587 _syncZIndex : function(overlay) {
4588 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4589 if (!isNaN(zIndex)) {
4590 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4592 overlay.cfg.setProperty("zIndex", 0);
4597 * Registers an Overlay or an array of Overlays with the manager. Upon
4598 * registration, the Overlay receives functions for focus and blur,
4599 * along with CustomEvents for each.
4602 * @param {Overlay} overlay An Overlay to register with the manager.
4603 * @param {Overlay[]} overlay An array of Overlays to register with
4605 * @return {boolean} true if any Overlays are registered.
4607 register: function (overlay) {
4609 var registered = false,
4613 if (overlay instanceof Overlay) {
4615 overlay.cfg.addProperty("manager", { value: this } );
4617 this._bindFocus(overlay);
4618 this._bindBlur(overlay);
4619 this._bindDestroy(overlay);
4620 this._syncZIndex(overlay);
4622 this.overlays.push(overlay);
4623 this.bringToTop(overlay);
4627 } else if (overlay instanceof Array) {
4629 for (i = 0, n = overlay.length; i < n; i++) {
4630 registered = this.register(overlay[i]) || registered;
4639 * Places the specified Overlay instance on top of all other
4640 * Overlay instances.
4641 * @method bringToTop
4642 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4644 * @param {String} p_oOverlay String representing the id of an
4647 bringToTop: function (p_oOverlay) {
4649 var oOverlay = this.find(p_oOverlay),
4656 aOverlays = this.overlays;
4657 aOverlays.sort(this.compareZIndexDesc);
4659 oTopOverlay = aOverlays[0];
4662 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4664 if (!isNaN(nTopZIndex)) {
4666 var bRequiresBump = false;
4668 if (oTopOverlay !== oOverlay) {
4669 bRequiresBump = true;
4670 } else if (aOverlays.length > 1) {
4671 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4672 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4673 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4674 bRequiresBump = true;
4678 if (bRequiresBump) {
4679 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4682 aOverlays.sort(this.compareZIndexDesc);
4688 * Attempts to locate an Overlay by instance or ID.
4690 * @param {Overlay} overlay An Overlay to locate within the manager
4691 * @param {String} overlay An Overlay id to locate within the manager
4692 * @return {Overlay} The requested Overlay, if found, or null if it
4693 * cannot be located.
4695 find: function (overlay) {
4697 var isInstance = overlay instanceof Overlay,
4698 overlays = this.overlays,
4699 n = overlays.length,
4704 if (isInstance || typeof overlay == "string") {
4705 for (i = n-1; i >= 0; i--) {
4707 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4718 * Used for sorting the manager's Overlays by z-index.
4719 * @method compareZIndexDesc
4721 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4722 * fall in the stacking order.
4724 compareZIndexDesc: function (o1, o2) {
4726 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4727 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4729 if (zIndex1 === null && zIndex2 === null) {
4731 } else if (zIndex1 === null){
4733 } else if (zIndex2 === null) {
4735 } else if (zIndex1 > zIndex2) {
4737 } else if (zIndex1 < zIndex2) {
4745 * Shows all Overlays in the manager.
4748 showAll: function () {
4749 var overlays = this.overlays,
4750 n = overlays.length,
4753 for (i = n - 1; i >= 0; i--) {
4759 * Hides all Overlays in the manager.
4762 hideAll: function () {
4763 var overlays = this.overlays,
4764 n = overlays.length,
4767 for (i = n - 1; i >= 0; i--) {
4773 * Returns a string representation of the object.
4775 * @return {String} The string representation of the OverlayManager
4777 toString: function () {
4778 return "OverlayManager";
4785 * ContainerEffect encapsulates animation transitions that are executed when
4786 * an Overlay is shown or hidden.
4787 * @namespace YAHOO.widget
4788 * @class ContainerEffect
4790 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
4791 * should be associated with
4792 * @param {Object} attrIn The object literal representing the animation
4793 * arguments to be used for the animate-in transition. The arguments for
4794 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4795 * duration(Number), and method(i.e. Easing.easeIn).
4796 * @param {Object} attrOut The object literal representing the animation
4797 * arguments to be used for the animate-out transition. The arguments for
4798 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4799 * duration(Number), and method(i.e. Easing.easeIn).
4800 * @param {HTMLElement} targetElement Optional. The target element that
4801 * should be animated during the transition. Defaults to overlay.element.
4802 * @param {class} Optional. The animation class to instantiate. Defaults to
4803 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4805 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
4808 animClass = YAHOO.util.Anim;
4812 * The overlay to animate
4814 * @type YAHOO.widget.Overlay
4816 this.overlay = overlay;
4819 * The animation attributes to use when transitioning into view
4823 this.attrIn = attrIn;
4826 * The animation attributes to use when transitioning out of view
4830 this.attrOut = attrOut;
4833 * The target element to be animated
4834 * @property targetElement
4837 this.targetElement = targetElement || overlay.element;
4840 * The animation class to use for animating the overlay
4841 * @property animClass
4844 this.animClass = animClass;
4847 var Dom = YAHOO.util.Dom,
4848 CustomEvent = YAHOO.util.CustomEvent,
4849 ContainerEffect = YAHOO.widget.ContainerEffect;
4852 * A pre-configured ContainerEffect instance that can be used for fading
4853 * an overlay in and out.
4856 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4857 * @param {Number} dur The duration of the animation
4858 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4860 ContainerEffect.FADE = function (overlay, dur) {
4862 var Easing = YAHOO.util.Easing,
4864 attributes: {opacity:{from:0, to:1}},
4866 method: Easing.easeIn
4869 attributes: {opacity:{to:0}},
4871 method: Easing.easeOut
4873 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
4875 fade.handleUnderlayStart = function() {
4876 var underlay = this.overlay.underlay;
4877 if (underlay && YAHOO.env.ua.ie) {
4878 var hasFilters = (underlay.filters && underlay.filters.length > 0);
4880 Dom.addClass(overlay.element, "yui-effect-fade");
4885 fade.handleUnderlayComplete = function() {
4886 var underlay = this.overlay.underlay;
4887 if (underlay && YAHOO.env.ua.ie) {
4888 Dom.removeClass(overlay.element, "yui-effect-fade");
4892 fade.handleStartAnimateIn = function (type, args, obj) {
4893 obj.overlay._fadingIn = true;
4895 Dom.addClass(obj.overlay.element, "hide-select");
4897 if (!obj.overlay.underlay) {
4898 obj.overlay.cfg.refireEvent("underlay");
4901 obj.handleUnderlayStart();
4903 obj.overlay._setDomVisibility(true);
4904 Dom.setStyle(obj.overlay.element, "opacity", 0);
4907 fade.handleCompleteAnimateIn = function (type,args,obj) {
4908 obj.overlay._fadingIn = false;
4910 Dom.removeClass(obj.overlay.element, "hide-select");
4912 if (obj.overlay.element.style.filter) {
4913 obj.overlay.element.style.filter = null;
4916 obj.handleUnderlayComplete();
4918 obj.overlay.cfg.refireEvent("iframe");
4919 obj.animateInCompleteEvent.fire();
4922 fade.handleStartAnimateOut = function (type, args, obj) {
4923 obj.overlay._fadingOut = true;
4924 Dom.addClass(obj.overlay.element, "hide-select");
4925 obj.handleUnderlayStart();
4928 fade.handleCompleteAnimateOut = function (type, args, obj) {
4929 obj.overlay._fadingOut = false;
4930 Dom.removeClass(obj.overlay.element, "hide-select");
4932 if (obj.overlay.element.style.filter) {
4933 obj.overlay.element.style.filter = null;
4935 obj.overlay._setDomVisibility(false);
4936 Dom.setStyle(obj.overlay.element, "opacity", 1);
4938 obj.handleUnderlayComplete();
4940 obj.overlay.cfg.refireEvent("iframe");
4941 obj.animateOutCompleteEvent.fire();
4950 * A pre-configured ContainerEffect instance that can be used for sliding an
4951 * overlay in and out.
4954 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4955 * @param {Number} dur The duration of the animation
4956 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4958 ContainerEffect.SLIDE = function (overlay, dur) {
4959 var Easing = YAHOO.util.Easing,
4961 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
4962 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
4963 clientWidth = Dom.getClientWidth(),
4964 offsetWidth = overlay.element.offsetWidth,
4967 attributes: { points: { to: [x, y] } },
4969 method: Easing.easeIn
4973 attributes: { points: { to: [(clientWidth + 25), y] } },
4975 method: Easing.easeOut
4978 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
4980 slide.handleStartAnimateIn = function (type,args,obj) {
4981 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
4982 obj.overlay.element.style.top = y + "px";
4985 slide.handleTweenAnimateIn = function (type, args, obj) {
4987 var pos = Dom.getXY(obj.overlay.element),
4991 if (Dom.getStyle(obj.overlay.element, "visibility") ==
4992 "hidden" && currentX < x) {
4994 obj.overlay._setDomVisibility(true);
4998 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
4999 obj.overlay.cfg.refireEvent("iframe");
5002 slide.handleCompleteAnimateIn = function (type, args, obj) {
5003 obj.overlay.cfg.setProperty("xy", [x, y], true);
5006 obj.overlay.cfg.refireEvent("iframe");
5007 obj.animateInCompleteEvent.fire();
5010 slide.handleStartAnimateOut = function (type, args, obj) {
5012 var vw = Dom.getViewportWidth(),
5013 pos = Dom.getXY(obj.overlay.element),
5016 obj.animOut.attributes.points.to = [(vw + 25), yso];
5019 slide.handleTweenAnimateOut = function (type, args, obj) {
5021 var pos = Dom.getXY(obj.overlay.element),
5025 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
5026 obj.overlay.cfg.refireEvent("iframe");
5029 slide.handleCompleteAnimateOut = function (type, args, obj) {
5030 obj.overlay._setDomVisibility(false);
5032 obj.overlay.cfg.setProperty("xy", [x, y]);
5033 obj.animateOutCompleteEvent.fire();
5040 ContainerEffect.prototype = {
5043 * Initializes the animation classes and events.
5048 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
5049 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
5051 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
5052 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
5054 this.animateInCompleteEvent = this.createEvent("animateInComplete");
5055 this.animateInCompleteEvent.signature = CustomEvent.LIST;
5057 this.animateOutCompleteEvent = this.createEvent("animateOutComplete");
5058 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
5060 this.animIn = new this.animClass(
5062 this.attrIn.attributes,
5063 this.attrIn.duration,
5064 this.attrIn.method);
5066 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
5067 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
5068 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);
5070 this.animOut = new this.animClass(
5072 this.attrOut.attributes,
5073 this.attrOut.duration,
5074 this.attrOut.method);
5076 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
5077 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
5078 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, this);
5083 * Triggers the in-animation.
5086 animateIn: function () {
5087 this._stopAnims(this.lastFrameOnStop);
5088 this.beforeAnimateInEvent.fire();
5089 this.animIn.animate();
5093 * Triggers the out-animation.
5094 * @method animateOut
5096 animateOut: function () {
5097 this._stopAnims(this.lastFrameOnStop);
5098 this.beforeAnimateOutEvent.fire();
5099 this.animOut.animate();
5103 * Flag to define whether Anim should jump to the last frame,
5104 * when animateIn or animateOut is stopped.
5106 * @property lastFrameOnStop
5110 lastFrameOnStop : true,
5113 * Stops both animIn and animOut instances, if in progress.
5115 * @method _stopAnims
5116 * @param {boolean} finish If true, animation will jump to final frame.
5119 _stopAnims : function(finish) {
5120 if (this.animOut && this.animOut.isAnimated()) {
5121 this.animOut.stop(finish);
5124 if (this.animIn && this.animIn.isAnimated()) {
5125 this.animIn.stop(finish);
5130 * The default onStart handler for the in-animation.
5131 * @method handleStartAnimateIn
5132 * @param {String} type The CustomEvent type
5133 * @param {Object[]} args The CustomEvent arguments
5134 * @param {Object} obj The scope object
5136 handleStartAnimateIn: function (type, args, obj) { },
5139 * The default onTween handler for the in-animation.
5140 * @method handleTweenAnimateIn
5141 * @param {String} type The CustomEvent type
5142 * @param {Object[]} args The CustomEvent arguments
5143 * @param {Object} obj The scope object
5145 handleTweenAnimateIn: function (type, args, obj) { },
5148 * The default onComplete handler for the in-animation.
5149 * @method handleCompleteAnimateIn
5150 * @param {String} type The CustomEvent type
5151 * @param {Object[]} args The CustomEvent arguments
5152 * @param {Object} obj The scope object
5154 handleCompleteAnimateIn: function (type, args, obj) { },
5157 * The default onStart handler for the out-animation.
5158 * @method handleStartAnimateOut
5159 * @param {String} type The CustomEvent type
5160 * @param {Object[]} args The CustomEvent arguments
5161 * @param {Object} obj The scope object
5163 handleStartAnimateOut: function (type, args, obj) { },
5166 * The default onTween handler for the out-animation.
5167 * @method handleTweenAnimateOut
5168 * @param {String} type The CustomEvent type
5169 * @param {Object[]} args The CustomEvent arguments
5170 * @param {Object} obj The scope object
5172 handleTweenAnimateOut: function (type, args, obj) { },
5175 * The default onComplete handler for the out-animation.
5176 * @method handleCompleteAnimateOut
5177 * @param {String} type The CustomEvent type
5178 * @param {Object[]} args The CustomEvent arguments
5179 * @param {Object} obj The scope object
5181 handleCompleteAnimateOut: function (type, args, obj) { },
5184 * Returns a string representation of the object.
5186 * @return {String} The string representation of the ContainerEffect
5188 toString: function () {
5189 var output = "ContainerEffect";
5191 output += " [" + this.overlay.toString() + "]";
5197 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
5200 YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.9.0", build: "2800"});