2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
10 * Config is a utility used within an Object to allow the implementer to
11 * maintain a list of local configuration properties and listen for changes
12 * to those properties dynamically using CustomEvent. The initial values are
13 * also maintained so that the configuration can be reset at any given point
14 * to its initial state.
15 * @namespace YAHOO.util
18 * @param {Object} owner The owner Object to which this Config Object belongs
20 YAHOO.util.Config = function (owner) {
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) {
239 key = key.toLowerCase();
241 var property = this.config[key];
243 if (property && property.event) {
245 if (this.initialConfig[key] &&
246 !Lang.isUndefined(this.initialConfig[key])) {
248 this.setProperty(key, this.initialConfig[key]);
262 * Sets the value of a property. If the silent property is passed as
263 * true, the property's event will not be fired.
264 * @method setProperty
265 * @param {String} key The name of the property
266 * @param {String} value The value to set the property to
267 * @param {Boolean} silent Whether the value should be set silently,
268 * without firing the property event.
269 * @return {Boolean} True, if the set was successful, false if it failed.
271 setProperty: function (key, value, silent) {
275 key = key.toLowerCase();
277 if (this.queueInProgress && ! silent) {
278 // Currently running through a queue...
279 this.queueProperty(key,value);
283 property = this.config[key];
284 if (property && property.event) {
285 if (property.validator && !property.validator(value)) {
288 property.value = value;
290 this.fireEvent(key, value);
291 this.configChangedEvent.fire([key, value]);
302 * Sets the value of a property and queues its event to execute. If the
303 * event is already scheduled to execute, it is
304 * moved from its current position to the end of the queue.
305 * @method queueProperty
306 * @param {String} key The name of the property
307 * @param {String} value The value to set the property to
308 * @return {Boolean} true, if the set was successful, false if
311 queueProperty: function (key, value) {
313 key = key.toLowerCase();
315 var property = this.config[key],
316 foundDuplicate = false,
331 if (property && property.event) {
333 if (!Lang.isUndefined(value) && property.validator &&
334 !property.validator(value)) { // validator
338 if (!Lang.isUndefined(value)) {
339 property.value = value;
341 value = property.value;
344 foundDuplicate = false;
345 iLen = this.eventQueue.length;
347 for (i = 0; i < iLen; i++) {
348 queueItem = this.eventQueue[i];
351 queueItemKey = queueItem[0];
352 queueItemValue = queueItem[1];
354 if (queueItemKey == key) {
357 found a dupe... push to end of queue, null
358 current item, and break
361 this.eventQueue[i] = null;
363 this.eventQueue.push(
364 [key, (!Lang.isUndefined(value) ?
365 value : queueItemValue)]);
367 foundDuplicate = true;
373 // this is a refire, or a new property in the queue
375 if (! foundDuplicate && !Lang.isUndefined(value)) {
376 this.eventQueue.push([key, value]);
380 if (property.supercedes) {
382 sLen = property.supercedes.length;
384 for (s = 0; s < sLen; s++) {
386 supercedesCheck = property.supercedes[s];
387 qLen = this.eventQueue.length;
389 for (q = 0; q < qLen; q++) {
390 queueItemCheck = this.eventQueue[q];
392 if (queueItemCheck) {
393 queueItemCheckKey = queueItemCheck[0];
394 queueItemCheckValue = queueItemCheck[1];
396 if (queueItemCheckKey ==
397 supercedesCheck.toLowerCase() ) {
399 this.eventQueue.push([queueItemCheckKey,
400 queueItemCheckValue]);
402 this.eventQueue[q] = null;
419 * Fires the event for a property using the property's current value.
420 * @method refireEvent
421 * @param {String} key The name of the property
423 refireEvent: function (key) {
425 key = key.toLowerCase();
427 var property = this.config[key];
429 if (property && property.event &&
431 !Lang.isUndefined(property.value)) {
433 if (this.queueInProgress) {
435 this.queueProperty(key);
439 this.fireEvent(key, property.value);
447 * Applies a key-value Object literal to the configuration, replacing
448 * any existing values, and queueing the property events.
449 * Although the values will be set, fireQueue() must be called for their
450 * associated events to execute.
451 * @method applyConfig
452 * @param {Object} userConfig The configuration Object literal
453 * @param {Boolean} init When set to true, the initialConfig will
454 * be set to the userConfig passed in, so that calling a reset will
455 * reset the properties to the passed values.
457 applyConfig: function (userConfig, init) {
464 for (sKey in userConfig) {
465 if (Lang.hasOwnProperty(userConfig, sKey)) {
466 oConfig[sKey.toLowerCase()] = userConfig[sKey];
469 this.initialConfig = oConfig;
472 for (sKey in userConfig) {
473 if (Lang.hasOwnProperty(userConfig, sKey)) {
474 this.queueProperty(sKey, userConfig[sKey]);
480 * Refires the events for all configuration properties using their
484 refresh: function () {
488 for (prop in this.config) {
489 if (Lang.hasOwnProperty(this.config, prop)) {
490 this.refireEvent(prop);
496 * Fires the normalized list of queued property change events
499 fireQueue: function () {
507 this.queueInProgress = true;
508 for (i = 0;i < this.eventQueue.length; i++) {
509 queueItem = this.eventQueue[i];
513 value = queueItem[1];
514 property = this.config[key];
516 property.value = value;
518 // Clear out queue entry, to avoid it being
519 // re-added to the queue by any queueProperty/supercedes
520 // calls which are invoked during fireEvent
521 this.eventQueue[i] = null;
523 this.fireEvent(key,value);
527 this.queueInProgress = false;
528 this.eventQueue = [];
532 * Subscribes an external handler to the change event for any
534 * @method subscribeToConfigEvent
535 * @param {String} key The property name
536 * @param {Function} handler The handler function to use subscribe to
537 * the property's event
538 * @param {Object} obj The Object to use for scoping the event handler
539 * (see CustomEvent documentation)
540 * @param {Boolean} overrideContext Optional. If true, will override
541 * "this" within the handler to map to the scope Object passed into the
543 * @return {Boolean} True, if the subscription was successful,
546 subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
548 var property = this.config[key.toLowerCase()];
550 if (property && property.event) {
551 if (!Config.alreadySubscribed(property.event, handler, obj)) {
552 property.event.subscribe(handler, obj, overrideContext);
562 * Unsubscribes an external handler from the change event for any
564 * @method unsubscribeFromConfigEvent
565 * @param {String} key The property name
566 * @param {Function} handler The handler function to use subscribe to
567 * the property's event
568 * @param {Object} obj The Object to use for scoping the event
569 * handler (see CustomEvent documentation)
570 * @return {Boolean} True, if the unsubscription was successful,
573 unsubscribeFromConfigEvent: function (key, handler, obj) {
574 var property = this.config[key.toLowerCase()];
575 if (property && property.event) {
576 return property.event.unsubscribe(handler, obj);
583 * Returns a string representation of the Config object
585 * @return {String} The Config object in string format.
587 toString: function () {
588 var output = "Config";
590 output += " [" + this.owner.toString() + "]";
596 * Returns a string representation of the Config object's current
598 * @method outputEventQueue
599 * @return {String} The string list of CustomEvents currently queued
602 outputEventQueue: function () {
607 nQueue = this.eventQueue.length;
609 for (q = 0; q < nQueue; q++) {
610 queueItem = this.eventQueue[q];
612 output += queueItem[0] + "=" + queueItem[1] + ", ";
619 * Sets all properties to null, unsubscribes all listeners from each
620 * property's change event and all listeners from the configChangedEvent.
623 destroy: function () {
625 var oConfig = this.config,
630 for (sProperty in oConfig) {
632 if (Lang.hasOwnProperty(oConfig, sProperty)) {
634 oProperty = oConfig[sProperty];
636 oProperty.event.unsubscribeAll();
637 oProperty.event = null;
643 this.configChangedEvent.unsubscribeAll();
645 this.configChangedEvent = null;
648 this.initialConfig = null;
649 this.eventQueue = null;
658 * Checks to determine if a particular function/Object pair are already
659 * subscribed to the specified CustomEvent
660 * @method YAHOO.util.Config.alreadySubscribed
662 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
664 * @param {Function} fn The function to look for in the subscribers list
665 * @param {Object} obj The execution scope Object for the subscription
666 * @return {Boolean} true, if the function/Object pair is already subscribed
667 * to the CustomEvent passed in
669 Config.alreadySubscribed = function (evt, fn, obj) {
671 var nSubscribers = evt.subscribers.length,
675 if (nSubscribers > 0) {
676 i = nSubscribers - 1;
678 subsc = evt.subscribers[i];
679 if (subsc && subsc.obj == obj && subsc.fn == fn) {
690 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
696 * The Container family of components is designed to enable developers to
697 * create different kinds of content-containing modules on the web. Module
698 * and Overlay are the most basic containers, and they can be used directly
699 * or extended to build custom containers. Also part of the Container family
700 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
701 * Dialog, and SimpleDialog.
704 * @requires yahoo, dom, event
705 * @optional dragdrop, animation, button
709 * Module is a JavaScript representation of the Standard Module Format.
710 * Standard Module Format is a simple standard for markup containers where
711 * child nodes representing the header, body, and footer of the content are
712 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
713 * Module is the base class for all other classes in the YUI
715 * @namespace YAHOO.widget
718 * @param {String} el The element ID representing the Module <em>OR</em>
719 * @param {HTMLElement} el The element representing the Module
720 * @param {Object} userConfig The configuration Object literal containing
721 * the configuration that should be set for this module. See configuration
722 * documentation for more details.
724 YAHOO.widget.Module = function (el, userConfig) {
726 this.init(el, userConfig);
731 var Dom = YAHOO.util.Dom,
732 Config = YAHOO.util.Config,
733 Event = YAHOO.util.Event,
734 CustomEvent = YAHOO.util.CustomEvent,
735 Module = YAHOO.widget.Module,
744 * Constant representing the name of the Module's events
745 * @property EVENT_TYPES
751 "BEFORE_INIT": "beforeInit",
754 "BEFORE_RENDER": "beforeRender",
756 "CHANGE_HEADER": "changeHeader",
757 "CHANGE_BODY": "changeBody",
758 "CHANGE_FOOTER": "changeFooter",
759 "CHANGE_CONTENT": "changeContent",
760 "DESTROY": "destroy",
761 "BEFORE_SHOW": "beforeShow",
763 "BEFORE_HIDE": "beforeHide",
768 * Constant representing the Module's configuration properties
769 * @property DEFAULT_CONFIG
779 validator: YAHOO.lang.isBoolean
785 supercedes: ["visible"]
789 key: "monitorresize",
793 "APPEND_TO_DOCUMENT_BODY": {
794 key: "appendtodocumentbody",
800 * Constant representing the prefix path to use for non-secure images
801 * @property YAHOO.widget.Module.IMG_ROOT
806 Module.IMG_ROOT = null;
809 * Constant representing the prefix path to use for securely served images
810 * @property YAHOO.widget.Module.IMG_ROOT_SSL
815 Module.IMG_ROOT_SSL = null;
818 * Constant for the default CSS class name that represents a Module
819 * @property YAHOO.widget.Module.CSS_MODULE
824 Module.CSS_MODULE = "yui-module";
827 * Constant representing the module header
828 * @property YAHOO.widget.Module.CSS_HEADER
833 Module.CSS_HEADER = "hd";
836 * Constant representing the module body
837 * @property YAHOO.widget.Module.CSS_BODY
842 Module.CSS_BODY = "bd";
845 * Constant representing the module footer
846 * @property YAHOO.widget.Module.CSS_FOOTER
851 Module.CSS_FOOTER = "ft";
854 * Constant representing the url for the "src" attribute of the iframe
855 * used to monitor changes to the browser's base font size
856 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
861 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
864 * Constant representing the buffer amount (in pixels) to use when positioning
865 * the text resize monitor offscreen. The resize monitor is positioned
866 * offscreen by an amount eqaul to its offsetHeight + the buffer value.
868 * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
872 // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
873 Module.RESIZE_MONITOR_BUFFER = 1;
876 * Singleton CustomEvent fired when the font size is changed in the browser.
877 * Opera's "zoom" functionality currently does not support text
879 * @event YAHOO.widget.Module.textResizeEvent
881 Module.textResizeEvent = new CustomEvent("textResize");
884 * Helper utility method, which forces a document level
885 * redraw for Opera, which can help remove repaint
886 * irregularities after applying DOM changes.
888 * @method YAHOO.widget.Module.forceDocumentRedraw
891 Module.forceDocumentRedraw = function() {
892 var docEl = document.documentElement;
894 docEl.className += " ";
895 docEl.className = YAHOO.lang.trim(docEl.className);
899 function createModuleTemplate() {
901 if (!m_oModuleTemplate) {
902 m_oModuleTemplate = document.createElement("div");
904 m_oModuleTemplate.innerHTML = ("<div class=\"" +
905 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
906 Module.CSS_BODY + "\"></div><div class=\"" +
907 Module.CSS_FOOTER + "\"></div>");
909 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
910 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
911 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
914 return m_oModuleTemplate;
917 function createHeader() {
918 if (!m_oHeaderTemplate) {
919 createModuleTemplate();
921 return (m_oHeaderTemplate.cloneNode(false));
924 function createBody() {
925 if (!m_oBodyTemplate) {
926 createModuleTemplate();
928 return (m_oBodyTemplate.cloneNode(false));
931 function createFooter() {
932 if (!m_oFooterTemplate) {
933 createModuleTemplate();
935 return (m_oFooterTemplate.cloneNode(false));
941 * The class's constructor function
942 * @property contructor
948 * The main module element that contains the header, body, and footer
955 * The header element, denoted with CSS class "hd"
962 * The body element, denoted with CSS class "bd"
969 * The footer element, denoted with CSS class "ft"
976 * The id of the element
983 * A string representing the root path for all images created by
985 * @deprecated It is recommend that any images for a Module be applied
986 * via CSS using the "background-image" property.
987 * @property imageRoot
990 imageRoot: Module.IMG_ROOT,
993 * Initializes the custom events for Module which are fired
994 * automatically at appropriate times by the Module class.
997 initEvents: function () {
999 var SIGNATURE = CustomEvent.LIST;
1002 * CustomEvent fired prior to class initalization.
1003 * @event beforeInitEvent
1004 * @param {class} classRef class reference of the initializing
1005 * class, such as this.beforeInitEvent.fire(Module)
1007 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1008 this.beforeInitEvent.signature = SIGNATURE;
1011 * CustomEvent fired after class initalization.
1013 * @param {class} classRef class reference of the initializing
1014 * class, such as this.beforeInitEvent.fire(Module)
1016 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1017 this.initEvent.signature = SIGNATURE;
1020 * CustomEvent fired when the Module is appended to the DOM
1021 * @event appendEvent
1023 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1024 this.appendEvent.signature = SIGNATURE;
1027 * CustomEvent fired before the Module is rendered
1028 * @event beforeRenderEvent
1030 this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1031 this.beforeRenderEvent.signature = SIGNATURE;
1034 * CustomEvent fired after the Module is rendered
1035 * @event renderEvent
1037 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1038 this.renderEvent.signature = SIGNATURE;
1041 * CustomEvent fired when the header content of the Module
1043 * @event changeHeaderEvent
1044 * @param {String/HTMLElement} content String/element representing
1045 * the new header content
1047 this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1048 this.changeHeaderEvent.signature = SIGNATURE;
1051 * CustomEvent fired when the body content of the Module is modified
1052 * @event changeBodyEvent
1053 * @param {String/HTMLElement} content String/element representing
1054 * the new body content
1056 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1057 this.changeBodyEvent.signature = SIGNATURE;
1060 * CustomEvent fired when the footer content of the Module
1062 * @event changeFooterEvent
1063 * @param {String/HTMLElement} content String/element representing
1064 * the new footer content
1066 this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1067 this.changeFooterEvent.signature = SIGNATURE;
1070 * CustomEvent fired when the content of the Module is modified
1071 * @event changeContentEvent
1073 this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1074 this.changeContentEvent.signature = SIGNATURE;
1077 * CustomEvent fired when the Module is destroyed
1078 * @event destroyEvent
1080 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
1081 this.destroyEvent.signature = SIGNATURE;
1084 * CustomEvent fired before the Module is shown
1085 * @event beforeShowEvent
1087 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1088 this.beforeShowEvent.signature = SIGNATURE;
1091 * CustomEvent fired after the Module is shown
1094 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1095 this.showEvent.signature = SIGNATURE;
1098 * CustomEvent fired before the Module is hidden
1099 * @event beforeHideEvent
1101 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1102 this.beforeHideEvent.signature = SIGNATURE;
1105 * CustomEvent fired after the Module is hidden
1108 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1109 this.hideEvent.signature = SIGNATURE;
1113 * String representing the current user-agent platform
1114 * @property platform
1117 platform: function () {
1118 var ua = navigator.userAgent.toLowerCase();
1120 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1122 } else if (ua.indexOf("macintosh") != -1) {
1130 * String representing the user-agent of the browser
1131 * @deprecated Use YAHOO.env.ua
1135 browser: function () {
1136 var ua = navigator.userAgent.toLowerCase();
1138 Check Opera first in case of spoof and check Safari before
1139 Gecko since Safari's user agent string includes "like Gecko"
1141 if (ua.indexOf('opera') != -1) {
1143 } else if (ua.indexOf('msie 7') != -1) {
1145 } else if (ua.indexOf('msie') != -1) {
1147 } else if (ua.indexOf('safari') != -1) {
1149 } else if (ua.indexOf('gecko') != -1) {
1157 * Boolean representing whether or not the current browsing context is
1159 * @property isSecure
1162 isSecure: function () {
1163 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1171 * Initializes the custom events for Module which are fired
1172 * automatically at appropriate times by the Module class.
1174 initDefaultConfig: function () {
1175 // Add properties //
1177 * Specifies whether the Module is visible on the page.
1182 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1183 handler: this.configVisible,
1184 value: DEFAULT_CONFIG.VISIBLE.value,
1185 validator: DEFAULT_CONFIG.VISIBLE.validator
1190 * Object or array of objects representing the ContainerEffect
1191 * classes that are active for animating the container.
1194 * <strong>NOTE:</strong> Although this configuration
1195 * property is introduced at the Module level, an out of the box
1196 * implementation is not shipped for the Module class so setting
1197 * the proroperty on the Module class has no effect. The Overlay
1198 * class is the first class to provide out of the box ContainerEffect
1205 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1206 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1207 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1211 * Specifies whether to create a special proxy iframe to monitor
1212 * for user font resizing in the document
1213 * @config monitorresize
1217 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1218 handler: this.configMonitorResize,
1219 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1223 * Specifies if the module should be rendered as the first child
1224 * of document.body or appended as the last child when render is called
1225 * with document.body as the "appendToNode".
1227 * Appending to the body while the DOM is still being constructed can
1228 * lead to Operation Aborted errors in IE hence this flag is set to
1232 * @config appendtodocumentbody
1236 this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1237 value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1242 * The Module class's initialization method, which is executed for
1243 * Module and all of its subclasses. This method is automatically
1244 * called by the constructor, and sets up all DOM references for
1245 * pre-existing markup, and creates required markup if it is not
1248 * If the element passed in does not have an id, one will be generated
1252 * @param {String} el The element ID representing the Module <em>OR</em>
1253 * @param {HTMLElement} el The element representing the Module
1254 * @param {Object} userConfig The configuration Object literal
1255 * containing the configuration that should be set for this module.
1256 * See configuration documentation for more details.
1258 init: function (el, userConfig) {
1263 this.beforeInitEvent.fire(Module);
1266 * The Module's Config object used for monitoring
1267 * configuration properties.
1269 * @type YAHOO.util.Config
1271 this.cfg = new Config(this);
1273 if (this.isSecure) {
1274 this.imageRoot = Module.IMG_ROOT_SSL;
1277 if (typeof el == "string") {
1279 el = document.getElementById(el);
1281 el = (createModuleTemplate()).cloneNode(false);
1286 this.id = Dom.generateId(el);
1289 child = this.element.firstChild;
1292 var fndHd = false, fndBd = false, fndFt = false;
1294 // We're looking for elements
1295 if (1 == child.nodeType) {
1296 if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1297 this.header = child;
1299 } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1302 } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1303 this.footer = child;
1307 } while ((child = child.nextSibling));
1310 this.initDefaultConfig();
1312 Dom.addClass(this.element, Module.CSS_MODULE);
1315 this.cfg.applyConfig(userConfig, true);
1319 Subscribe to the fireQueue() method of Config so that any
1320 queued configuration changes are excecuted upon render of
1324 if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1325 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1328 this.initEvent.fire(Module);
1332 * Initialize an empty IFRAME that is placed out of the visible area
1333 * that can be used to detect text resize.
1334 * @method initResizeMonitor
1336 initResizeMonitor: function () {
1338 var isGeckoWin = (UA.gecko && this.platform == "windows");
1340 // Help prevent spinning loading icon which
1341 // started with FireFox 2.0.0.8/Win
1343 setTimeout(function(){self._initResizeMonitor();}, 0);
1345 this._initResizeMonitor();
1350 * Create and initialize the text resize monitoring iframe.
1353 * @method _initResizeMonitor
1355 _initResizeMonitor : function() {
1361 function fireTextResize() {
1362 Module.textResizeEvent.fire();
1366 oIFrame = Dom.get("_yuiResizeMonitor");
1368 var supportsCWResize = this._supportsCWResize();
1371 oIFrame = document.createElement("iframe");
1373 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1374 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1377 if (!supportsCWResize) {
1378 // Can't monitor on contentWindow, so fire from inside iframe
1379 sHTML = ["<html><head><script ",
1380 "type=\"text/javascript\">",
1381 "window.onresize=function(){window.parent.",
1382 "YAHOO.widget.Module.textResizeEvent.",
1385 "<body></body></html>"].join('');
1387 oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1390 oIFrame.id = "_yuiResizeMonitor";
1391 oIFrame.title = "Text Resize Monitor";
1393 Need to set "position" property before inserting the
1394 iframe into the document or Safari's status bar will
1395 forever indicate the iframe is loading
1396 (See YUILibrary bug #1723064)
1398 oIFrame.style.position = "absolute";
1399 oIFrame.style.visibility = "hidden";
1401 var db = document.body,
1404 db.insertBefore(oIFrame, fc);
1406 db.appendChild(oIFrame);
1409 // Setting the background color fixes an issue with IE6/IE7, where
1410 // elements in the DOM, with -ve margin-top which positioned them
1411 // offscreen (so they would be overlapped by the iframe and its -ve top
1412 // setting), would have their -ve margin-top ignored, when the iframe
1414 oIFrame.style.backgroundColor = "transparent";
1416 oIFrame.style.borderWidth = "0";
1417 oIFrame.style.width = "2em";
1418 oIFrame.style.height = "2em";
1419 oIFrame.style.left = "0";
1420 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1421 oIFrame.style.visibility = "visible";
1424 Don't open/close the document for Gecko like we used to, since it
1425 leads to duplicate cookies. (See YUILibrary bug #1721755)
1428 oDoc = oIFrame.contentWindow.document;
1434 if (oIFrame && oIFrame.contentWindow) {
1435 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1437 if (!Module.textResizeInitialized) {
1438 if (supportsCWResize) {
1439 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1441 This will fail in IE if document.domain has
1442 changed, so we must change the listener to
1443 use the oIFrame element instead
1445 Event.on(oIFrame, "resize", fireTextResize);
1448 Module.textResizeInitialized = true;
1450 this.resizeMonitor = oIFrame;
1456 * Text resize monitor helper method.
1457 * Determines if the browser supports resize events on iframe content windows.
1460 * @method _supportsCWResize
1462 _supportsCWResize : function() {
1464 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1465 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1467 We don't want to start sniffing for patch versions, so fire textResize the same
1468 way on all FF2 flavors
1470 var bSupported = true;
1471 if (UA.gecko && UA.gecko <= 1.8) {
1478 * Event handler fired when the resize monitor element is resized.
1479 * @method onDomResize
1480 * @param {DOMEvent} e The DOM resize event
1481 * @param {Object} obj The scope object passed to the handler
1483 onDomResize: function (e, obj) {
1485 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1487 this.resizeMonitor.style.top = nTop + "px";
1488 this.resizeMonitor.style.left = "0";
1492 * Sets the Module's header content to the string specified, or appends
1493 * the passed element to the header. If no header is present, one will
1494 * be automatically created. An empty string can be passed to the method
1495 * to clear the contents of the header.
1498 * @param {String} headerContent The string used to set the header.
1499 * As a convenience, non HTMLElement objects can also be passed into
1500 * the method, and will be treated as strings, with the header innerHTML
1501 * set to their default toString implementations.
1503 * @param {HTMLElement} headerContent The HTMLElement to append to
1505 * @param {DocumentFragment} headerContent The document fragment
1506 * containing elements which are to be added to the header
1508 setHeader: function (headerContent) {
1509 var oHeader = this.header || (this.header = createHeader());
1511 if (headerContent.nodeName) {
1512 oHeader.innerHTML = "";
1513 oHeader.appendChild(headerContent);
1515 oHeader.innerHTML = headerContent;
1518 if (this._rendered) {
1519 this._renderHeader();
1522 this.changeHeaderEvent.fire(headerContent);
1523 this.changeContentEvent.fire();
1528 * Appends the passed element to the header. If no header is present,
1529 * one will be automatically created.
1530 * @method appendToHeader
1531 * @param {HTMLElement | DocumentFragment} element The element to
1532 * append to the header. In the case of a document fragment, the
1533 * children of the fragment will be appended to the header.
1535 appendToHeader: function (element) {
1536 var oHeader = this.header || (this.header = createHeader());
1538 oHeader.appendChild(element);
1540 this.changeHeaderEvent.fire(element);
1541 this.changeContentEvent.fire();
1546 * Sets the Module's body content to the HTML specified.
1548 * If no body is present, one will be automatically created.
1550 * An empty string can be passed to the method to clear the contents of the body.
1552 * @param {String} bodyContent The HTML used to set the body.
1553 * As a convenience, non HTMLElement objects can also be passed into
1554 * the method, and will be treated as strings, with the body innerHTML
1555 * set to their default toString implementations.
1557 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1558 * child of the body element.
1560 * @param {DocumentFragment} bodyContent The document fragment
1561 * containing elements which are to be added to the body
1563 setBody: function (bodyContent) {
1564 var oBody = this.body || (this.body = createBody());
1566 if (bodyContent.nodeName) {
1567 oBody.innerHTML = "";
1568 oBody.appendChild(bodyContent);
1570 oBody.innerHTML = bodyContent;
1573 if (this._rendered) {
1577 this.changeBodyEvent.fire(bodyContent);
1578 this.changeContentEvent.fire();
1582 * Appends the passed element to the body. If no body is present, one
1583 * will be automatically created.
1584 * @method appendToBody
1585 * @param {HTMLElement | DocumentFragment} element The element to
1586 * append to the body. In the case of a document fragment, the
1587 * children of the fragment will be appended to the body.
1590 appendToBody: function (element) {
1591 var oBody = this.body || (this.body = createBody());
1593 oBody.appendChild(element);
1595 this.changeBodyEvent.fire(element);
1596 this.changeContentEvent.fire();
1601 * Sets the Module's footer content to the HTML specified, or appends
1602 * the passed element to the footer. If no footer is present, one will
1603 * be automatically created. An empty string can be passed to the method
1604 * to clear the contents of the footer.
1606 * @param {String} footerContent The HTML used to set the footer
1607 * As a convenience, non HTMLElement objects can also be passed into
1608 * the method, and will be treated as strings, with the footer innerHTML
1609 * set to their default toString implementations.
1611 * @param {HTMLElement} footerContent The HTMLElement to append to
1614 * @param {DocumentFragment} footerContent The document fragment containing
1615 * elements which are to be added to the footer
1617 setFooter: function (footerContent) {
1619 var oFooter = this.footer || (this.footer = createFooter());
1621 if (footerContent.nodeName) {
1622 oFooter.innerHTML = "";
1623 oFooter.appendChild(footerContent);
1625 oFooter.innerHTML = footerContent;
1628 if (this._rendered) {
1629 this._renderFooter();
1632 this.changeFooterEvent.fire(footerContent);
1633 this.changeContentEvent.fire();
1637 * Appends the passed element to the footer. If no footer is present,
1638 * one will be automatically created.
1639 * @method appendToFooter
1640 * @param {HTMLElement | DocumentFragment} element The element to
1641 * append to the footer. In the case of a document fragment, the
1642 * children of the fragment will be appended to the footer
1644 appendToFooter: function (element) {
1646 var oFooter = this.footer || (this.footer = createFooter());
1648 oFooter.appendChild(element);
1650 this.changeFooterEvent.fire(element);
1651 this.changeContentEvent.fire();
1656 * Renders the Module by inserting the elements that are not already
1657 * in the main Module into their correct places. Optionally appends
1658 * the Module to the specified node prior to the render's execution.
1660 * For Modules without existing markup, the appendToNode argument
1661 * is REQUIRED. If this argument is ommitted and the current element is
1662 * not present in the document, the function will return false,
1663 * indicating that the render was a failure.
1666 * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1667 * then the module is rendered as the first child of the body element,
1668 * and not appended to it, to avoid Operation Aborted errors in IE when
1669 * rendering the module before window's load event is fired. You can
1670 * use the appendtodocumentbody configuration property to change this
1671 * to append to document.body if required.
1674 * @param {String} appendToNode The element id to which the Module
1675 * should be appended to prior to rendering <em>OR</em>
1676 * @param {HTMLElement} appendToNode The element to which the Module
1677 * should be appended to prior to rendering
1678 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1679 * represents the actual Standard Module container.
1680 * @return {Boolean} Success or failure of the render
1682 render: function (appendToNode, moduleElement) {
1686 function appendTo(parentNode) {
1687 if (typeof parentNode == "string") {
1688 parentNode = document.getElementById(parentNode);
1692 me._addToParent(parentNode, me.element);
1693 me.appendEvent.fire();
1697 this.beforeRenderEvent.fire();
1699 if (! moduleElement) {
1700 moduleElement = this.element;
1704 appendTo(appendToNode);
1706 // No node was passed in. If the element is not already in the Dom, this fails
1707 if (! Dom.inDocument(this.element)) {
1712 this._renderHeader(moduleElement);
1713 this._renderBody(moduleElement);
1714 this._renderFooter(moduleElement);
1716 this._rendered = true;
1718 this.renderEvent.fire();
1723 * Renders the currently set header into it's proper position under the
1724 * module element. If the module element is not provided, "this.element"
1727 * @method _renderHeader
1729 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1731 _renderHeader: function(moduleElement){
1732 moduleElement = moduleElement || this.element;
1734 // Need to get everything into the DOM if it isn't already
1735 if (this.header && !Dom.inDocument(this.header)) {
1736 // There is a header, but it's not in the DOM yet. Need to add it.
1737 var firstChild = moduleElement.firstChild;
1739 moduleElement.insertBefore(this.header, firstChild);
1741 moduleElement.appendChild(this.header);
1747 * Renders the currently set body into it's proper position under the
1748 * module element. If the module element is not provided, "this.element"
1751 * @method _renderBody
1753 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1755 _renderBody: function(moduleElement){
1756 moduleElement = moduleElement || this.element;
1758 if (this.body && !Dom.inDocument(this.body)) {
1759 // There is a body, but it's not in the DOM yet. Need to add it.
1760 if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1761 moduleElement.insertBefore(this.body, this.footer);
1763 moduleElement.appendChild(this.body);
1769 * Renders the currently set footer into it's proper position under the
1770 * module element. If the module element is not provided, "this.element"
1773 * @method _renderFooter
1775 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1777 _renderFooter: function(moduleElement){
1778 moduleElement = moduleElement || this.element;
1780 if (this.footer && !Dom.inDocument(this.footer)) {
1781 // There is a footer, but it's not in the DOM yet. Need to add it.
1782 moduleElement.appendChild(this.footer);
1787 * Removes the Module element from the DOM and sets all child elements
1791 destroy: function () {
1796 Event.purgeElement(this.element, true);
1797 parent = this.element.parentNode;
1801 parent.removeChild(this.element);
1804 this.element = null;
1809 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1814 this.destroyEvent.fire();
1818 * Shows the Module element by setting the visible configuration
1819 * property to true. Also fires two events: beforeShowEvent prior to
1820 * the visibility change, and showEvent after.
1824 this.cfg.setProperty("visible", true);
1828 * Hides the Module element by setting the visible configuration
1829 * property to false. Also fires two events: beforeHideEvent prior to
1830 * the visibility change, and hideEvent after.
1834 this.cfg.setProperty("visible", false);
1837 // BUILT-IN EVENT HANDLERS FOR MODULE //
1839 * Default event handler for changing the visibility property of a
1840 * Module. By default, this is achieved by switching the "display" style
1841 * between "block" and "none".
1842 * This method is responsible for firing showEvent and hideEvent.
1843 * @param {String} type The CustomEvent type (usually the property name)
1844 * @param {Object[]} args The CustomEvent arguments. For configuration
1845 * handlers, args[0] will equal the newly applied value for the property.
1846 * @param {Object} obj The scope object. For configuration handlers,
1847 * this will usually equal the owner.
1848 * @method configVisible
1850 configVisible: function (type, args, obj) {
1851 var visible = args[0];
1853 this.beforeShowEvent.fire();
1854 Dom.setStyle(this.element, "display", "block");
1855 this.showEvent.fire();
1857 this.beforeHideEvent.fire();
1858 Dom.setStyle(this.element, "display", "none");
1859 this.hideEvent.fire();
1864 * Default event handler for the "monitorresize" configuration property
1865 * @param {String} type The CustomEvent type (usually the property name)
1866 * @param {Object[]} args The CustomEvent arguments. For configuration
1867 * handlers, args[0] will equal the newly applied value for the property.
1868 * @param {Object} obj The scope object. For configuration handlers,
1869 * this will usually equal the owner.
1870 * @method configMonitorResize
1872 configMonitorResize: function (type, args, obj) {
1873 var monitor = args[0];
1875 this.initResizeMonitor();
1877 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1878 this.resizeMonitor = null;
1883 * This method is a protected helper, used when constructing the DOM structure for the module
1884 * to account for situations which may cause Operation Aborted errors in IE. It should not
1885 * be used for general DOM construction.
1887 * If the parentNode is not document.body, the element is appended as the last element.
1890 * If the parentNode is document.body the element is added as the first child to help
1891 * prevent Operation Aborted errors in IE.
1894 * @param {parentNode} The HTML element to which the element will be added
1895 * @param {element} The HTML element to be added to parentNode's children
1896 * @method _addToParent
1899 _addToParent: function(parentNode, element) {
1900 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1901 parentNode.insertBefore(element, parentNode.firstChild);
1903 parentNode.appendChild(element);
1908 * Returns a String representation of the Object.
1910 * @return {String} The string representation of the Module
1912 toString: function () {
1913 return "Module " + this.id;
1917 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1923 * Overlay is a Module that is absolutely positioned above the page flow. It
1924 * has convenience methods for positioning and sizing, as well as options for
1925 * controlling zIndex and constraining the Overlay's position to the current
1926 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1927 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1928 * properly rendered above SELECT elements.
1929 * @namespace YAHOO.widget
1931 * @extends YAHOO.widget.Module
1932 * @param {String} el The element ID representing the Overlay <em>OR</em>
1933 * @param {HTMLElement} el The element representing the Overlay
1934 * @param {Object} userConfig The configuration object literal containing
1935 * the configuration that should be set for this Overlay. See configuration
1936 * documentation for more details.
1939 YAHOO.widget.Overlay = function (el, userConfig) {
1940 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1943 var Lang = YAHOO.lang,
1944 CustomEvent = YAHOO.util.CustomEvent,
1945 Module = YAHOO.widget.Module,
1946 Event = YAHOO.util.Event,
1947 Dom = YAHOO.util.Dom,
1948 Config = YAHOO.util.Config,
1950 Overlay = YAHOO.widget.Overlay,
1952 _SUBSCRIBE = "subscribe",
1953 _UNSUBSCRIBE = "unsubscribe",
1954 _CONTAINED = "contained",
1959 * Constant representing the name of the Overlay's events
1960 * @property EVENT_TYPES
1966 "BEFORE_MOVE": "beforeMove",
1971 * Constant representing the Overlay's configuration properties
1972 * @property DEFAULT_CONFIG
1981 validator: Lang.isNumber,
1982 suppressEvent: true,
1983 supercedes: ["iframe"]
1988 validator: Lang.isNumber,
1989 suppressEvent: true,
1990 supercedes: ["iframe"]
1995 suppressEvent: true,
1996 supercedes: ["iframe"]
2001 suppressEvent: true,
2002 supercedes: ["iframe"]
2008 supercedes: ["iframe", "visible"]
2013 suppressEvent: true,
2014 supercedes: ["context", "fixedcenter", "iframe"]
2019 suppressEvent: true,
2020 supercedes: ["context", "fixedcenter", "iframe"]
2023 "AUTO_FILL_HEIGHT" : {
2024 key: "autofillheight",
2025 supercedes: ["height"],
2034 "CONSTRAIN_TO_VIEWPORT": {
2035 key: "constraintoviewport",
2037 validator: Lang.isBoolean,
2038 supercedes: ["iframe", "x", "y", "xy"]
2043 value: (UA.ie == 6 ? true : false),
2044 validator: Lang.isBoolean,
2045 supercedes: ["zindex"]
2048 "PREVENT_CONTEXT_OVERLAP": {
2049 key: "preventcontextoverlap",
2051 validator: Lang.isBoolean,
2052 supercedes: ["constraintoviewport"]
2058 * The URL that will be placed in the iframe
2059 * @property YAHOO.widget.Overlay.IFRAME_SRC
2064 Overlay.IFRAME_SRC = "javascript:false;";
2067 * Number representing how much the iframe shim should be offset from each
2068 * side of an Overlay instance, in pixels.
2069 * @property YAHOO.widget.Overlay.IFRAME_SRC
2075 Overlay.IFRAME_OFFSET = 3;
2078 * Number representing the minimum distance an Overlay instance should be
2079 * positioned relative to the boundaries of the browser's viewport, in pixels.
2080 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2086 Overlay.VIEWPORT_OFFSET = 10;
2089 * Constant representing the top left corner of an element, used for
2090 * configuring the context element alignment
2091 * @property YAHOO.widget.Overlay.TOP_LEFT
2096 Overlay.TOP_LEFT = "tl";
2099 * Constant representing the top right corner of an element, used for
2100 * configuring the context element alignment
2101 * @property YAHOO.widget.Overlay.TOP_RIGHT
2106 Overlay.TOP_RIGHT = "tr";
2109 * Constant representing the top bottom left corner of an element, used for
2110 * configuring the context element alignment
2111 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2116 Overlay.BOTTOM_LEFT = "bl";
2119 * Constant representing the bottom right corner of an element, used for
2120 * configuring the context element alignment
2121 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2126 Overlay.BOTTOM_RIGHT = "br";
2128 Overlay.PREVENT_OVERLAP_X = {
2135 Overlay.PREVENT_OVERLAP_Y = {
2143 * Constant representing the default CSS class used for an Overlay
2144 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2149 Overlay.CSS_OVERLAY = "yui-overlay";
2152 * Constant representing the default hidden CSS class used for an Overlay. This class is
2153 * applied to the overlay's outer DIV whenever it's hidden.
2155 * @property YAHOO.widget.Overlay.CSS_HIDDEN
2160 Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2163 * Constant representing the default CSS class used for an Overlay iframe shim.
2165 * @property YAHOO.widget.Overlay.CSS_IFRAME
2170 Overlay.CSS_IFRAME = "yui-overlay-iframe";
2173 * Constant representing the names of the standard module elements
2174 * used in the overlay.
2175 * @property YAHOO.widget.Overlay.STD_MOD_RE
2180 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2183 * A singleton CustomEvent used for reacting to the DOM event for
2185 * @event YAHOO.widget.Overlay.windowScrollEvent
2187 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2190 * A singleton CustomEvent used for reacting to the DOM event for
2192 * @event YAHOO.widget.Overlay.windowResizeEvent
2194 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2197 * The DOM event handler used to fire the CustomEvent for window scroll
2198 * @method YAHOO.widget.Overlay.windowScrollHandler
2200 * @param {DOMEvent} e The DOM scroll event
2202 Overlay.windowScrollHandler = function (e) {
2203 var t = Event.getTarget(e);
2205 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2206 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2207 // - IE doesn't recognize scroll registered on the document.
2209 // Also, when document view is scrolled, IE doesn't provide a target,
2210 // rest of the browsers set target to window.document, apart from opera
2211 // which sets target to window.
2212 if (!t || t === window || t === window.document) {
2215 if (! window.scrollEnd) {
2216 window.scrollEnd = -1;
2219 clearTimeout(window.scrollEnd);
2221 window.scrollEnd = setTimeout(function () {
2222 Overlay.windowScrollEvent.fire();
2226 Overlay.windowScrollEvent.fire();
2232 * The DOM event handler used to fire the CustomEvent for window resize
2233 * @method YAHOO.widget.Overlay.windowResizeHandler
2235 * @param {DOMEvent} e The DOM resize event
2237 Overlay.windowResizeHandler = function (e) {
2240 if (! window.resizeEnd) {
2241 window.resizeEnd = -1;
2244 clearTimeout(window.resizeEnd);
2246 window.resizeEnd = setTimeout(function () {
2247 Overlay.windowResizeEvent.fire();
2250 Overlay.windowResizeEvent.fire();
2255 * A boolean that indicated whether the window resize and scroll events have
2256 * already been subscribed to.
2257 * @property YAHOO.widget.Overlay._initialized
2261 Overlay._initialized = null;
2263 if (Overlay._initialized === null) {
2264 Event.on(window, "scroll", Overlay.windowScrollHandler);
2265 Event.on(window, "resize", Overlay.windowResizeHandler);
2266 Overlay._initialized = true;
2270 * Internal map of special event types, which are provided
2271 * by the instance. It maps the event type to the custom event
2272 * instance. Contains entries for the "windowScroll", "windowResize" and
2273 * "textResize" static container events.
2275 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2280 Overlay._TRIGGER_MAP = {
2281 "windowScroll" : Overlay.windowScrollEvent,
2282 "windowResize" : Overlay.windowResizeEvent,
2283 "textResize" : Module.textResizeEvent
2286 YAHOO.extend(Overlay, Module, {
2290 * Array of default event types which will trigger
2291 * context alignment for the Overlay class.
2293 * <p>The array is empty by default for Overlay,
2294 * but maybe populated in future releases, so classes extending
2295 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2296 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2297 * value with their own array of values.
2301 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2304 * @property CONTEXT_TRIGGERS
2308 CONTEXT_TRIGGERS : [],
2311 * The Overlay initialization method, which is executed for Overlay and
2312 * all of its subclasses. This method is automatically called by the
2313 * constructor, and sets up all DOM references for pre-existing markup,
2314 * and creates required markup if it is not already present.
2316 * @param {String} el The element ID representing the Overlay <em>OR</em>
2317 * @param {HTMLElement} el The element representing the Overlay
2318 * @param {Object} userConfig The configuration object literal
2319 * containing the configuration that should be set for this Overlay.
2320 * See configuration documentation for more details.
2322 init: function (el, userConfig) {
2325 Note that we don't pass the user config in here yet because we
2326 only want it executed once, at the lowest subclass level
2329 Overlay.superclass.init.call(this, el/*, userConfig*/);
2331 this.beforeInitEvent.fire(Overlay);
2333 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2336 this.cfg.applyConfig(userConfig, true);
2339 if (this.platform == "mac" && UA.gecko) {
2341 if (! Config.alreadySubscribed(this.showEvent,
2342 this.showMacGeckoScrollbars, this)) {
2344 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2349 if (! Config.alreadySubscribed(this.hideEvent,
2350 this.hideMacGeckoScrollbars, this)) {
2352 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2358 this.initEvent.fire(Overlay);
2362 * Initializes the custom events for Overlay which are fired
2363 * automatically at appropriate times by the Overlay class.
2364 * @method initEvents
2366 initEvents: function () {
2368 Overlay.superclass.initEvents.call(this);
2370 var SIGNATURE = CustomEvent.LIST;
2373 * CustomEvent fired before the Overlay is moved.
2374 * @event beforeMoveEvent
2375 * @param {Number} x x coordinate
2376 * @param {Number} y y coordinate
2378 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2379 this.beforeMoveEvent.signature = SIGNATURE;
2382 * CustomEvent fired after the Overlay is moved.
2384 * @param {Number} x x coordinate
2385 * @param {Number} y y coordinate
2387 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2388 this.moveEvent.signature = SIGNATURE;
2393 * Initializes the class's configurable properties which can be changed
2394 * using the Overlay's Config object (cfg).
2395 * @method initDefaultConfig
2397 initDefaultConfig: function () {
2399 Overlay.superclass.initDefaultConfig.call(this);
2403 // Add overlay config properties //
2406 * The absolute x-coordinate position of the Overlay
2411 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2413 handler: this.configX,
2414 validator: DEFAULT_CONFIG.X.validator,
2415 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2416 supercedes: DEFAULT_CONFIG.X.supercedes
2421 * The absolute y-coordinate position of the Overlay
2426 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2428 handler: this.configY,
2429 validator: DEFAULT_CONFIG.Y.validator,
2430 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2431 supercedes: DEFAULT_CONFIG.Y.supercedes
2436 * An array with the absolute x and y positions of the Overlay
2441 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2442 handler: this.configXY,
2443 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2444 supercedes: DEFAULT_CONFIG.XY.supercedes
2449 * The array of context arguments for context-sensitive positioning.
2453 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2454 * the 5 array elements described in detail below:
2458 * <dt>contextElementOrId <String|HTMLElement></dt>
2459 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2460 * <dt>overlayCorner <String></dt>
2461 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2462 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2463 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2464 * <dt>contextCorner <String></dt>
2465 * <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>
2466 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2469 * 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>
2470 * 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.
2471 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2474 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2475 * 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).
2478 * <dt>xyOffset <Number[]></dt>
2480 * 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.
2481 * 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.
2486 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2487 * align the Overlay's top left corner to the bottom left corner of the
2488 * context element with id "img1".
2491 * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
2492 * align the Overlay's top left corner to the bottom left corner of the
2493 * 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).
2496 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2497 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2504 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2505 handler: this.configContext,
2506 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2507 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2511 * Determines whether or not the Overlay should be anchored
2512 * to the center of the viewport.
2514 * <p>This property can be set to:</p>
2519 * To enable fixed center positioning
2521 * When enabled, the overlay will
2522 * be positioned in the center of viewport when initially displayed, and
2523 * will remain in the center of the viewport whenever the window is
2524 * scrolled or resized.
2527 * If the overlay is too big for the viewport,
2528 * it's top left corner will be aligned with the top left corner of the viewport.
2533 * To disable fixed center positioning.
2534 * <p>In this case the overlay can still be
2535 * centered as a one-off operation, by invoking the <code>center()</code> method,
2536 * however it will not remain centered when the window is scrolled/resized.
2538 * <dt>"contained"<dt>
2539 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2540 * <p>However, unlike setting the property to <code>true</code>,
2541 * when the property is set to <code>"contained"</code>, if the overlay is
2542 * too big for the viewport, it will not get automatically centered when the
2543 * user scrolls or resizes the window (until the window is large enough to contain the
2544 * overlay). This is useful in cases where the Overlay has both header and footer
2545 * UI controls which the user may need to access.
2550 * @config fixedcenter
2551 * @type Boolean | String
2554 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2555 handler: this.configFixedCenter,
2556 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2557 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2558 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2562 * CSS width of the Overlay.
2567 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2568 handler: this.configWidth,
2569 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2570 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2574 * CSS height of the Overlay.
2579 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2580 handler: this.configHeight,
2581 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2582 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2586 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2587 * Supported values are "header", "body", "footer".
2589 * @config autofillheight
2593 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2594 handler: this.configAutoFillHeight,
2595 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2596 validator : this._validateAutoFill,
2597 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2601 * CSS z-index of the Overlay.
2606 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2607 handler: this.configzIndex,
2608 value: DEFAULT_CONFIG.ZINDEX.value
2612 * True if the Overlay should be prevented from being positioned
2613 * out of the viewport.
2614 * @config constraintoviewport
2618 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2620 handler: this.configConstrainToViewport,
2621 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2622 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2623 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2629 * @description Boolean indicating whether or not the Overlay should
2630 * have an IFRAME shim; used to prevent SELECT elements from
2631 * poking through an Overlay instance in IE6. When set to "true",
2632 * the iframe shim is created when the Overlay instance is intially
2635 * @default true for IE6 and below, false for all other browsers.
2637 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2639 handler: this.configIframe,
2640 value: DEFAULT_CONFIG.IFRAME.value,
2641 validator: DEFAULT_CONFIG.IFRAME.validator,
2642 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2647 * @config preventcontextoverlap
2648 * @description Boolean indicating whether or not the Overlay should overlap its
2649 * context element (defined using the "context" configuration property) when the
2650 * "constraintoviewport" configuration property is set to "true".
2654 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2655 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2656 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2657 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2662 * Moves the Overlay to the specified position. This function is
2663 * identical to calling this.cfg.setProperty("xy", [x,y]);
2665 * @param {Number} x The Overlay's new x position
2666 * @param {Number} y The Overlay's new y position
2668 moveTo: function (x, y) {
2669 this.cfg.setProperty("xy", [x, y]);
2673 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2674 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2675 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2676 * @method hideMacGeckoScrollbars
2678 hideMacGeckoScrollbars: function () {
2679 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2683 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2684 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2685 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2686 * @method showMacGeckoScrollbars
2688 showMacGeckoScrollbars: function () {
2689 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2693 * Internal implementation to set the visibility of the overlay in the DOM.
2695 * @method _setDomVisibility
2696 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2699 _setDomVisibility : function(show) {
2700 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2701 var hiddenClass = Overlay.CSS_HIDDEN;
2704 Dom.removeClass(this.element, hiddenClass);
2706 Dom.addClass(this.element, hiddenClass);
2710 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2712 * The default event handler fired when the "visible" property is
2713 * changed. This method is responsible for firing showEvent
2715 * @method configVisible
2716 * @param {String} type The CustomEvent type (usually the property name)
2717 * @param {Object[]} args The CustomEvent arguments. For configuration
2718 * handlers, args[0] will equal the newly applied value for the property.
2719 * @param {Object} obj The scope object. For configuration handlers,
2720 * this will usually equal the owner.
2722 configVisible: function (type, args, obj) {
2724 var visible = args[0],
2725 currentVis = Dom.getStyle(this.element, "visibility"),
2726 effect = this.cfg.getProperty("effect"),
2727 effectInstances = [],
2728 isMacGecko = (this.platform == "mac" && UA.gecko),
2729 alreadySubscribed = Config.alreadySubscribed,
2730 eff, ei, e, i, j, k, h,
2734 if (currentVis == "inherit") {
2735 e = this.element.parentNode;
2737 while (e.nodeType != 9 && e.nodeType != 11) {
2738 currentVis = Dom.getStyle(e, "visibility");
2740 if (currentVis != "inherit") {
2747 if (currentVis == "inherit") {
2748 currentVis = "visible";
2753 if (effect instanceof Array) {
2754 nEffects = effect.length;
2756 for (i = 0; i < nEffects; i++) {
2758 effectInstances[effectInstances.length] =
2759 eff.effect(this, eff.duration);
2763 effectInstances[effectInstances.length] =
2764 effect.effect(this, effect.duration);
2768 if (visible) { // Show
2770 this.showMacGeckoScrollbars();
2773 if (effect) { // Animate in
2774 if (visible) { // Animate in if not showing
2775 if (currentVis != "visible" || currentVis === "") {
2776 this.beforeShowEvent.fire();
2777 nEffectInstances = effectInstances.length;
2779 for (j = 0; j < nEffectInstances; j++) {
2780 ei = effectInstances[j];
2781 if (j === 0 && !alreadySubscribed(
2782 ei.animateInCompleteEvent,
2783 this.showEvent.fire, this.showEvent)) {
2786 Delegate showEvent until end
2787 of animateInComplete
2790 ei.animateInCompleteEvent.subscribe(
2791 this.showEvent.fire, this.showEvent, true);
2798 if (currentVis != "visible" || currentVis === "") {
2799 this.beforeShowEvent.fire();
2801 this._setDomVisibility(true);
2803 this.cfg.refireEvent("iframe");
2804 this.showEvent.fire();
2806 this._setDomVisibility(true);
2812 this.hideMacGeckoScrollbars();
2815 if (effect) { // Animate out if showing
2816 if (currentVis == "visible") {
2817 this.beforeHideEvent.fire();
2819 nEffectInstances = effectInstances.length;
2820 for (k = 0; k < nEffectInstances; k++) {
2821 h = effectInstances[k];
2823 if (k === 0 && !alreadySubscribed(
2824 h.animateOutCompleteEvent, this.hideEvent.fire,
2828 Delegate hideEvent until end
2829 of animateOutComplete
2832 h.animateOutCompleteEvent.subscribe(
2833 this.hideEvent.fire, this.hideEvent, true);
2839 } else if (currentVis === "") {
2840 this._setDomVisibility(false);
2843 } else { // Simple hide
2845 if (currentVis == "visible" || currentVis === "") {
2846 this.beforeHideEvent.fire();
2847 this._setDomVisibility(false);
2848 this.hideEvent.fire();
2850 this._setDomVisibility(false);
2857 * Fixed center event handler used for centering on scroll/resize, but only if
2858 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2859 * the overlay fits within the viewport.
2861 * @method doCenterOnDOMEvent
2863 doCenterOnDOMEvent: function () {
2865 fc = cfg.getProperty("fixedcenter");
2867 if (cfg.getProperty("visible")) {
2868 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2875 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2876 * will fit entirely inside the viewport, in both dimensions - width and height.
2878 * @method fitsInViewport
2879 * @return boolean true if the Overlay will fit, false if not
2881 fitsInViewport : function() {
2882 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2883 element = this.element,
2884 elementWidth = element.offsetWidth,
2885 elementHeight = element.offsetHeight,
2886 viewportWidth = Dom.getViewportWidth(),
2887 viewportHeight = Dom.getViewportHeight();
2889 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2893 * The default event handler fired when the "fixedcenter" property
2895 * @method configFixedCenter
2896 * @param {String} type The CustomEvent type (usually the property name)
2897 * @param {Object[]} args The CustomEvent arguments. For configuration
2898 * handlers, args[0] will equal the newly applied value for the property.
2899 * @param {Object} obj The scope object. For configuration handlers,
2900 * this will usually equal the owner.
2902 configFixedCenter: function (type, args, obj) {
2905 alreadySubscribed = Config.alreadySubscribed,
2906 windowResizeEvent = Overlay.windowResizeEvent,
2907 windowScrollEvent = Overlay.windowScrollEvent;
2912 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2913 this.beforeShowEvent.subscribe(this.center);
2916 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2917 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2920 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2921 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2925 this.beforeShowEvent.unsubscribe(this.center);
2927 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2928 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2933 * The default event handler fired when the "height" property is changed.
2934 * @method configHeight
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 configHeight: function (type, args, obj) {
2943 var height = args[0],
2946 Dom.setStyle(el, "height", height);
2947 this.cfg.refireEvent("iframe");
2951 * The default event handler fired when the "autofillheight" property is changed.
2952 * @method configAutoFillHeight
2954 * @param {String} type The CustomEvent type (usually the property name)
2955 * @param {Object[]} args The CustomEvent arguments. For configuration
2956 * handlers, args[0] will equal the newly applied value for the property.
2957 * @param {Object} obj The scope object. For configuration handlers,
2958 * this will usually equal the owner.
2960 configAutoFillHeight: function (type, args, obj) {
2961 var fillEl = args[0],
2963 autoFillHeight = "autofillheight",
2965 currEl = cfg.getProperty(autoFillHeight),
2966 autoFill = this._autoFillOnHeightChange;
2968 cfg.unsubscribeFromConfigEvent(height, autoFill);
2969 Module.textResizeEvent.unsubscribe(autoFill);
2970 this.changeContentEvent.unsubscribe(autoFill);
2972 if (currEl && fillEl !== currEl && this[currEl]) {
2973 Dom.setStyle(this[currEl], height, "");
2977 fillEl = Lang.trim(fillEl.toLowerCase());
2979 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
2980 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
2981 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
2983 cfg.setProperty(autoFillHeight, fillEl, true);
2988 * The default event handler fired when the "width" property is changed.
2989 * @method configWidth
2990 * @param {String} type The CustomEvent type (usually the property name)
2991 * @param {Object[]} args The CustomEvent arguments. For configuration
2992 * handlers, args[0] will equal the newly applied value for the property.
2993 * @param {Object} obj The scope object. For configuration handlers,
2994 * this will usually equal the owner.
2996 configWidth: function (type, args, obj) {
2998 var width = args[0],
3001 Dom.setStyle(el, "width", width);
3002 this.cfg.refireEvent("iframe");
3006 * The default event handler fired when the "zIndex" property is changed.
3007 * @method configzIndex
3008 * @param {String} type The CustomEvent type (usually the property name)
3009 * @param {Object[]} args The CustomEvent arguments. For configuration
3010 * handlers, args[0] will equal the newly applied value for the property.
3011 * @param {Object} obj The scope object. For configuration handlers,
3012 * this will usually equal the owner.
3014 configzIndex: function (type, args, obj) {
3016 var zIndex = args[0],
3020 zIndex = Dom.getStyle(el, "zIndex");
3021 if (! zIndex || isNaN(zIndex)) {
3026 if (this.iframe || this.cfg.getProperty("iframe") === true) {
3032 Dom.setStyle(el, "zIndex", zIndex);
3033 this.cfg.setProperty("zIndex", zIndex, true);
3041 * The default event handler fired when the "xy" property is changed.
3043 * @param {String} type The CustomEvent type (usually the property name)
3044 * @param {Object[]} args The CustomEvent arguments. For configuration
3045 * handlers, args[0] will equal the newly applied value for the property.
3046 * @param {Object} obj The scope object. For configuration handlers,
3047 * this will usually equal the owner.
3049 configXY: function (type, args, obj) {
3055 this.cfg.setProperty("x", x);
3056 this.cfg.setProperty("y", y);
3058 this.beforeMoveEvent.fire([x, y]);
3060 x = this.cfg.getProperty("x");
3061 y = this.cfg.getProperty("y");
3064 this.cfg.refireEvent("iframe");
3065 this.moveEvent.fire([x, y]);
3069 * The default event handler fired when the "x" property is changed.
3071 * @param {String} type The CustomEvent type (usually the property name)
3072 * @param {Object[]} args The CustomEvent arguments. For configuration
3073 * handlers, args[0] will equal the newly applied value for the property.
3074 * @param {Object} obj The scope object. For configuration handlers,
3075 * this will usually equal the owner.
3077 configX: function (type, args, obj) {
3080 y = this.cfg.getProperty("y");
3082 this.cfg.setProperty("x", x, true);
3083 this.cfg.setProperty("y", y, true);
3085 this.beforeMoveEvent.fire([x, y]);
3087 x = this.cfg.getProperty("x");
3088 y = this.cfg.getProperty("y");
3090 Dom.setX(this.element, x, true);
3092 this.cfg.setProperty("xy", [x, y], true);
3094 this.cfg.refireEvent("iframe");
3095 this.moveEvent.fire([x, y]);
3099 * The default event handler fired when the "y" property is changed.
3101 * @param {String} type The CustomEvent type (usually the property name)
3102 * @param {Object[]} args The CustomEvent arguments. For configuration
3103 * handlers, args[0] will equal the newly applied value for the property.
3104 * @param {Object} obj The scope object. For configuration handlers,
3105 * this will usually equal the owner.
3107 configY: function (type, args, obj) {
3109 var x = this.cfg.getProperty("x"),
3112 this.cfg.setProperty("x", x, true);
3113 this.cfg.setProperty("y", y, true);
3115 this.beforeMoveEvent.fire([x, y]);
3117 x = this.cfg.getProperty("x");
3118 y = this.cfg.getProperty("y");
3120 Dom.setY(this.element, y, true);
3122 this.cfg.setProperty("xy", [x, y], true);
3124 this.cfg.refireEvent("iframe");
3125 this.moveEvent.fire([x, y]);
3129 * Shows the iframe shim, if it has been enabled.
3130 * @method showIframe
3132 showIframe: function () {
3134 var oIFrame = this.iframe,
3138 oParentNode = this.element.parentNode;
3140 if (oParentNode != oIFrame.parentNode) {
3141 this._addToParent(oParentNode, oIFrame);
3143 oIFrame.style.display = "block";
3148 * Hides the iframe shim, if it has been enabled.
3149 * @method hideIframe
3151 hideIframe: function () {
3153 this.iframe.style.display = "none";
3158 * Syncronizes the size and position of iframe shim to that of its
3159 * corresponding Overlay instance.
3160 * @method syncIframe
3162 syncIframe: function () {
3164 var oIFrame = this.iframe,
3165 oElement = this.element,
3166 nOffset = Overlay.IFRAME_OFFSET,
3167 nDimensionOffset = (nOffset * 2),
3172 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3173 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3175 // Position <iframe>
3176 aXY = this.cfg.getProperty("xy");
3178 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3179 this.syncPosition();
3180 aXY = this.cfg.getProperty("xy");
3182 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3187 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3188 * the Overlay element. The zindex of the iframe is set to be one less
3189 * than the Overlay element's zindex.
3191 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3192 * to ensure that the iframe shim has a non-negative zindex.
3193 * If you require the iframe zindex to be 0 or higher, the zindex of
3194 * the Overlay element should be set to a value greater than 0, before
3195 * this method is called.
3197 * @method stackIframe
3199 stackIframe: function () {
3201 var overlayZ = Dom.getStyle(this.element, "zIndex");
3202 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3203 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3209 * The default event handler fired when the "iframe" property is changed.
3210 * @method configIframe
3211 * @param {String} type The CustomEvent type (usually the property name)
3212 * @param {Object[]} args The CustomEvent arguments. For configuration
3213 * handlers, args[0] will equal the newly applied value for the property.
3214 * @param {Object} obj The scope object. For configuration handlers,
3215 * this will usually equal the owner.
3217 configIframe: function (type, args, obj) {
3219 var bIFrame = args[0];
3221 function createIFrame() {
3223 var oIFrame = this.iframe,
3224 oElement = this.element,
3228 if (!m_oIFrameTemplate) {
3229 m_oIFrameTemplate = document.createElement("iframe");
3231 if (this.isSecure) {
3232 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3236 Set the opacity of the <iframe> to 0 so that it
3237 doesn't modify the opacity of any transparent
3238 elements that may be on top of it (like a shadow).
3241 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3243 Need to set the "frameBorder" property to 0
3244 supress the default <iframe> border in IE.
3245 Setting the CSS "border" property alone
3248 m_oIFrameTemplate.frameBorder = 0;
3251 m_oIFrameTemplate.style.opacity = "0";
3254 m_oIFrameTemplate.style.position = "absolute";
3255 m_oIFrameTemplate.style.border = "none";
3256 m_oIFrameTemplate.style.margin = "0";
3257 m_oIFrameTemplate.style.padding = "0";
3258 m_oIFrameTemplate.style.display = "none";
3259 m_oIFrameTemplate.tabIndex = -1;
3260 m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3263 oIFrame = m_oIFrameTemplate.cloneNode(false);
3264 oIFrame.id = this.id + "_f";
3265 oParent = oElement.parentNode;
3267 var parentNode = oParent || document.body;
3269 this._addToParent(parentNode, oIFrame);
3270 this.iframe = oIFrame;
3274 Show the <iframe> before positioning it since the "setXY"
3275 method of DOM requires the element be in the document
3281 Syncronize the size and position of the <iframe> to that
3287 // Add event listeners to update the <iframe> when necessary
3288 if (!this._hasIframeEventListeners) {
3289 this.showEvent.subscribe(this.showIframe);
3290 this.hideEvent.subscribe(this.hideIframe);
3291 this.changeContentEvent.subscribe(this.syncIframe);
3293 this._hasIframeEventListeners = true;
3297 function onBeforeShow() {
3298 createIFrame.call(this);
3299 this.beforeShowEvent.unsubscribe(onBeforeShow);
3300 this._iframeDeferred = false;
3303 if (bIFrame) { // <iframe> shim is enabled
3305 if (this.cfg.getProperty("visible")) {
3306 createIFrame.call(this);
3308 if (!this._iframeDeferred) {
3309 this.beforeShowEvent.subscribe(onBeforeShow);
3310 this._iframeDeferred = true;
3314 } else { // <iframe> shim is disabled
3317 if (this._hasIframeEventListeners) {
3318 this.showEvent.unsubscribe(this.showIframe);
3319 this.hideEvent.unsubscribe(this.hideIframe);
3320 this.changeContentEvent.unsubscribe(this.syncIframe);
3322 this._hasIframeEventListeners = false;
3328 * Set's the container's XY value from DOM if not already set.
3330 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3331 * not already set. The method also refire's the XY config property event, so any
3332 * beforeMove, Move event listeners are invoked.
3334 * @method _primeXYFromDOM
3337 _primeXYFromDOM : function() {
3338 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3339 // Set CFG XY based on DOM XY
3340 this.syncPosition();
3341 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3342 this.cfg.refireEvent("xy");
3343 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3348 * The default event handler fired when the "constraintoviewport"
3349 * property is changed.
3350 * @method configConstrainToViewport
3351 * @param {String} type The CustomEvent type (usually the property name)
3352 * @param {Object[]} args The CustomEvent arguments. For configuration
3353 * handlers, args[0] will equal the newly applied value for
3355 * @param {Object} obj The scope object. For configuration handlers,
3356 * this will usually equal the owner.
3358 configConstrainToViewport: function (type, args, obj) {
3362 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3363 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3365 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3366 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3369 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3370 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3375 * The default event handler fired when the "context" property
3378 * @method configContext
3379 * @param {String} type The CustomEvent type (usually the property name)
3380 * @param {Object[]} args The CustomEvent arguments. For configuration
3381 * handlers, args[0] will equal the newly applied value for the property.
3382 * @param {Object} obj The scope object. For configuration handlers,
3383 * this will usually equal the owner.
3385 configContext: function (type, args, obj) {
3387 var contextArgs = args[0],
3389 elementMagnetCorner,
3390 contextMagnetCorner,
3393 defTriggers = this.CONTEXT_TRIGGERS;
3397 contextEl = contextArgs[0];
3398 elementMagnetCorner = contextArgs[1];
3399 contextMagnetCorner = contextArgs[2];
3400 triggers = contextArgs[3];
3401 offset = contextArgs[4];
3403 if (defTriggers && defTriggers.length > 0) {
3404 triggers = (triggers || []).concat(defTriggers);
3408 if (typeof contextEl == "string") {
3409 this.cfg.setProperty("context", [
3410 document.getElementById(contextEl),
3411 elementMagnetCorner,
3412 contextMagnetCorner,
3418 if (elementMagnetCorner && contextMagnetCorner) {
3419 this.align(elementMagnetCorner, contextMagnetCorner, offset);
3422 if (this._contextTriggers) {
3423 // Unsubscribe Old Set
3424 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3428 // Subscribe New Set
3429 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3430 this._contextTriggers = triggers;
3437 * Custom Event handler for context alignment triggers. Invokes the align method
3439 * @method _alignOnTrigger
3442 * @param {String} type The event type (not used by the default implementation)
3443 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3445 _alignOnTrigger: function(type, args) {
3450 * Helper method to locate the custom event instance for the event name string
3451 * passed in. As a convenience measure, any custom events passed in are returned.
3453 * @method _findTriggerCE
3456 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3457 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3459 _findTriggerCE : function(t) {
3461 if (t instanceof CustomEvent) {
3463 } else if (Overlay._TRIGGER_MAP[t]) {
3464 tce = Overlay._TRIGGER_MAP[t];
3470 * Utility method that subscribes or unsubscribes the given
3471 * function from the list of trigger events provided.
3473 * @method _processTriggers
3476 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3477 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3478 * subscribed/unsubscribed respectively.
3480 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3481 * we are subscribing or unsubscribing trigger listeners
3483 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3484 * Context is always set to the overlay instance, and no additional object argument
3485 * get passed to the subscribed function.
3487 _processTriggers : function(triggers, mode, fn) {
3490 for (var i = 0, l = triggers.length; i < l; ++i) {
3492 tce = this._findTriggerCE(t);
3494 tce[mode](fn, this, true);
3501 // END BUILT-IN PROPERTY EVENT HANDLERS //
3503 * Aligns the Overlay to its context element using the specified corner
3504 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3507 * @param {String} elementAlign The String representing the corner of
3508 * the Overlay that should be aligned to the context element
3509 * @param {String} contextAlign The corner of the context element
3510 * that the elementAlign corner should stick to.
3511 * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3512 * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
3513 * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3515 align: function (elementAlign, contextAlign, xyOffset) {
3517 var contextArgs = this.cfg.getProperty("context"),
3523 function doAlign(v, h) {
3525 var alignX = null, alignY = null;
3527 switch (elementAlign) {
3529 case Overlay.TOP_LEFT:
3534 case Overlay.TOP_RIGHT:
3535 alignX = h - element.offsetWidth;
3539 case Overlay.BOTTOM_LEFT:
3541 alignY = v - element.offsetHeight;
3544 case Overlay.BOTTOM_RIGHT:
3545 alignX = h - element.offsetWidth;
3546 alignY = v - element.offsetHeight;
3550 if (alignX !== null && alignY !== null) {
3552 alignX += xyOffset[0];
3553 alignY += xyOffset[1];
3555 me.moveTo(alignX, alignY);
3560 context = contextArgs[0];
3561 element = this.element;
3564 if (! elementAlign) {
3565 elementAlign = contextArgs[1];
3568 if (! contextAlign) {
3569 contextAlign = contextArgs[2];
3572 if (!xyOffset && contextArgs[4]) {
3573 xyOffset = contextArgs[4];
3576 if (element && context) {
3577 contextRegion = Dom.getRegion(context);
3579 switch (contextAlign) {
3581 case Overlay.TOP_LEFT:
3582 doAlign(contextRegion.top, contextRegion.left);
3585 case Overlay.TOP_RIGHT:
3586 doAlign(contextRegion.top, contextRegion.right);
3589 case Overlay.BOTTOM_LEFT:
3590 doAlign(contextRegion.bottom, contextRegion.left);
3593 case Overlay.BOTTOM_RIGHT:
3594 doAlign(contextRegion.bottom, contextRegion.right);
3602 * The default event handler executed when the moveEvent is fired, if the
3603 * "constraintoviewport" is set to true.
3604 * @method enforceConstraints
3605 * @param {String} type The CustomEvent type (usually the property name)
3606 * @param {Object[]} args The CustomEvent arguments. For configuration
3607 * handlers, args[0] will equal the newly applied value for the property.
3608 * @param {Object} obj The scope object. For configuration handlers,
3609 * this will usually equal the owner.
3611 enforceConstraints: function (type, args, obj) {
3614 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3615 this.cfg.setProperty("x", cXY[0], true);
3616 this.cfg.setProperty("y", cXY[1], true);
3617 this.cfg.setProperty("xy", cXY, true);
3621 * Shared implementation method for getConstrainedX and getConstrainedY.
3624 * Given a coordinate value, returns the calculated coordinate required to
3625 * position the Overlay if it is to be constrained to the viewport, based on the
3626 * current element size, viewport dimensions, scroll values and preventoverlap
3630 * @method _getConstrainedPos
3632 * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3633 * @param {Number} The coordinate value which needs to be constrained
3634 * @return {Number} The constrained coordinate value
3636 _getConstrainedPos: function(pos, val) {
3638 var overlayEl = this.element,
3640 buffer = Overlay.VIEWPORT_OFFSET,
3644 overlaySize = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3645 viewportSize = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3646 docScroll = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3647 overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3649 context = this.cfg.getProperty("context"),
3651 bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3652 bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3654 minConstraint = docScroll + buffer,
3655 maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3657 constrainedVal = val;
3659 if (val < minConstraint || val > maxConstraint) {
3660 if (bPreventContextOverlap) {
3661 constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3663 if (bOverlayFitsInViewport) {
3664 if (val < minConstraint) {
3665 constrainedVal = minConstraint;
3666 } else if (val > maxConstraint) {
3667 constrainedVal = maxConstraint;
3670 constrainedVal = minConstraint;
3675 return constrainedVal;
3679 * Helper method, used to position the Overlap to prevent overlap with the
3680 * context element (used when preventcontextoverlap is enabled)
3682 * @method _preventOverlap
3684 * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3685 * @param {HTMLElement} contextEl The context element
3686 * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3687 * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3688 * @param {Object} docScroll The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3690 * @return {Number} The new coordinate value which was set to prevent overlap
3692 _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3694 var x = (pos == "x"),
3696 buffer = Overlay.VIEWPORT_OFFSET,
3700 contextElPos = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3701 contextElSize = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3703 minRegionSize = contextElPos - buffer,
3704 maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3708 flip = function () {
3711 if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3712 flippedVal = (contextElPos - overlaySize);
3714 flippedVal = (contextElPos + contextElSize);
3717 overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3722 setPosition = function () {
3724 var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3727 if (overlaySize > displayRegionSize) {
3730 All possible positions and values have been
3731 tried, but none were successful, so fall back
3732 to the original size and position.
3738 position = setPosition();
3747 return this.cfg.getProperty(pos);
3751 * Given x coordinate value, returns the calculated x coordinate required to
3752 * position the Overlay if it is to be constrained to the viewport, based on the
3753 * current element size, viewport dimensions and scroll values.
3755 * @param {Number} x The X coordinate value to be constrained
3756 * @return {Number} The constrained x coordinate
3758 getConstrainedX: function (x) {
3759 return this._getConstrainedPos("x", x);
3763 * Given y coordinate value, returns the calculated y coordinate required to
3764 * position the Overlay if it is to be constrained to the viewport, based on the
3765 * current element size, viewport dimensions and scroll values.
3767 * @param {Number} y The Y coordinate value to be constrained
3768 * @return {Number} The constrained y coordinate
3770 getConstrainedY : function (y) {
3771 return this._getConstrainedPos("y", y);
3775 * Given x, y coordinate values, returns the calculated coordinates required to
3776 * position the Overlay if it is to be constrained to the viewport, based on the
3777 * current element size, viewport dimensions and scroll values.
3779 * @param {Number} x The X coordinate value to be constrained
3780 * @param {Number} y The Y coordinate value to be constrained
3781 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3783 getConstrainedXY: function(x, y) {
3784 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3788 * Centers the container in the viewport.
3791 center: function () {
3793 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3794 elementWidth = this.element.offsetWidth,
3795 elementHeight = this.element.offsetHeight,
3796 viewPortWidth = Dom.getViewportWidth(),
3797 viewPortHeight = Dom.getViewportHeight(),
3801 if (elementWidth < viewPortWidth) {
3802 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3804 x = nViewportOffset + Dom.getDocumentScrollLeft();
3807 if (elementHeight < viewPortHeight) {
3808 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3810 y = nViewportOffset + Dom.getDocumentScrollTop();
3813 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3814 this.cfg.refireEvent("iframe");
3817 this.forceContainerRedraw();
3822 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3823 * Panel's position in the DOM. This is primarily used to update
3824 * position information during drag & drop.
3825 * @method syncPosition
3827 syncPosition: function () {
3829 var pos = Dom.getXY(this.element);
3831 this.cfg.setProperty("x", pos[0], true);
3832 this.cfg.setProperty("y", pos[1], true);
3833 this.cfg.setProperty("xy", pos, true);
3838 * Event handler fired when the resize monitor element is resized.
3839 * @method onDomResize
3840 * @param {DOMEvent} e The resize DOM event
3841 * @param {Object} obj The scope object
3843 onDomResize: function (e, obj) {
3847 Overlay.superclass.onDomResize.call(this, e, obj);
3849 setTimeout(function () {
3851 me.cfg.refireEvent("iframe");
3852 me.cfg.refireEvent("context");
3857 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3859 * @method _getComputedHeight
3861 * @param {HTMLElement} el The element for which the content height needs to be determined
3862 * @return {Number} The content box height of the given element, or null if it could not be determined.
3864 _getComputedHeight : (function() {
3866 if (document.defaultView && document.defaultView.getComputedStyle) {
3867 return function(el) {
3869 if (el.ownerDocument && el.ownerDocument.defaultView) {
3870 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3872 height = parseInt(computed.height, 10);
3875 return (Lang.isNumber(height)) ? height : null;
3878 return function(el) {
3880 if (el.style.pixelHeight) {
3881 height = el.style.pixelHeight;
3883 return (Lang.isNumber(height)) ? height : null;
3889 * autofillheight validator. Verifies that the autofill value is either null
3890 * or one of the strings : "body", "header" or "footer".
3892 * @method _validateAutoFillHeight
3894 * @param {String} val
3895 * @return true, if valid, false otherwise
3897 _validateAutoFillHeight : function(val) {
3898 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3902 * The default custom event handler executed when the overlay's height is changed,
3903 * if the autofillheight property has been set.
3905 * @method _autoFillOnHeightChange
3907 * @param {String} type The event type
3908 * @param {Array} args The array of arguments passed to event subscribers
3909 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3910 * out the containers height
3912 _autoFillOnHeightChange : function(type, args, el) {
3913 var height = this.cfg.getProperty("height");
3914 if ((height && height !== "auto") || (height === 0)) {
3915 this.fillHeight(el);
3920 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3921 * otherwise returns the offsetHeight
3922 * @method _getPreciseHeight
3924 * @param {HTMLElement} el
3925 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3927 _getPreciseHeight : function(el) {
3928 var height = el.offsetHeight;
3930 if (el.getBoundingClientRect) {
3931 var rect = el.getBoundingClientRect();
3932 height = rect.bottom - rect.top;
3940 * Sets the height on the provided header, body or footer element to
3941 * fill out the height of the container. It determines the height of the
3942 * containers content box, based on it's configured height value, and
3943 * sets the height of the autofillheight element to fill out any
3944 * space remaining after the other standard module element heights
3945 * have been accounted for.
3947 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
3948 * height has not been set on the container, since for an "auto" height container,
3949 * the heights of the header/body/footer will drive the height of the container.</p>
3951 * @method fillHeight
3952 * @param {HTMLElement} el The element which should be resized to fill out the height
3953 * of the container element.
3955 fillHeight : function(el) {
3957 var container = this.innerElement || this.element,
3958 containerEls = [this.header, this.body, this.footer],
3965 for (var i = 0, l = containerEls.length; i < l; i++) {
3966 containerEl = containerEls[i];
3968 if (el !== containerEl) {
3969 filled += this._getPreciseHeight(containerEl);
3978 if (UA.ie || UA.opera) {
3979 // Need to set height to 0, to allow height to be reduced
3980 Dom.setStyle(el, 'height', 0 + 'px');
3983 total = this._getComputedHeight(container);
3985 // Fallback, if we can't get computed value for content height
3986 if (total === null) {
3987 Dom.addClass(container, "yui-override-padding");
3988 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
3989 Dom.removeClass(container, "yui-override-padding");
3992 remaining = Math.max(total - filled, 0);
3994 Dom.setStyle(el, "height", remaining + "px");
3996 // Re-adjust height if required, to account for el padding and border
3997 if (el.offsetHeight != remaining) {
3998 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4000 Dom.setStyle(el, "height", remaining + "px");
4006 * Places the Overlay on top of all other instances of
4007 * YAHOO.widget.Overlay.
4008 * @method bringToTop
4010 bringToTop: function () {
4013 oElement = this.element;
4015 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4017 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4018 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4020 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4021 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4023 if (nZIndex1 > nZIndex2) {
4025 } else if (nZIndex1 < nZIndex2) {
4032 function isOverlayElement(p_oElement) {
4034 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4035 Panel = YAHOO.widget.Panel;
4037 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4038 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4039 aOverlays[aOverlays.length] = p_oElement.parentNode;
4041 aOverlays[aOverlays.length] = p_oElement;
4046 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
4048 aOverlays.sort(compareZIndexDesc);
4050 var oTopOverlay = aOverlays[0],
4054 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4056 if (!isNaN(nTopZIndex)) {
4057 var bRequiresBump = false;
4059 if (oTopOverlay != oElement) {
4060 bRequiresBump = true;
4061 } else if (aOverlays.length > 1) {
4062 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4063 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4064 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4065 bRequiresBump = true;
4068 if (bRequiresBump) {
4069 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4076 * Removes the Overlay element from the DOM and sets all child
4080 destroy: function () {
4083 this.iframe.parentNode.removeChild(this.iframe);
4088 Overlay.windowResizeEvent.unsubscribe(
4089 this.doCenterOnDOMEvent, this);
4091 Overlay.windowScrollEvent.unsubscribe(
4092 this.doCenterOnDOMEvent, this);
4094 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4096 if (this._contextTriggers) {
4097 // Unsubscribe context triggers - to cover context triggers which listen for global
4098 // events such as windowResize and windowScroll. Easier just to unsubscribe all
4099 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4102 Overlay.superclass.destroy.call(this);
4106 * Can be used to force the container to repaint/redraw it's contents.
4108 * By default applies and then removes a 1px bottom margin through the
4109 * application/removal of a "yui-force-redraw" class.
4112 * It is currently used by Overlay to force a repaint for webkit
4113 * browsers, when centering.
4115 * @method forceContainerRedraw
4117 forceContainerRedraw : function() {
4119 Dom.addClass(c.element, "yui-force-redraw");
4120 setTimeout(function() {
4121 Dom.removeClass(c.element, "yui-force-redraw");
4126 * Returns a String representation of the object.
4128 * @return {String} The string representation of the Overlay.
4130 toString: function () {
4131 return "Overlay " + this.id;
4139 * OverlayManager is used for maintaining the focus status of
4140 * multiple Overlays.
4141 * @namespace YAHOO.widget
4142 * @namespace YAHOO.widget
4143 * @class OverlayManager
4145 * @param {Array} overlays Optional. A collection of Overlays to register
4147 * @param {Object} userConfig The object literal representing the user
4148 * configuration of the OverlayManager
4150 YAHOO.widget.OverlayManager = function (userConfig) {
4151 this.init(userConfig);
4154 var Overlay = YAHOO.widget.Overlay,
4155 Event = YAHOO.util.Event,
4156 Dom = YAHOO.util.Dom,
4157 Config = YAHOO.util.Config,
4158 CustomEvent = YAHOO.util.CustomEvent,
4159 OverlayManager = YAHOO.widget.OverlayManager;
4162 * The CSS class representing a focused Overlay
4163 * @property OverlayManager.CSS_FOCUSED
4168 OverlayManager.CSS_FOCUSED = "focused";
4170 OverlayManager.prototype = {
4173 * The class's constructor function
4174 * @property contructor
4177 constructor: OverlayManager,
4180 * The array of Overlays that are currently registered
4181 * @property overlays
4182 * @type YAHOO.widget.Overlay[]
4187 * Initializes the default configuration of the OverlayManager
4188 * @method initDefaultConfig
4190 initDefaultConfig: function () {
4192 * The collection of registered Overlays in use by
4193 * the OverlayManager
4195 * @type YAHOO.widget.Overlay[]
4198 this.cfg.addProperty("overlays", { suppressEvent: true } );
4201 * The default DOM event that should be used to focus an Overlay
4202 * @config focusevent
4204 * @default "mousedown"
4206 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4210 * Initializes the OverlayManager
4212 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4213 * register with the manager.
4214 * @param {Object} userConfig The object literal representing the user
4215 * configuration of the OverlayManager
4217 init: function (userConfig) {
4220 * The OverlayManager's Config object used for monitoring
4221 * configuration properties.
4225 this.cfg = new Config(this);
4227 this.initDefaultConfig();
4230 this.cfg.applyConfig(userConfig, true);
4232 this.cfg.fireQueue();
4235 * The currently activated Overlay
4236 * @property activeOverlay
4238 * @type YAHOO.widget.Overlay
4240 var activeOverlay = null;
4243 * Returns the currently focused Overlay
4245 * @return {Overlay} The currently focused Overlay
4247 this.getActive = function () {
4248 return activeOverlay;
4252 * Focuses the specified Overlay
4254 * @param {Overlay} overlay The Overlay to focus
4255 * @param {String} overlay The id of the Overlay to focus
4257 this.focus = function (overlay) {
4258 var o = this.find(overlay);
4265 * Removes the specified Overlay from the manager
4267 * @param {Overlay} overlay The Overlay to remove
4268 * @param {String} overlay The id of the Overlay to remove
4270 this.remove = function (overlay) {
4272 var o = this.find(overlay),
4276 if (activeOverlay == o) {
4277 activeOverlay = null;
4280 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4283 // Set it's zindex so that it's sorted to the end.
4284 originalZ = Dom.getStyle(o.element, "zIndex");
4285 o.cfg.setProperty("zIndex", -1000, true);
4288 this.overlays.sort(this.compareZIndexDesc);
4289 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4291 o.hideEvent.unsubscribe(o.blur);
4292 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4293 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4294 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4297 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4298 o.cfg.setProperty("zIndex", originalZ, true);
4299 o.cfg.setProperty("manager", null);
4302 /* _managed Flag for custom or existing. Don't want to remove existing */
4303 if (o.focusEvent._managed) { o.focusEvent = null; }
4304 if (o.blurEvent._managed) { o.blurEvent = null; }
4306 if (o.focus._managed) { o.focus = null; }
4307 if (o.blur._managed) { o.blur = null; }
4312 * Removes focus from all registered Overlays in the manager
4315 this.blurAll = function () {
4317 var nOverlays = this.overlays.length,
4320 if (nOverlays > 0) {
4323 this.overlays[i].blur();
4330 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4333 * @method _manageBlur
4334 * @param {Overlay} overlay The overlay instance which got blurred.
4337 this._manageBlur = function (overlay) {
4338 var changed = false;
4339 if (activeOverlay == overlay) {
4340 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4341 activeOverlay = null;
4348 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4351 * @method _manageFocus
4352 * @param {Overlay} overlay The overlay instance which got focus.
4355 this._manageFocus = function(overlay) {
4356 var changed = false;
4357 if (activeOverlay != overlay) {
4358 if (activeOverlay) {
4359 activeOverlay.blur();
4361 activeOverlay = overlay;
4362 this.bringToTop(activeOverlay);
4363 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4369 var overlays = this.cfg.getProperty("overlays");
4371 if (! this.overlays) {
4376 this.register(overlays);
4377 this.overlays.sort(this.compareZIndexDesc);
4382 * @method _onOverlayElementFocus
4383 * @description Event handler for the DOM event that is used to focus
4384 * the Overlay instance as specified by the "focusevent"
4385 * configuration property.
4387 * @param {Event} p_oEvent Object representing the DOM event
4388 * object passed back by the event utility (Event).
4390 _onOverlayElementFocus: function (p_oEvent) {
4392 var oTarget = Event.getTarget(p_oEvent),
4393 oClose = this.close;
4395 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4403 * @method _onOverlayDestroy
4404 * @description "destroy" event handler for the Overlay.
4406 * @param {String} p_sType String representing the name of the event
4408 * @param {Array} p_aArgs Array of arguments sent when the event
4410 * @param {Overlay} p_oOverlay Object representing the overlay that
4413 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4414 this.remove(p_oOverlay);
4418 * @method _onOverlayFocusHandler
4420 * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4423 * @param {String} p_sType String representing the name of the event
4425 * @param {Array} p_aArgs Array of arguments sent when the event
4427 * @param {Overlay} p_oOverlay Object representing the overlay that
4430 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4431 this._manageFocus(p_oOverlay);
4435 * @method _onOverlayBlurHandler
4436 * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4439 * @param {String} p_sType String representing the name of the event
4441 * @param {Array} p_aArgs Array of arguments sent when the event
4443 * @param {Overlay} p_oOverlay Object representing the overlay that
4446 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4447 this._manageBlur(p_oOverlay);
4451 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4452 * monitor focus state.
4454 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4455 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4456 * on the instance, the _bindFocus method will add them, and the focus method will
4457 * update the OverlayManager's state directly.
4459 * @method _bindFocus
4460 * @param {Overlay} overlay The overlay for which focus needs to be managed
4463 _bindFocus : function(overlay) {
4466 if (!overlay.focusEvent) {
4467 overlay.focusEvent = overlay.createEvent("focus");
4468 overlay.focusEvent.signature = CustomEvent.LIST;
4469 overlay.focusEvent._managed = true;
4471 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4474 if (!overlay.focus) {
4475 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4476 overlay.focus = function () {
4477 if (mgr._manageFocus(this)) {
4479 if (this.cfg.getProperty("visible") && this.focusFirst) {
4482 this.focusEvent.fire();
4485 overlay.focus._managed = true;
4490 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4491 * monitor blur state.
4493 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4494 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4495 * on the instance, the _bindBlur method will add them, and the blur method
4496 * update the OverlayManager's state directly.
4499 * @param {Overlay} overlay The overlay for which blur needs to be managed
4502 _bindBlur : function(overlay) {
4505 if (!overlay.blurEvent) {
4506 overlay.blurEvent = overlay.createEvent("blur");
4507 overlay.blurEvent.signature = CustomEvent.LIST;
4508 overlay.focusEvent._managed = true;
4510 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4513 if (!overlay.blur) {
4514 overlay.blur = function () {
4515 if (mgr._manageBlur(this)) {
4516 this.blurEvent.fire();
4519 overlay.blur._managed = true;
4522 overlay.hideEvent.subscribe(overlay.blur);
4526 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4527 * to be removed for the OverlayManager when destroyed.
4529 * @method _bindDestroy
4530 * @param {Overlay} overlay The overlay instance being managed
4533 _bindDestroy : function(overlay) {
4535 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4539 * Ensures the zIndex configuration property on the managed overlay based instance
4540 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4542 * @method _syncZIndex
4543 * @param {Overlay} overlay The overlay instance being managed
4546 _syncZIndex : function(overlay) {
4547 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4548 if (!isNaN(zIndex)) {
4549 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4551 overlay.cfg.setProperty("zIndex", 0);
4556 * Registers an Overlay or an array of Overlays with the manager. Upon
4557 * registration, the Overlay receives functions for focus and blur,
4558 * along with CustomEvents for each.
4561 * @param {Overlay} overlay An Overlay to register with the manager.
4562 * @param {Overlay[]} overlay An array of Overlays to register with
4564 * @return {boolean} true if any Overlays are registered.
4566 register: function (overlay) {
4568 var registered = false,
4572 if (overlay instanceof Overlay) {
4574 overlay.cfg.addProperty("manager", { value: this } );
4576 this._bindFocus(overlay);
4577 this._bindBlur(overlay);
4578 this._bindDestroy(overlay);
4579 this._syncZIndex(overlay);
4581 this.overlays.push(overlay);
4582 this.bringToTop(overlay);
4586 } else if (overlay instanceof Array) {
4588 for (i = 0, n = overlay.length; i < n; i++) {
4589 registered = this.register(overlay[i]) || registered;
4598 * Places the specified Overlay instance on top of all other
4599 * Overlay instances.
4600 * @method bringToTop
4601 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4603 * @param {String} p_oOverlay String representing the id of an
4606 bringToTop: function (p_oOverlay) {
4608 var oOverlay = this.find(p_oOverlay),
4615 aOverlays = this.overlays;
4616 aOverlays.sort(this.compareZIndexDesc);
4618 oTopOverlay = aOverlays[0];
4621 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4623 if (!isNaN(nTopZIndex)) {
4625 var bRequiresBump = false;
4627 if (oTopOverlay !== oOverlay) {
4628 bRequiresBump = true;
4629 } else if (aOverlays.length > 1) {
4630 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4631 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4632 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4633 bRequiresBump = true;
4637 if (bRequiresBump) {
4638 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4641 aOverlays.sort(this.compareZIndexDesc);
4647 * Attempts to locate an Overlay by instance or ID.
4649 * @param {Overlay} overlay An Overlay to locate within the manager
4650 * @param {String} overlay An Overlay id to locate within the manager
4651 * @return {Overlay} The requested Overlay, if found, or null if it
4652 * cannot be located.
4654 find: function (overlay) {
4656 var isInstance = overlay instanceof Overlay,
4657 overlays = this.overlays,
4658 n = overlays.length,
4663 if (isInstance || typeof overlay == "string") {
4664 for (i = n-1; i >= 0; i--) {
4666 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4677 * Used for sorting the manager's Overlays by z-index.
4678 * @method compareZIndexDesc
4680 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4681 * fall in the stacking order.
4683 compareZIndexDesc: function (o1, o2) {
4685 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4686 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4688 if (zIndex1 === null && zIndex2 === null) {
4690 } else if (zIndex1 === null){
4692 } else if (zIndex2 === null) {
4694 } else if (zIndex1 > zIndex2) {
4696 } else if (zIndex1 < zIndex2) {
4704 * Shows all Overlays in the manager.
4707 showAll: function () {
4708 var overlays = this.overlays,
4709 n = overlays.length,
4712 for (i = n - 1; i >= 0; i--) {
4718 * Hides all Overlays in the manager.
4721 hideAll: function () {
4722 var overlays = this.overlays,
4723 n = overlays.length,
4726 for (i = n - 1; i >= 0; i--) {
4732 * Returns a string representation of the object.
4734 * @return {String} The string representation of the OverlayManager
4736 toString: function () {
4737 return "OverlayManager";
4744 * ContainerEffect encapsulates animation transitions that are executed when
4745 * an Overlay is shown or hidden.
4746 * @namespace YAHOO.widget
4747 * @class ContainerEffect
4749 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
4750 * should be associated with
4751 * @param {Object} attrIn The object literal representing the animation
4752 * arguments to be used for the animate-in transition. The arguments for
4753 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4754 * duration(Number), and method(i.e. Easing.easeIn).
4755 * @param {Object} attrOut The object literal representing the animation
4756 * arguments to be used for the animate-out transition. The arguments for
4757 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4758 * duration(Number), and method(i.e. Easing.easeIn).
4759 * @param {HTMLElement} targetElement Optional. The target element that
4760 * should be animated during the transition. Defaults to overlay.element.
4761 * @param {class} Optional. The animation class to instantiate. Defaults to
4762 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4764 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
4767 animClass = YAHOO.util.Anim;
4771 * The overlay to animate
4773 * @type YAHOO.widget.Overlay
4775 this.overlay = overlay;
4778 * The animation attributes to use when transitioning into view
4782 this.attrIn = attrIn;
4785 * The animation attributes to use when transitioning out of view
4789 this.attrOut = attrOut;
4792 * The target element to be animated
4793 * @property targetElement
4796 this.targetElement = targetElement || overlay.element;
4799 * The animation class to use for animating the overlay
4800 * @property animClass
4803 this.animClass = animClass;
4808 var Dom = YAHOO.util.Dom,
4809 CustomEvent = YAHOO.util.CustomEvent,
4810 ContainerEffect = YAHOO.widget.ContainerEffect;
4814 * A pre-configured ContainerEffect instance that can be used for fading
4815 * an overlay in and out.
4818 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4819 * @param {Number} dur The duration of the animation
4820 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4822 ContainerEffect.FADE = function (overlay, dur) {
4824 var Easing = YAHOO.util.Easing,
4826 attributes: {opacity:{from:0, to:1}},
4828 method: Easing.easeIn
4831 attributes: {opacity:{to:0}},
4833 method: Easing.easeOut
4835 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
4837 fade.handleUnderlayStart = function() {
4838 var underlay = this.overlay.underlay;
4839 if (underlay && YAHOO.env.ua.ie) {
4840 var hasFilters = (underlay.filters && underlay.filters.length > 0);
4842 Dom.addClass(overlay.element, "yui-effect-fade");
4847 fade.handleUnderlayComplete = function() {
4848 var underlay = this.overlay.underlay;
4849 if (underlay && YAHOO.env.ua.ie) {
4850 Dom.removeClass(overlay.element, "yui-effect-fade");
4854 fade.handleStartAnimateIn = function (type, args, obj) {
4855 Dom.addClass(obj.overlay.element, "hide-select");
4857 if (!obj.overlay.underlay) {
4858 obj.overlay.cfg.refireEvent("underlay");
4861 obj.handleUnderlayStart();
4863 obj.overlay._setDomVisibility(true);
4864 Dom.setStyle(obj.overlay.element, "opacity", 0);
4867 fade.handleCompleteAnimateIn = function (type,args,obj) {
4868 Dom.removeClass(obj.overlay.element, "hide-select");
4870 if (obj.overlay.element.style.filter) {
4871 obj.overlay.element.style.filter = null;
4874 obj.handleUnderlayComplete();
4876 obj.overlay.cfg.refireEvent("iframe");
4877 obj.animateInCompleteEvent.fire();
4880 fade.handleStartAnimateOut = function (type, args, obj) {
4881 Dom.addClass(obj.overlay.element, "hide-select");
4882 obj.handleUnderlayStart();
4885 fade.handleCompleteAnimateOut = function (type, args, obj) {
4886 Dom.removeClass(obj.overlay.element, "hide-select");
4887 if (obj.overlay.element.style.filter) {
4888 obj.overlay.element.style.filter = null;
4890 obj.overlay._setDomVisibility(false);
4891 Dom.setStyle(obj.overlay.element, "opacity", 1);
4893 obj.handleUnderlayComplete();
4895 obj.overlay.cfg.refireEvent("iframe");
4896 obj.animateOutCompleteEvent.fire();
4905 * A pre-configured ContainerEffect instance that can be used for sliding an
4906 * overlay in and out.
4909 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4910 * @param {Number} dur The duration of the animation
4911 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4913 ContainerEffect.SLIDE = function (overlay, dur) {
4914 var Easing = YAHOO.util.Easing,
4916 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
4917 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
4918 clientWidth = Dom.getClientWidth(),
4919 offsetWidth = overlay.element.offsetWidth,
4922 attributes: { points: { to: [x, y] } },
4924 method: Easing.easeIn
4928 attributes: { points: { to: [(clientWidth + 25), y] } },
4930 method: Easing.easeOut
4933 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
4935 slide.handleStartAnimateIn = function (type,args,obj) {
4936 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
4937 obj.overlay.element.style.top = y + "px";
4940 slide.handleTweenAnimateIn = function (type, args, obj) {
4942 var pos = Dom.getXY(obj.overlay.element),
4946 if (Dom.getStyle(obj.overlay.element, "visibility") ==
4947 "hidden" && currentX < x) {
4949 obj.overlay._setDomVisibility(true);
4953 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
4954 obj.overlay.cfg.refireEvent("iframe");
4957 slide.handleCompleteAnimateIn = function (type, args, obj) {
4958 obj.overlay.cfg.setProperty("xy", [x, y], true);
4961 obj.overlay.cfg.refireEvent("iframe");
4962 obj.animateInCompleteEvent.fire();
4965 slide.handleStartAnimateOut = function (type, args, obj) {
4967 var vw = Dom.getViewportWidth(),
4968 pos = Dom.getXY(obj.overlay.element),
4971 obj.animOut.attributes.points.to = [(vw + 25), yso];
4974 slide.handleTweenAnimateOut = function (type, args, obj) {
4976 var pos = Dom.getXY(obj.overlay.element),
4980 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
4981 obj.overlay.cfg.refireEvent("iframe");
4984 slide.handleCompleteAnimateOut = function (type, args, obj) {
4985 obj.overlay._setDomVisibility(false);
4987 obj.overlay.cfg.setProperty("xy", [x, y]);
4988 obj.animateOutCompleteEvent.fire();
4995 ContainerEffect.prototype = {
4998 * Initializes the animation classes and events.
5003 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
5004 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
5006 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
5007 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
5009 this.animateInCompleteEvent = this.createEvent("animateInComplete");
5010 this.animateInCompleteEvent.signature = CustomEvent.LIST;
5012 this.animateOutCompleteEvent =
5013 this.createEvent("animateOutComplete");
5014 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
5016 this.animIn = new this.animClass(this.targetElement,
5017 this.attrIn.attributes, this.attrIn.duration,
5018 this.attrIn.method);
5020 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
5021 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
5023 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
5026 this.animOut = new this.animClass(this.targetElement,
5027 this.attrOut.attributes, this.attrOut.duration,
5028 this.attrOut.method);
5030 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
5031 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
5032 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
5038 * Triggers the in-animation.
5041 animateIn: function () {
5042 this.beforeAnimateInEvent.fire();
5043 this.animIn.animate();
5047 * Triggers the out-animation.
5048 * @method animateOut
5050 animateOut: function () {
5051 this.beforeAnimateOutEvent.fire();
5052 this.animOut.animate();
5056 * The default onStart handler for the in-animation.
5057 * @method handleStartAnimateIn
5058 * @param {String} type The CustomEvent type
5059 * @param {Object[]} args The CustomEvent arguments
5060 * @param {Object} obj The scope object
5062 handleStartAnimateIn: function (type, args, obj) { },
5065 * The default onTween handler for the in-animation.
5066 * @method handleTweenAnimateIn
5067 * @param {String} type The CustomEvent type
5068 * @param {Object[]} args The CustomEvent arguments
5069 * @param {Object} obj The scope object
5071 handleTweenAnimateIn: function (type, args, obj) { },
5074 * The default onComplete handler for the in-animation.
5075 * @method handleCompleteAnimateIn
5076 * @param {String} type The CustomEvent type
5077 * @param {Object[]} args The CustomEvent arguments
5078 * @param {Object} obj The scope object
5080 handleCompleteAnimateIn: function (type, args, obj) { },
5083 * The default onStart handler for the out-animation.
5084 * @method handleStartAnimateOut
5085 * @param {String} type The CustomEvent type
5086 * @param {Object[]} args The CustomEvent arguments
5087 * @param {Object} obj The scope object
5089 handleStartAnimateOut: function (type, args, obj) { },
5092 * The default onTween handler for the out-animation.
5093 * @method handleTweenAnimateOut
5094 * @param {String} type The CustomEvent type
5095 * @param {Object[]} args The CustomEvent arguments
5096 * @param {Object} obj The scope object
5098 handleTweenAnimateOut: function (type, args, obj) { },
5101 * The default onComplete handler for the out-animation.
5102 * @method handleCompleteAnimateOut
5103 * @param {String} type The CustomEvent type
5104 * @param {Object[]} args The CustomEvent arguments
5105 * @param {Object} obj The scope object
5107 handleCompleteAnimateOut: function (type, args, obj) { },
5110 * Returns a string representation of the object.
5112 * @return {String} The string representation of the ContainerEffect
5114 toString: function () {
5115 var output = "ContainerEffect";
5117 output += " [" + this.overlay.toString() + "]";
5123 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
5126 YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.8.0r4", build: "2449"});