2 Copyright (c) 2007, 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 YAHOO.log("No owner specified for Config object", "error");
37 var Lang = YAHOO.lang,
38 CustomEvent = YAHOO.util.CustomEvent,
39 Config = YAHOO.util.Config;
43 * Constant representing the CustomEvent type for the config changed event.
44 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
49 Config.CONFIG_CHANGED_EVENT = "configChanged";
52 * Constant representing the boolean type string
53 * @property YAHOO.util.Config.BOOLEAN_TYPE
58 Config.BOOLEAN_TYPE = "boolean";
63 * Object reference to the owner of this Config Object
70 * Boolean flag that specifies whether a queue is currently
72 * @property queueInProgress
75 queueInProgress: false,
78 * Maintains the local collection of configuration property objects and
79 * their specified values
87 * Maintains the local collection of configuration property objects as
88 * they were initially applied.
89 * This object is used when resetting a property.
90 * @property initialConfig
97 * Maintains the local, normalized CustomEvent queue
98 * @property eventQueue
105 * Custom Event, notifying subscribers when Config properties are set
106 * (setProperty is called without the silent flag
107 * @event configChangedEvent
109 configChangedEvent: null,
112 * Initializes the configuration Object and all of its local members.
114 * @param {Object} owner The owner Object to which this Config
117 init: function (owner) {
121 this.configChangedEvent =
122 this.createEvent(Config.CONFIG_CHANGED_EVENT);
124 this.configChangedEvent.signature = CustomEvent.LIST;
125 this.queueInProgress = false;
127 this.initialConfig = {};
128 this.eventQueue = [];
133 * Validates that the value passed in is a Boolean.
134 * @method checkBoolean
135 * @param {Object} val The value to validate
136 * @return {Boolean} true, if the value is valid
138 checkBoolean: function (val) {
139 return (typeof val == Config.BOOLEAN_TYPE);
143 * Validates that the value passed in is a number.
144 * @method checkNumber
145 * @param {Object} val The value to validate
146 * @return {Boolean} true, if the value is valid
148 checkNumber: function (val) {
149 return (!isNaN(val));
153 * Fires a configuration property event using the specified value.
156 * @param {String} key The configuration property's name
157 * @param {value} Object The value of the correct type for the property
159 fireEvent: function ( key, value ) {
160 YAHOO.log("Firing Config event: " + key + "=" + value, "info");
161 var property = this.config[key];
163 if (property && property.event) {
164 property.event.fire(value);
169 * Adds a property to the Config Object's private config hash.
170 * @method addProperty
171 * @param {String} key The configuration property's name
172 * @param {Object} propertyObject The Object containing all of this
173 * property's arguments
175 addProperty: function ( key, propertyObject ) {
176 key = key.toLowerCase();
177 YAHOO.log("Added property: " + key, "info");
179 this.config[key] = propertyObject;
181 propertyObject.event = this.createEvent(key, { scope: this.owner });
182 propertyObject.event.signature = CustomEvent.LIST;
185 propertyObject.key = key;
187 if (propertyObject.handler) {
188 propertyObject.event.subscribe(propertyObject.handler,
192 this.setProperty(key, propertyObject.value, true);
194 if (! propertyObject.suppressEvent) {
195 this.queueProperty(key, propertyObject.value);
201 * Returns a key-value configuration map of the values currently set in
204 * @return {Object} The current config, represented in a key-value map
206 getConfig: function () {
212 for (prop in this.config) {
213 property = this.config[prop];
214 if (property && property.event) {
215 cfg[prop] = property.value;
223 * Returns the value of specified property.
224 * @method getProperty
225 * @param {String} key The name of the property
226 * @return {Object} The value of the specified property
228 getProperty: function (key) {
229 var property = this.config[key.toLowerCase()];
230 if (property && property.event) {
231 return property.value;
238 * Resets the specified property's value to its initial value.
239 * @method resetProperty
240 * @param {String} key The name of the property
241 * @return {Boolean} True is the property was reset, false if not
243 resetProperty: function (key) {
245 key = key.toLowerCase();
247 var property = this.config[key];
249 if (property && property.event) {
251 if (this.initialConfig[key] &&
252 !Lang.isUndefined(this.initialConfig[key])) {
254 this.setProperty(key, this.initialConfig[key]);
268 * Sets the value of a property. If the silent property is passed as
269 * true, the property's event will not be fired.
270 * @method setProperty
271 * @param {String} key The name of the property
272 * @param {String} value The value to set the property to
273 * @param {Boolean} silent Whether the value should be set silently,
274 * without firing the property event.
275 * @return {Boolean} True, if the set was successful, false if it failed.
277 setProperty: function (key, value, silent) {
281 key = key.toLowerCase();
282 YAHOO.log("setProperty: " + key + "=" + value, "info");
284 if (this.queueInProgress && ! silent) {
285 // Currently running through a queue...
286 this.queueProperty(key,value);
290 property = this.config[key];
291 if (property && property.event) {
292 if (property.validator && !property.validator(value)) {
295 property.value = value;
297 this.fireEvent(key, value);
298 this.configChangedEvent.fire([key, value]);
309 * Sets the value of a property and queues its event to execute. If the
310 * event is already scheduled to execute, it is
311 * moved from its current position to the end of the queue.
312 * @method queueProperty
313 * @param {String} key The name of the property
314 * @param {String} value The value to set the property to
315 * @return {Boolean} true, if the set was successful, false if
318 queueProperty: function (key, value) {
320 key = key.toLowerCase();
321 YAHOO.log("queueProperty: " + key + "=" + value, "info");
323 var property = this.config[key],
324 foundDuplicate = false,
339 if (property && property.event) {
341 if (!Lang.isUndefined(value) && property.validator &&
342 !property.validator(value)) { // validator
346 if (!Lang.isUndefined(value)) {
347 property.value = value;
349 value = property.value;
352 foundDuplicate = false;
353 iLen = this.eventQueue.length;
355 for (i = 0; i < iLen; i++) {
356 queueItem = this.eventQueue[i];
359 queueItemKey = queueItem[0];
360 queueItemValue = queueItem[1];
362 if (queueItemKey == key) {
365 found a dupe... push to end of queue, null
366 current item, and break
369 this.eventQueue[i] = null;
371 this.eventQueue.push(
372 [key, (!Lang.isUndefined(value) ?
373 value : queueItemValue)]);
375 foundDuplicate = true;
381 // this is a refire, or a new property in the queue
383 if (! foundDuplicate && !Lang.isUndefined(value)) {
384 this.eventQueue.push([key, value]);
388 if (property.supercedes) {
390 sLen = property.supercedes.length;
392 for (s = 0; s < sLen; s++) {
394 supercedesCheck = property.supercedes[s];
395 qLen = this.eventQueue.length;
397 for (q = 0; q < qLen; q++) {
398 queueItemCheck = this.eventQueue[q];
400 if (queueItemCheck) {
401 queueItemCheckKey = queueItemCheck[0];
402 queueItemCheckValue = queueItemCheck[1];
404 if (queueItemCheckKey ==
405 supercedesCheck.toLowerCase() ) {
407 this.eventQueue.push([queueItemCheckKey,
408 queueItemCheckValue]);
410 this.eventQueue[q] = null;
419 YAHOO.log("Config event queue: " + this.outputEventQueue(), "info");
428 * Fires the event for a property using the property's current value.
429 * @method refireEvent
430 * @param {String} key The name of the property
432 refireEvent: function (key) {
434 key = key.toLowerCase();
436 var property = this.config[key];
438 if (property && property.event &&
440 !Lang.isUndefined(property.value)) {
442 if (this.queueInProgress) {
444 this.queueProperty(key);
448 this.fireEvent(key, property.value);
456 * Applies a key-value Object literal to the configuration, replacing
457 * any existing values, and queueing the property events.
458 * Although the values will be set, fireQueue() must be called for their
459 * associated events to execute.
460 * @method applyConfig
461 * @param {Object} userConfig The configuration Object literal
462 * @param {Boolean} init When set to true, the initialConfig will
463 * be set to the userConfig passed in, so that calling a reset will
464 * reset the properties to the passed values.
466 applyConfig: function (userConfig, init) {
476 for (sKey in userConfig) {
478 if (Lang.hasOwnProperty(userConfig, sKey)) {
480 oConfig[sKey.toLowerCase()] = userConfig[sKey];
486 this.initialConfig = oConfig;
490 for (sKey in userConfig) {
492 if (Lang.hasOwnProperty(userConfig, sKey)) {
494 this.queueProperty(sKey, userConfig[sKey]);
503 * Refires the events for all configuration properties using their
507 refresh: function () {
511 for (prop in this.config) {
512 this.refireEvent(prop);
517 * Fires the normalized list of queued property change events
520 fireQueue: function () {
528 this.queueInProgress = true;
529 for (i = 0;i < this.eventQueue.length; i++) {
530 queueItem = this.eventQueue[i];
534 value = queueItem[1];
535 property = this.config[key];
537 property.value = value;
539 this.fireEvent(key,value);
543 this.queueInProgress = false;
544 this.eventQueue = [];
548 * Subscribes an external handler to the change event for any
550 * @method subscribeToConfigEvent
551 * @param {String} key The property name
552 * @param {Function} handler The handler function to use subscribe to
553 * the property's event
554 * @param {Object} obj The Object to use for scoping the event handler
555 * (see CustomEvent documentation)
556 * @param {Boolean} override Optional. If true, will override "this"
557 * within the handler to map to the scope Object passed into the method.
558 * @return {Boolean} True, if the subscription was successful,
561 subscribeToConfigEvent: function (key, handler, obj, override) {
563 var property = this.config[key.toLowerCase()];
565 if (property && property.event) {
567 if (!Config.alreadySubscribed(property.event, handler, obj)) {
569 property.event.subscribe(handler, obj, override);
584 * Unsubscribes an external handler from the change event for any
586 * @method unsubscribeFromConfigEvent
587 * @param {String} key The property name
588 * @param {Function} handler The handler function to use subscribe to
589 * the property's event
590 * @param {Object} obj The Object to use for scoping the event
591 * handler (see CustomEvent documentation)
592 * @return {Boolean} True, if the unsubscription was successful,
595 unsubscribeFromConfigEvent: function (key, handler, obj) {
596 var property = this.config[key.toLowerCase()];
597 if (property && property.event) {
598 return property.event.unsubscribe(handler, obj);
605 * Returns a string representation of the Config object
607 * @return {String} The Config object in string format.
609 toString: function () {
610 var output = "Config";
612 output += " [" + this.owner.toString() + "]";
618 * Returns a string representation of the Config object's current
620 * @method outputEventQueue
621 * @return {String} The string list of CustomEvents currently queued
624 outputEventQueue: function () {
629 nQueue = this.eventQueue.length;
631 for (q = 0; q < nQueue; q++) {
632 queueItem = this.eventQueue[q];
634 output += queueItem[0] + "=" + queueItem[1] + ", ";
641 * Sets all properties to null, unsubscribes all listeners from each
642 * property's change event and all listeners from the configChangedEvent.
645 destroy: function () {
647 var oConfig = this.config,
652 for (sProperty in oConfig) {
654 if (Lang.hasOwnProperty(oConfig, sProperty)) {
656 oProperty = oConfig[sProperty];
658 oProperty.event.unsubscribeAll();
659 oProperty.event = null;
665 this.configChangedEvent.unsubscribeAll();
667 this.configChangedEvent = null;
670 this.initialConfig = null;
671 this.eventQueue = null;
680 * Checks to determine if a particular function/Object pair are already
681 * subscribed to the specified CustomEvent
682 * @method YAHOO.util.Config.alreadySubscribed
684 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
686 * @param {Function} fn The function to look for in the subscribers list
687 * @param {Object} obj The execution scope Object for the subscription
688 * @return {Boolean} true, if the function/Object pair is already subscribed
689 * to the CustomEvent passed in
691 Config.alreadySubscribed = function (evt, fn, obj) {
693 var nSubscribers = evt.subscribers.length,
697 if (nSubscribers > 0) {
699 i = nSubscribers - 1;
703 subsc = evt.subscribers[i];
705 if (subsc && subsc.obj == obj && subsc.fn == fn) {
720 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
726 * The Container family of components is designed to enable developers to
727 * create different kinds of content-containing modules on the web. Module
728 * and Overlay are the most basic containers, and they can be used directly
729 * or extended to build custom containers. Also part of the Container family
730 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
731 * Dialog, and SimpleDialog.
734 * @requires yahoo, dom, event
735 * @optional dragdrop, animation, button
739 * Module is a JavaScript representation of the Standard Module Format.
740 * Standard Module Format is a simple standard for markup containers where
741 * child nodes representing the header, body, and footer of the content are
742 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
743 * Module is the base class for all other classes in the YUI
745 * @namespace YAHOO.widget
748 * @param {String} el The element ID representing the Module <em>OR</em>
749 * @param {HTMLElement} el The element representing the Module
750 * @param {Object} userConfig The configuration Object literal containing
751 * the configuration that should be set for this module. See configuration
752 * documentation for more details.
754 YAHOO.widget.Module = function (el, userConfig) {
758 this.init(el, userConfig);
762 YAHOO.log("No element or element ID specified" +
763 " for Module instantiation", "error");
770 var Dom = YAHOO.util.Dom,
771 Config = YAHOO.util.Config,
772 Event = YAHOO.util.Event,
773 CustomEvent = YAHOO.util.CustomEvent,
774 Module = YAHOO.widget.Module,
782 * Constant representing the name of the Module's events
783 * @property EVENT_TYPES
790 "BEFORE_INIT": "beforeInit",
793 "BEFORE_RENDER": "beforeRender",
795 "CHANGE_HEADER": "changeHeader",
796 "CHANGE_BODY": "changeBody",
797 "CHANGE_FOOTER": "changeFooter",
798 "CHANGE_CONTENT": "changeContent",
799 "DESTORY": "destroy",
800 "BEFORE_SHOW": "beforeShow",
802 "BEFORE_HIDE": "beforeHide",
808 * Constant representing the Module's configuration properties
809 * @property DEFAULT_CONFIG
819 validator: YAHOO.lang.isBoolean
825 supercedes: ["visible"]
829 key: "monitorresize",
837 * Constant representing the prefix path to use for non-secure images
838 * @property YAHOO.widget.Module.IMG_ROOT
843 Module.IMG_ROOT = null;
846 * Constant representing the prefix path to use for securely served images
847 * @property YAHOO.widget.Module.IMG_ROOT_SSL
852 Module.IMG_ROOT_SSL = null;
855 * Constant for the default CSS class name that represents a Module
856 * @property YAHOO.widget.Module.CSS_MODULE
861 Module.CSS_MODULE = "yui-module";
864 * Constant representing the module header
865 * @property YAHOO.widget.Module.CSS_HEADER
870 Module.CSS_HEADER = "hd";
873 * Constant representing the module body
874 * @property YAHOO.widget.Module.CSS_BODY
879 Module.CSS_BODY = "bd";
882 * Constant representing the module footer
883 * @property YAHOO.widget.Module.CSS_FOOTER
888 Module.CSS_FOOTER = "ft";
891 * Constant representing the url for the "src" attribute of the iframe
892 * used to monitor changes to the browser's base font size
893 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
898 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
901 * Singleton CustomEvent fired when the font size is changed in the browser.
902 * Opera's "zoom" functionality currently does not support text
904 * @event YAHOO.widget.Module.textResizeEvent
906 Module.textResizeEvent = new CustomEvent("textResize");
909 function createModuleTemplate() {
911 if (!m_oModuleTemplate) {
913 m_oModuleTemplate = document.createElement("div");
915 m_oModuleTemplate.innerHTML = ("<div class=\"" +
916 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
917 Module.CSS_BODY + "\"></div><div class=\"" +
918 Module.CSS_FOOTER + "\"></div>");
920 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
921 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
922 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
926 return m_oModuleTemplate;
931 function createHeader() {
933 if (!m_oHeaderTemplate) {
935 createModuleTemplate();
939 return (m_oHeaderTemplate.cloneNode(false));
944 function createBody() {
946 if (!m_oBodyTemplate) {
948 createModuleTemplate();
952 return (m_oBodyTemplate.cloneNode(false));
957 function createFooter() {
959 if (!m_oFooterTemplate) {
961 createModuleTemplate();
965 return (m_oFooterTemplate.cloneNode(false));
973 * The class's constructor function
974 * @property contructor
980 * The main module element that contains the header, body, and footer
987 * The header element, denoted with CSS class "hd"
994 * The body element, denoted with CSS class "bd"
1001 * The footer element, denoted with CSS class "ft"
1008 * The id of the element
1015 * A string representing the root path for all images created by
1016 * a Module instance.
1017 * @deprecated It is recommend that any images for a Module be applied
1018 * via CSS using the "background-image" property.
1019 * @property imageRoot
1022 imageRoot: Module.IMG_ROOT,
1025 * Initializes the custom events for Module which are fired
1026 * automatically at appropriate times by the Module class.
1027 * @method initEvents
1029 initEvents: function () {
1031 var SIGNATURE = CustomEvent.LIST;
1034 * CustomEvent fired prior to class initalization.
1035 * @event beforeInitEvent
1036 * @param {class} classRef class reference of the initializing
1037 * class, such as this.beforeInitEvent.fire(Module)
1039 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1040 this.beforeInitEvent.signature = SIGNATURE;
1043 * CustomEvent fired after class initalization.
1045 * @param {class} classRef class reference of the initializing
1046 * class, such as this.beforeInitEvent.fire(Module)
1048 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1049 this.initEvent.signature = SIGNATURE;
1052 * CustomEvent fired when the Module is appended to the DOM
1053 * @event appendEvent
1055 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1056 this.appendEvent.signature = SIGNATURE;
1059 * CustomEvent fired before the Module is rendered
1060 * @event beforeRenderEvent
1062 this.beforeRenderEvent =
1063 this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1064 this.beforeRenderEvent.signature = SIGNATURE;
1067 * CustomEvent fired after the Module is rendered
1068 * @event renderEvent
1070 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1071 this.renderEvent.signature = SIGNATURE;
1074 * CustomEvent fired when the header content of the Module
1076 * @event changeHeaderEvent
1077 * @param {String/HTMLElement} content String/element representing
1078 * the new header content
1080 this.changeHeaderEvent =
1081 this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1082 this.changeHeaderEvent.signature = SIGNATURE;
1085 * CustomEvent fired when the body content of the Module is modified
1086 * @event changeBodyEvent
1087 * @param {String/HTMLElement} content String/element representing
1088 * the new body content
1090 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1091 this.changeBodyEvent.signature = SIGNATURE;
1094 * CustomEvent fired when the footer content of the Module
1096 * @event changeFooterEvent
1097 * @param {String/HTMLElement} content String/element representing
1098 * the new footer content
1100 this.changeFooterEvent =
1101 this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1102 this.changeFooterEvent.signature = SIGNATURE;
1105 * CustomEvent fired when the content of the Module is modified
1106 * @event changeContentEvent
1108 this.changeContentEvent =
1109 this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1110 this.changeContentEvent.signature = SIGNATURE;
1113 * CustomEvent fired when the Module is destroyed
1114 * @event destroyEvent
1116 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
1117 this.destroyEvent.signature = SIGNATURE;
1120 * CustomEvent fired before the Module is shown
1121 * @event beforeShowEvent
1123 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1124 this.beforeShowEvent.signature = SIGNATURE;
1127 * CustomEvent fired after the Module is shown
1130 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1131 this.showEvent.signature = SIGNATURE;
1134 * CustomEvent fired before the Module is hidden
1135 * @event beforeHideEvent
1137 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1138 this.beforeHideEvent.signature = SIGNATURE;
1141 * CustomEvent fired after the Module is hidden
1144 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1145 this.hideEvent.signature = SIGNATURE;
1149 * String representing the current user-agent platform
1150 * @property platform
1153 platform: function () {
1155 var ua = navigator.userAgent.toLowerCase();
1157 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1161 } else if (ua.indexOf("macintosh") != -1) {
1174 * String representing the user-agent of the browser
1175 * @deprecated Use YAHOO.env.ua
1179 browser: function () {
1181 var ua = navigator.userAgent.toLowerCase();
1184 Check Opera first in case of spoof and check Safari before
1185 Gecko since Safari's user agent string includes "like Gecko"
1188 if (ua.indexOf('opera') != -1) {
1192 } else if (ua.indexOf('msie 7') != -1) {
1196 } else if (ua.indexOf('msie') != -1) {
1200 } else if (ua.indexOf('safari') != -1) {
1204 } else if (ua.indexOf('gecko') != -1) {
1217 * Boolean representing whether or not the current browsing context is
1219 * @property isSecure
1222 isSecure: function () {
1224 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1237 * Initializes the custom events for Module which are fired
1238 * automatically at appropriate times by the Module class.
1240 initDefaultConfig: function () {
1242 // Add properties //
1245 * Specifies whether the Module is visible on the page.
1250 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1251 handler: this.configVisible,
1252 value: DEFAULT_CONFIG.VISIBLE.value,
1253 validator: DEFAULT_CONFIG.VISIBLE.validator
1257 * Object or array of objects representing the ContainerEffect
1258 * classes that are active for animating the container.
1263 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1264 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1265 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1269 * Specifies whether to create a special proxy iframe to monitor
1270 * for user font resizing in the document
1271 * @config monitorresize
1275 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1276 handler: this.configMonitorResize,
1277 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1283 * The Module class's initialization method, which is executed for
1284 * Module and all of its subclasses. This method is automatically
1285 * called by the constructor, and sets up all DOM references for
1286 * pre-existing markup, and creates required markup if it is not
1289 * @param {String} el The element ID representing the Module <em>OR</em>
1290 * @param {HTMLElement} el The element representing the Module
1291 * @param {Object} userConfig The configuration Object literal
1292 * containing the configuration that should be set for this module.
1293 * See configuration documentation for more details.
1295 init: function (el, userConfig) {
1301 this.beforeInitEvent.fire(Module);
1304 * The Module's Config object used for monitoring
1305 * configuration properties.
1307 * @type YAHOO.util.Config
1309 this.cfg = new Config(this);
1311 if (this.isSecure) {
1312 this.imageRoot = Module.IMG_ROOT_SSL;
1315 if (typeof el == "string") {
1319 el = document.getElementById(el);
1323 el = (createModuleTemplate()).cloneNode(false);
1337 child = this.element.firstChild;
1343 switch (child.className) {
1345 case Module.CSS_HEADER:
1347 this.header = child;
1351 case Module.CSS_BODY:
1357 case Module.CSS_FOOTER:
1359 this.footer = child;
1365 } while ((child = child.nextSibling));
1370 this.initDefaultConfig();
1372 Dom.addClass(this.element, Module.CSS_MODULE);
1375 this.cfg.applyConfig(userConfig, true);
1379 Subscribe to the fireQueue() method of Config so that any
1380 queued configuration changes are excecuted upon render of
1384 if (!Config.alreadySubscribed(this.renderEvent,
1385 this.cfg.fireQueue, this.cfg)) {
1387 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1391 this.initEvent.fire(Module);
1395 * Initialized an empty IFRAME that is placed out of the visible area
1396 * that can be used to detect text resize.
1397 * @method initResizeMonitor
1399 initResizeMonitor: function () {
1405 function fireTextResize() {
1407 Module.textResizeEvent.fire();
1411 if (!YAHOO.env.ua.opera) {
1413 oIFrame = Dom.get("_yuiResizeMonitor");
1417 oIFrame = document.createElement("iframe");
1419 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL &&
1422 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1428 Need to set "src" attribute of the iframe to
1429 prevent the browser from reporting duplicate
1430 cookies. (See SourceForge bug #1721755)
1433 if (YAHOO.env.ua.gecko) {
1435 sHTML = "<html><head><script " +
1436 "type=\"text/javascript\">" +
1437 "window.onresize=function(){window.parent." +
1438 "YAHOO.widget.Module.textResizeEvent." +
1439 "fire();};window.parent.YAHOO.widget.Module." +
1440 "textResizeEvent.fire();</script></head>" +
1441 "<body></body></html>";
1443 oIFrame.src = "data:text/html;charset=utf-8," +
1444 encodeURIComponent(sHTML);
1448 oIFrame.id = "_yuiResizeMonitor";
1451 Need to set "position" property before inserting the
1452 iframe into the document or Safari's status bar will
1453 forever indicate the iframe is loading
1454 (See SourceForge bug #1723064)
1457 oIFrame.style.position = "absolute";
1458 oIFrame.style.visibility = "hidden";
1460 document.body.appendChild(oIFrame);
1462 oIFrame.style.width = "10em";
1463 oIFrame.style.height = "10em";
1464 oIFrame.style.top = (-1 * oIFrame.offsetHeight) + "px";
1465 oIFrame.style.left = (-1 * oIFrame.offsetWidth) + "px";
1466 oIFrame.style.borderWidth = "0";
1467 oIFrame.style.visibility = "visible";
1469 if (YAHOO.env.ua.webkit) {
1471 oDoc = oIFrame.contentWindow.document;
1480 if (oIFrame && oIFrame.contentWindow) {
1482 Module.textResizeEvent.subscribe(this.onDomResize,
1485 if (!Module.textResizeInitialized) {
1487 if (!Event.on(oIFrame.contentWindow, "resize",
1491 This will fail in IE if document.domain has
1492 changed, so we must change the listener to
1493 use the oIFrame element instead
1496 Event.on(oIFrame, "resize", fireTextResize);
1500 Module.textResizeInitialized = true;
1504 this.resizeMonitor = oIFrame;
1513 * Event handler fired when the resize monitor element is resized.
1514 * @method onDomResize
1515 * @param {DOMEvent} e The DOM resize event
1516 * @param {Object} obj The scope object passed to the handler
1518 onDomResize: function (e, obj) {
1520 var nLeft = -1 * this.resizeMonitor.offsetWidth,
1521 nTop = -1 * this.resizeMonitor.offsetHeight;
1523 this.resizeMonitor.style.top = nTop + "px";
1524 this.resizeMonitor.style.left = nLeft + "px";
1529 * Sets the Module's header content to the HTML specified, or appends
1530 * the passed element to the header. If no header is present, one will
1531 * be automatically created.
1533 * @param {String} headerContent The HTML used to set the header
1535 * @param {HTMLElement} headerContent The HTMLElement to append to
1538 setHeader: function (headerContent) {
1540 var oHeader = this.header || (this.header = createHeader());
1542 if (typeof headerContent == "string") {
1544 oHeader.innerHTML = headerContent;
1548 oHeader.innerHTML = "";
1549 oHeader.appendChild(headerContent);
1553 this.changeHeaderEvent.fire(headerContent);
1554 this.changeContentEvent.fire();
1559 * Appends the passed element to the header. If no header is present,
1560 * one will be automatically created.
1561 * @method appendToHeader
1562 * @param {HTMLElement} element The element to append to the header
1564 appendToHeader: function (element) {
1566 var oHeader = this.header || (this.header = createHeader());
1568 oHeader.appendChild(element);
1570 this.changeHeaderEvent.fire(element);
1571 this.changeContentEvent.fire();
1576 * Sets the Module's body content to the HTML specified, or appends the
1577 * passed element to the body. If no body is present, one will be
1578 * automatically created.
1580 * @param {String} bodyContent The HTML used to set the body <em>OR</em>
1581 * @param {HTMLElement} bodyContent The HTMLElement to append to the body
1583 setBody: function (bodyContent) {
1585 var oBody = this.body || (this.body = createBody());
1587 if (typeof bodyContent == "string") {
1589 oBody.innerHTML = bodyContent;
1593 oBody.innerHTML = "";
1594 oBody.appendChild(bodyContent);
1598 this.changeBodyEvent.fire(bodyContent);
1599 this.changeContentEvent.fire();
1604 * Appends the passed element to the body. If no body is present, one
1605 * will be automatically created.
1606 * @method appendToBody
1607 * @param {HTMLElement} element The element to append to the body
1609 appendToBody: function (element) {
1611 var oBody = this.body || (this.body = createBody());
1613 oBody.appendChild(element);
1615 this.changeBodyEvent.fire(element);
1616 this.changeContentEvent.fire();
1621 * Sets the Module's footer content to the HTML specified, or appends
1622 * the passed element to the footer. If no footer is present, one will
1623 * be automatically created.
1625 * @param {String} footerContent The HTML used to set the footer
1627 * @param {HTMLElement} footerContent The HTMLElement to append to
1630 setFooter: function (footerContent) {
1632 var oFooter = this.footer || (this.footer = createFooter());
1634 if (typeof footerContent == "string") {
1636 oFooter.innerHTML = footerContent;
1640 oFooter.innerHTML = "";
1641 oFooter.appendChild(footerContent);
1645 this.changeFooterEvent.fire(footerContent);
1646 this.changeContentEvent.fire();
1651 * Appends the passed element to the footer. If no footer is present,
1652 * one will be automatically created.
1653 * @method appendToFooter
1654 * @param {HTMLElement} element The element to append to the footer
1656 appendToFooter: function (element) {
1658 var oFooter = this.footer || (this.footer = createFooter());
1660 oFooter.appendChild(element);
1662 this.changeFooterEvent.fire(element);
1663 this.changeContentEvent.fire();
1668 * Renders the Module by inserting the elements that are not already
1669 * in the main Module into their correct places. Optionally appends
1670 * the Module to the specified node prior to the render's execution.
1671 * NOTE: For Modules without existing markup, the appendToNode argument
1672 * is REQUIRED. If this argument is ommitted and the current element is
1673 * not present in the document, the function will return false,
1674 * indicating that the render was a failure.
1676 * @param {String} appendToNode The element id to which the Module
1677 * should be appended to prior to rendering <em>OR</em>
1678 * @param {HTMLElement} appendToNode The element to which the Module
1679 * should be appended to prior to rendering
1680 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1681 * represents the actual Standard Module container.
1682 * @return {Boolean} Success or failure of the render
1684 render: function (appendToNode, moduleElement) {
1689 function appendTo(element) {
1690 if (typeof element == "string") {
1691 element = document.getElementById(element);
1695 element.appendChild(me.element);
1696 me.appendEvent.fire();
1700 this.beforeRenderEvent.fire();
1702 if (! moduleElement) {
1703 moduleElement = this.element;
1708 appendTo(appendToNode);
1713 No node was passed in. If the element is not already in
1717 if (! Dom.inDocument(this.element)) {
1719 YAHOO.log("Render failed. Must specify appendTo node if " +
1720 " Module isn't already in the DOM.", "error");
1728 // Need to get everything into the DOM if it isn't already
1730 if (this.header && ! Dom.inDocument(this.header)) {
1733 There is a header, but it's not in the DOM yet...
1737 firstChild = moduleElement.firstChild;
1739 if (firstChild) { // Insert before first child if exists
1741 moduleElement.insertBefore(this.header, firstChild);
1743 } else { // Append to empty body because there are no children
1745 moduleElement.appendChild(this.header);
1751 if (this.body && ! Dom.inDocument(this.body)) {
1754 There is a body, but it's not in the DOM yet...
1759 // Insert before footer if exists in DOM
1761 if (this.footer && Dom.isAncestor(
1762 this.moduleElement, this.footer)) {
1764 moduleElement.insertBefore(this.body, this.footer);
1766 } else { // Append to element because there is no footer
1768 moduleElement.appendChild(this.body);
1774 if (this.footer && ! Dom.inDocument(this.footer)) {
1777 There is a footer, but it's not in the DOM yet...
1781 moduleElement.appendChild(this.footer);
1785 this.renderEvent.fire();
1790 * Removes the Module element from the DOM and sets all child elements
1794 destroy: function () {
1800 Event.purgeElement(this.element, true);
1801 parent = this.element.parentNode;
1805 parent.removeChild(this.element);
1808 this.element = null;
1813 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1818 this.destroyEvent.fire();
1821 if (e instanceof CustomEvent) {
1829 * Shows the Module element by setting the visible configuration
1830 * property to true. Also fires two events: beforeShowEvent prior to
1831 * the visibility change, and showEvent after.
1835 this.cfg.setProperty("visible", true);
1839 * Hides the Module element by setting the visible configuration
1840 * property to false. Also fires two events: beforeHideEvent prior to
1841 * the visibility change, and hideEvent after.
1845 this.cfg.setProperty("visible", false);
1848 // BUILT-IN EVENT HANDLERS FOR MODULE //
1851 * Default event handler for changing the visibility property of a
1852 * Module. By default, this is achieved by switching the "display" style
1853 * between "block" and "none".
1854 * This method is responsible for firing showEvent and hideEvent.
1855 * @param {String} type The CustomEvent type (usually the property name)
1856 * @param {Object[]} args The CustomEvent arguments. For configuration
1857 * handlers, args[0] will equal the newly applied value for the property.
1858 * @param {Object} obj The scope object. For configuration handlers,
1859 * this will usually equal the owner.
1860 * @method configVisible
1862 configVisible: function (type, args, obj) {
1863 var visible = args[0];
1865 this.beforeShowEvent.fire();
1866 Dom.setStyle(this.element, "display", "block");
1867 this.showEvent.fire();
1869 this.beforeHideEvent.fire();
1870 Dom.setStyle(this.element, "display", "none");
1871 this.hideEvent.fire();
1876 * Default event handler for the "monitorresize" configuration property
1877 * @param {String} type The CustomEvent type (usually the property name)
1878 * @param {Object[]} args The CustomEvent arguments. For configuration
1879 * handlers, args[0] will equal the newly applied value for the property.
1880 * @param {Object} obj The scope object. For configuration handlers,
1881 * this will usually equal the owner.
1882 * @method configMonitorResize
1884 configMonitorResize: function (type, args, obj) {
1886 var monitor = args[0];
1890 this.initResizeMonitor();
1894 Module.textResizeEvent.unsubscribe(
1895 this.onDomResize, this, true);
1897 this.resizeMonitor = null;
1903 * Returns a String representation of the Object.
1905 * @return {String} The string representation of the Module
1907 toString: function () {
1908 return "Module " + this.id;
1913 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1919 * Overlay is a Module that is absolutely positioned above the page flow. It
1920 * has convenience methods for positioning and sizing, as well as options for
1921 * controlling zIndex and constraining the Overlay's position to the current
1922 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1923 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1924 * properly rendered above SELECT elements.
1925 * @namespace YAHOO.widget
1928 * @param {String} el The element ID representing the Overlay <em>OR</em>
1929 * @param {HTMLElement} el The element representing the Overlay
1930 * @param {Object} userConfig The configuration object literal containing
1931 * the configuration that should be set for this Overlay. See configuration
1932 * documentation for more details.
1935 YAHOO.widget.Overlay = function (el, userConfig) {
1937 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1942 var Lang = YAHOO.lang,
1943 CustomEvent = YAHOO.util.CustomEvent,
1944 Module = YAHOO.widget.Module,
1945 Event = YAHOO.util.Event,
1946 Dom = YAHOO.util.Dom,
1947 Config = YAHOO.util.Config,
1948 Overlay = YAHOO.widget.Overlay,
1953 * Constant representing the name of the Overlay's events
1954 * @property EVENT_TYPES
1961 "BEFORE_MOVE": "beforeMove",
1967 * Constant representing the Overlay's configuration properties
1968 * @property DEFAULT_CONFIG
1977 validator: Lang.isNumber,
1978 suppressEvent: true,
1979 supercedes: ["iframe"]
1984 validator: Lang.isNumber,
1985 suppressEvent: true,
1986 supercedes: ["iframe"]
1991 suppressEvent: true,
1992 supercedes: ["iframe"]
1997 suppressEvent: true,
1998 supercedes: ["iframe"]
2004 validator: Lang.isBoolean,
2005 supercedes: ["iframe", "visible"]
2010 suppressEvent: true,
2011 supercedes: ["context", "fixedcenter", "iframe"]
2016 suppressEvent: true,
2017 supercedes: ["context", "fixedcenter", "iframe"]
2025 "CONSTRAIN_TO_VIEWPORT": {
2026 key: "constraintoviewport",
2028 validator: Lang.isBoolean,
2029 supercedes: ["iframe", "x", "y", "xy"]
2034 value: (YAHOO.env.ua.ie == 6 ? true : false),
2035 validator: Lang.isBoolean,
2036 supercedes: ["zindex"]
2043 * The URL that will be placed in the iframe
2044 * @property YAHOO.widget.Overlay.IFRAME_SRC
2049 Overlay.IFRAME_SRC = "javascript:false;";
2052 * Number representing how much the iframe shim should be offset from each
2053 * side of an Overlay instance.
2054 * @property YAHOO.widget.Overlay.IFRAME_SRC
2060 Overlay.IFRAME_OFFSET = 3;
2063 * Constant representing the top left corner of an element, used for
2064 * configuring the context element alignment
2065 * @property YAHOO.widget.Overlay.TOP_LEFT
2070 Overlay.TOP_LEFT = "tl";
2073 * Constant representing the top right corner of an element, used for
2074 * configuring the context element alignment
2075 * @property YAHOO.widget.Overlay.TOP_RIGHT
2080 Overlay.TOP_RIGHT = "tr";
2083 * Constant representing the top bottom left corner of an element, used for
2084 * configuring the context element alignment
2085 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2090 Overlay.BOTTOM_LEFT = "bl";
2093 * Constant representing the bottom right corner of an element, used for
2094 * configuring the context element alignment
2095 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2100 Overlay.BOTTOM_RIGHT = "br";
2103 * Constant representing the default CSS class used for an Overlay
2104 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2109 Overlay.CSS_OVERLAY = "yui-overlay";
2113 * A singleton CustomEvent used for reacting to the DOM event for
2115 * @event YAHOO.widget.Overlay.windowScrollEvent
2117 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2120 * A singleton CustomEvent used for reacting to the DOM event for
2122 * @event YAHOO.widget.Overlay.windowResizeEvent
2124 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2127 * The DOM event handler used to fire the CustomEvent for window scroll
2128 * @method YAHOO.widget.Overlay.windowScrollHandler
2130 * @param {DOMEvent} e The DOM scroll event
2132 Overlay.windowScrollHandler = function (e) {
2134 if (YAHOO.env.ua.ie) {
2136 if (! window.scrollEnd) {
2138 window.scrollEnd = -1;
2142 clearTimeout(window.scrollEnd);
2144 window.scrollEnd = setTimeout(function () {
2146 Overlay.windowScrollEvent.fire();
2152 Overlay.windowScrollEvent.fire();
2159 * The DOM event handler used to fire the CustomEvent for window resize
2160 * @method YAHOO.widget.Overlay.windowResizeHandler
2162 * @param {DOMEvent} e The DOM resize event
2164 Overlay.windowResizeHandler = function (e) {
2166 if (YAHOO.env.ua.ie) {
2168 if (! window.resizeEnd) {
2169 window.resizeEnd = -1;
2172 clearTimeout(window.resizeEnd);
2174 window.resizeEnd = setTimeout(function () {
2176 Overlay.windowResizeEvent.fire();
2182 Overlay.windowResizeEvent.fire();
2189 * A boolean that indicated whether the window resize and scroll events have
2190 * already been subscribed to.
2191 * @property YAHOO.widget.Overlay._initialized
2195 Overlay._initialized = null;
2197 if (Overlay._initialized === null) {
2199 Event.on(window, "scroll", Overlay.windowScrollHandler);
2200 Event.on(window, "resize", Overlay.windowResizeHandler);
2202 Overlay._initialized = true;
2206 YAHOO.extend(Overlay, Module, {
2209 * The Overlay initialization method, which is executed for Overlay and
2210 * all of its subclasses. This method is automatically called by the
2211 * constructor, and sets up all DOM references for pre-existing markup,
2212 * and creates required markup if it is not already present.
2214 * @param {String} el The element ID representing the Overlay <em>OR</em>
2215 * @param {HTMLElement} el The element representing the Overlay
2216 * @param {Object} userConfig The configuration object literal
2217 * containing the configuration that should be set for this Overlay.
2218 * See configuration documentation for more details.
2220 init: function (el, userConfig) {
2223 Note that we don't pass the user config in here yet because we
2224 only want it executed once, at the lowest subclass level
2227 Overlay.superclass.init.call(this, el/*, userConfig*/);
2229 this.beforeInitEvent.fire(Overlay);
2231 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2235 this.cfg.applyConfig(userConfig, true);
2239 if (this.platform == "mac" && YAHOO.env.ua.gecko) {
2241 if (! Config.alreadySubscribed(this.showEvent,
2242 this.showMacGeckoScrollbars, this)) {
2244 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2249 if (! Config.alreadySubscribed(this.hideEvent,
2250 this.hideMacGeckoScrollbars, this)) {
2252 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2259 this.initEvent.fire(Overlay);
2264 * Initializes the custom events for Overlay which are fired
2265 * automatically at appropriate times by the Overlay class.
2266 * @method initEvents
2268 initEvents: function () {
2270 Overlay.superclass.initEvents.call(this);
2272 var SIGNATURE = CustomEvent.LIST;
2275 * CustomEvent fired before the Overlay is moved.
2276 * @event beforeMoveEvent
2277 * @param {Number} x x coordinate
2278 * @param {Number} y y coordinate
2280 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2281 this.beforeMoveEvent.signature = SIGNATURE;
2284 * CustomEvent fired after the Overlay is moved.
2286 * @param {Number} x x coordinate
2287 * @param {Number} y y coordinate
2289 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2290 this.moveEvent.signature = SIGNATURE;
2295 * Initializes the class's configurable properties which can be changed
2296 * using the Overlay's Config object (cfg).
2297 * @method initDefaultConfig
2299 initDefaultConfig: function () {
2301 Overlay.superclass.initDefaultConfig.call(this);
2304 // Add overlay config properties //
2307 * The absolute x-coordinate position of the Overlay
2312 this.cfg.addProperty(DEFAULT_CONFIG.X.key, {
2314 handler: this.configX,
2315 validator: DEFAULT_CONFIG.X.validator,
2316 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2317 supercedes: DEFAULT_CONFIG.X.supercedes
2323 * The absolute y-coordinate position of the Overlay
2328 this.cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2330 handler: this.configY,
2331 validator: DEFAULT_CONFIG.Y.validator,
2332 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2333 supercedes: DEFAULT_CONFIG.Y.supercedes
2339 * An array with the absolute x and y positions of the Overlay
2344 this.cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2346 handler: this.configXY,
2347 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2348 supercedes: DEFAULT_CONFIG.XY.supercedes
2354 * The array of context arguments for context-sensitive positioning.
2355 * The format is: [id or element, element corner, context corner].
2356 * For example, setting this property to ["img1", "tl", "bl"] would
2357 * align the Overlay's top left corner to the context element's
2358 * bottom left corner.
2363 this.cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2365 handler: this.configContext,
2366 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2367 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2373 * True if the Overlay should be anchored to the center of
2375 * @config fixedcenter
2379 this.cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2381 handler: this.configFixedCenter,
2382 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2383 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2384 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2390 * CSS width of the Overlay.
2395 this.cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2397 handler: this.configWidth,
2398 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2399 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2404 * CSS height of the Overlay.
2409 this.cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2411 handler: this.configHeight,
2412 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2413 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2418 * CSS z-index of the Overlay.
2423 this.cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2425 handler: this.configzIndex,
2426 value: DEFAULT_CONFIG.ZINDEX.value
2431 * True if the Overlay should be prevented from being positioned
2432 * out of the viewport.
2433 * @config constraintoviewport
2437 this.cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2439 handler: this.configConstrainToViewport,
2440 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2441 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2442 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2448 * @description Boolean indicating whether or not the Overlay should
2449 * have an IFRAME shim; used to prevent <SELECT> elements from
2450 * poking through an Overlay instance in IE6. When set to "true",
2451 * the iframe shim is created when the Overlay instance is intially
2454 * @default true for IE6 and below, false for all other browsers.
2456 this.cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2458 handler: this.configIframe,
2459 value: DEFAULT_CONFIG.IFRAME.value,
2460 validator: DEFAULT_CONFIG.IFRAME.validator,
2461 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2468 * Moves the Overlay to the specified position. This function is
2469 * identical to calling this.cfg.setProperty("xy", [x,y]);
2471 * @param {Number} x The Overlay's new x position
2472 * @param {Number} y The Overlay's new y position
2474 moveTo: function (x, y) {
2476 this.cfg.setProperty("xy", [x, y]);
2481 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2482 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2483 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2484 * @method hideMacGeckoScrollbars
2486 hideMacGeckoScrollbars: function () {
2488 Dom.removeClass(this.element, "show-scrollbars");
2489 Dom.addClass(this.element, "hide-scrollbars");
2494 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2495 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2496 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2497 * @method showMacGeckoScrollbars
2499 showMacGeckoScrollbars: function () {
2501 Dom.removeClass(this.element, "hide-scrollbars");
2502 Dom.addClass(this.element, "show-scrollbars");
2506 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2509 * The default event handler fired when the "visible" property is
2510 * changed. This method is responsible for firing showEvent
2512 * @method configVisible
2513 * @param {String} type The CustomEvent type (usually the property name)
2514 * @param {Object[]} args The CustomEvent arguments. For configuration
2515 * handlers, args[0] will equal the newly applied value for the property.
2516 * @param {Object} obj The scope object. For configuration handlers,
2517 * this will usually equal the owner.
2519 configVisible: function (type, args, obj) {
2521 var visible = args[0],
2522 currentVis = Dom.getStyle(this.element, "visibility"),
2523 effect = this.cfg.getProperty("effect"),
2524 effectInstances = [],
2525 isMacGecko = (this.platform == "mac" && YAHOO.env.ua.gecko),
2526 alreadySubscribed = Config.alreadySubscribed,
2527 eff, ei, e, i, j, k, h,
2532 if (currentVis == "inherit") {
2534 e = this.element.parentNode;
2536 while (e.nodeType != 9 && e.nodeType != 11) {
2538 currentVis = Dom.getStyle(e, "visibility");
2540 if (currentVis != "inherit") {
2550 if (currentVis == "inherit") {
2552 currentVis = "visible";
2561 if (effect instanceof Array) {
2563 nEffects = effect.length;
2565 for (i = 0; i < nEffects; i++) {
2569 effectInstances[effectInstances.length] =
2570 eff.effect(this, eff.duration);
2576 effectInstances[effectInstances.length] =
2577 effect.effect(this, effect.duration);
2584 if (visible) { // Show
2588 this.showMacGeckoScrollbars();
2593 if (effect) { // Animate in
2596 if (visible) { // Animate in if not showing
2599 if (currentVis != "visible" || currentVis === "") {
2601 this.beforeShowEvent.fire();
2603 nEffectInstances = effectInstances.length;
2605 for (j = 0; j < nEffectInstances; j++) {
2607 ei = effectInstances[j];
2609 if (j === 0 && !alreadySubscribed(
2610 ei.animateInCompleteEvent,
2611 this.showEvent.fire, this.showEvent)) {
2614 Delegate showEvent until end
2615 of animateInComplete
2618 ei.animateInCompleteEvent.subscribe(
2619 this.showEvent.fire, this.showEvent, true);
2633 if (currentVis != "visible" || currentVis === "") {
2635 this.beforeShowEvent.fire();
2637 Dom.setStyle(this.element, "visibility", "visible");
2639 this.cfg.refireEvent("iframe");
2640 this.showEvent.fire();
2650 this.hideMacGeckoScrollbars();
2654 if (effect) { // Animate out if showing
2656 if (currentVis == "visible") {
2658 this.beforeHideEvent.fire();
2660 nEffectInstances = effectInstances.length;
2662 for (k = 0; k < nEffectInstances; k++) {
2664 h = effectInstances[k];
2666 if (k === 0 && !alreadySubscribed(
2667 h.animateOutCompleteEvent, this.hideEvent.fire,
2671 Delegate hideEvent until end
2672 of animateOutComplete
2675 h.animateOutCompleteEvent.subscribe(
2676 this.hideEvent.fire, this.hideEvent, true);
2684 } else if (currentVis === "") {
2686 Dom.setStyle(this.element, "visibility", "hidden");
2690 } else { // Simple hide
2692 if (currentVis == "visible" || currentVis === "") {
2694 this.beforeHideEvent.fire();
2696 Dom.setStyle(this.element, "visibility", "hidden");
2698 this.hideEvent.fire();
2709 * Center event handler used for centering on scroll/resize, but only if
2710 * the Overlay is visible
2711 * @method doCenterOnDOMEvent
2713 doCenterOnDOMEvent: function () {
2715 if (this.cfg.getProperty("visible")) {
2724 * The default event handler fired when the "fixedcenter" property
2726 * @method configFixedCenter
2727 * @param {String} type The CustomEvent type (usually the property name)
2728 * @param {Object[]} args The CustomEvent arguments. For configuration
2729 * handlers, args[0] will equal the newly applied value for the property.
2730 * @param {Object} obj The scope object. For configuration handlers,
2731 * this will usually equal the owner.
2733 configFixedCenter: function (type, args, obj) {
2736 alreadySubscribed = Config.alreadySubscribed,
2737 windowResizeEvent = Overlay.windowResizeEvent,
2738 windowScrollEvent = Overlay.windowScrollEvent;
2744 if (!alreadySubscribed(this.beforeShowEvent,
2745 this.center, this)) {
2747 this.beforeShowEvent.subscribe(this.center);
2751 if (!alreadySubscribed(windowResizeEvent,
2752 this.doCenterOnDOMEvent, this)) {
2754 windowResizeEvent.subscribe(this.doCenterOnDOMEvent,
2759 if (!alreadySubscribed(windowScrollEvent,
2760 this.doCenterOnDOMEvent, this)) {
2762 windowScrollEvent.subscribe(this.doCenterOnDOMEvent,
2769 this.beforeShowEvent.unsubscribe(this.center);
2771 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2772 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2779 * The default event handler fired when the "height" property is changed.
2780 * @method configHeight
2781 * @param {String} type The CustomEvent type (usually the property name)
2782 * @param {Object[]} args The CustomEvent arguments. For configuration
2783 * handlers, args[0] will equal the newly applied value for the property.
2784 * @param {Object} obj The scope object. For configuration handlers,
2785 * this will usually equal the owner.
2787 configHeight: function (type, args, obj) {
2789 var height = args[0],
2792 Dom.setStyle(el, "height", height);
2793 this.cfg.refireEvent("iframe");
2798 * The default event handler fired when the "width" property is changed.
2799 * @method configWidth
2800 * @param {String} type The CustomEvent type (usually the property name)
2801 * @param {Object[]} args The CustomEvent arguments. For configuration
2802 * handlers, args[0] will equal the newly applied value for the property.
2803 * @param {Object} obj The scope object. For configuration handlers,
2804 * this will usually equal the owner.
2806 configWidth: function (type, args, obj) {
2808 var width = args[0],
2811 Dom.setStyle(el, "width", width);
2812 this.cfg.refireEvent("iframe");
2817 * The default event handler fired when the "zIndex" property is changed.
2818 * @method configzIndex
2819 * @param {String} type The CustomEvent type (usually the property name)
2820 * @param {Object[]} args The CustomEvent arguments. For configuration
2821 * handlers, args[0] will equal the newly applied value for the property.
2822 * @param {Object} obj The scope object. For configuration handlers,
2823 * this will usually equal the owner.
2825 configzIndex: function (type, args, obj) {
2827 var zIndex = args[0],
2832 zIndex = Dom.getStyle(el, "zIndex");
2834 if (! zIndex || isNaN(zIndex)) {
2850 Dom.setStyle(this.iframe, "zIndex", (zIndex - 1));
2853 Dom.setStyle(el, "zIndex", zIndex);
2854 this.cfg.setProperty("zIndex", zIndex, true);
2859 * The default event handler fired when the "xy" property is changed.
2861 * @param {String} type The CustomEvent type (usually the property name)
2862 * @param {Object[]} args The CustomEvent arguments. For configuration
2863 * handlers, args[0] will equal the newly applied value for the property.
2864 * @param {Object} obj The scope object. For configuration handlers,
2865 * this will usually equal the owner.
2867 configXY: function (type, args, obj) {
2873 this.cfg.setProperty("x", x);
2874 this.cfg.setProperty("y", y);
2876 this.beforeMoveEvent.fire([x, y]);
2878 x = this.cfg.getProperty("x");
2879 y = this.cfg.getProperty("y");
2881 YAHOO.log(("xy: " + [x, y]), "iframe");
2883 this.cfg.refireEvent("iframe");
2884 this.moveEvent.fire([x, y]);
2889 * The default event handler fired when the "x" property is changed.
2891 * @param {String} type The CustomEvent type (usually the property name)
2892 * @param {Object[]} args The CustomEvent arguments. For configuration
2893 * handlers, args[0] will equal the newly applied value for the property.
2894 * @param {Object} obj The scope object. For configuration handlers,
2895 * this will usually equal the owner.
2897 configX: function (type, args, obj) {
2900 y = this.cfg.getProperty("y");
2902 this.cfg.setProperty("x", x, true);
2903 this.cfg.setProperty("y", y, true);
2905 this.beforeMoveEvent.fire([x, y]);
2907 x = this.cfg.getProperty("x");
2908 y = this.cfg.getProperty("y");
2910 Dom.setX(this.element, x, true);
2912 this.cfg.setProperty("xy", [x, y], true);
2914 this.cfg.refireEvent("iframe");
2915 this.moveEvent.fire([x, y]);
2920 * The default event handler fired when the "y" property is changed.
2922 * @param {String} type The CustomEvent type (usually the property name)
2923 * @param {Object[]} args The CustomEvent arguments. For configuration
2924 * handlers, args[0] will equal the newly applied value for the property.
2925 * @param {Object} obj The scope object. For configuration handlers,
2926 * this will usually equal the owner.
2928 configY: function (type, args, obj) {
2930 var x = this.cfg.getProperty("x"),
2933 this.cfg.setProperty("x", x, true);
2934 this.cfg.setProperty("y", y, true);
2936 this.beforeMoveEvent.fire([x, y]);
2938 x = this.cfg.getProperty("x");
2939 y = this.cfg.getProperty("y");
2941 Dom.setY(this.element, y, true);
2943 this.cfg.setProperty("xy", [x, y], true);
2945 this.cfg.refireEvent("iframe");
2946 this.moveEvent.fire([x, y]);
2951 * Shows the iframe shim, if it has been enabled.
2952 * @method showIframe
2954 showIframe: function () {
2956 var oIFrame = this.iframe,
2961 oParentNode = this.element.parentNode;
2963 if (oParentNode != oIFrame.parentNode) {
2965 oParentNode.appendChild(oIFrame);
2969 oIFrame.style.display = "block";
2976 * Hides the iframe shim, if it has been enabled.
2977 * @method hideIframe
2979 hideIframe: function () {
2983 this.iframe.style.display = "none";
2990 * Syncronizes the size and position of iframe shim to that of its
2991 * corresponding Overlay instance.
2992 * @method syncIframe
2994 syncIframe: function () {
2996 var oIFrame = this.iframe,
2997 oElement = this.element,
2998 nOffset = Overlay.IFRAME_OFFSET,
2999 nDimensionOffset = (nOffset * 2),
3007 oIFrame.style.width =
3008 (oElement.offsetWidth + nDimensionOffset + "px");
3010 oIFrame.style.height =
3011 (oElement.offsetHeight + nDimensionOffset + "px");
3014 // Position <iframe>
3016 aXY = this.cfg.getProperty("xy");
3018 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3020 this.syncPosition();
3022 aXY = this.cfg.getProperty("xy");
3026 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3034 * The default event handler fired when the "iframe" property is changed.
3035 * @method configIframe
3036 * @param {String} type The CustomEvent type (usually the property name)
3037 * @param {Object[]} args The CustomEvent arguments. For configuration
3038 * handlers, args[0] will equal the newly applied value for the property.
3039 * @param {Object} obj The scope object. For configuration handlers,
3040 * this will usually equal the owner.
3042 configIframe: function (type, args, obj) {
3044 var bIFrame = args[0];
3046 function createIFrame() {
3048 var oIFrame = this.iframe,
3049 oElement = this.element,
3056 if (!m_oIFrameTemplate) {
3058 m_oIFrameTemplate = document.createElement("iframe");
3060 if (this.isSecure) {
3062 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3067 Set the opacity of the <iframe> to 0 so that it
3068 doesn't modify the opacity of any transparent
3069 elements that may be on top of it (like a shadow).
3072 if (YAHOO.env.ua.ie) {
3074 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3077 Need to set the "frameBorder" property to 0
3078 supress the default <iframe> border in IE.
3079 Setting the CSS "border" property alone
3083 m_oIFrameTemplate.frameBorder = 0;
3088 m_oIFrameTemplate.style.opacity = "0";
3092 m_oIFrameTemplate.style.position = "absolute";
3093 m_oIFrameTemplate.style.border = "none";
3094 m_oIFrameTemplate.style.margin = "0";
3095 m_oIFrameTemplate.style.padding = "0";
3096 m_oIFrameTemplate.style.display = "none";
3100 oIFrame = m_oIFrameTemplate.cloneNode(false);
3102 oParent = oElement.parentNode;
3106 oParent.appendChild(oIFrame);
3110 document.body.appendChild(oIFrame);
3114 this.iframe = oIFrame;
3120 Show the <iframe> before positioning it since the "setXY"
3121 method of DOM requires the element be in the document
3129 Syncronize the size and position of the <iframe> to that
3136 // Add event listeners to update the <iframe> when necessary
3138 if (!this._hasIframeEventListeners) {
3140 this.showEvent.subscribe(this.showIframe);
3141 this.hideEvent.subscribe(this.hideIframe);
3142 this.changeContentEvent.subscribe(this.syncIframe);
3144 this._hasIframeEventListeners = true;
3151 function onBeforeShow() {
3153 createIFrame.call(this);
3155 this.beforeShowEvent.unsubscribe(onBeforeShow);
3157 this._iframeDeferred = false;
3162 if (bIFrame) { // <iframe> shim is enabled
3164 if (this.cfg.getProperty("visible")) {
3166 createIFrame.call(this);
3171 if (!this._iframeDeferred) {
3173 this.beforeShowEvent.subscribe(onBeforeShow);
3175 this._iframeDeferred = true;
3181 } else { // <iframe> shim is disabled
3185 if (this._hasIframeEventListeners) {
3187 this.showEvent.unsubscribe(this.showIframe);
3188 this.hideEvent.unsubscribe(this.hideIframe);
3189 this.changeContentEvent.unsubscribe(this.syncIframe);
3191 this._hasIframeEventListeners = false;
3201 * The default event handler fired when the "constraintoviewport"
3202 * property is changed.
3203 * @method configConstrainToViewport
3204 * @param {String} type The CustomEvent type (usually the property name)
3205 * @param {Object[]} args The CustomEvent arguments. For configuration
3206 * handlers, args[0] will equal the newly applied value for
3208 * @param {Object} obj The scope object. For configuration handlers,
3209 * this will usually equal the owner.
3211 configConstrainToViewport: function (type, args, obj) {
3217 if (! Config.alreadySubscribed(this.beforeMoveEvent,
3218 this.enforceConstraints, this)) {
3220 this.beforeMoveEvent.subscribe(this.enforceConstraints,
3227 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3234 * The default event handler fired when the "context" property
3236 * @method configContext
3237 * @param {String} type The CustomEvent type (usually the property name)
3238 * @param {Object[]} args The CustomEvent arguments. For configuration
3239 * handlers, args[0] will equal the newly applied value for the property.
3240 * @param {Object} obj The scope object. For configuration handlers,
3241 * this will usually equal the owner.
3243 configContext: function (type, args, obj) {
3245 var contextArgs = args[0],
3247 elementMagnetCorner,
3248 contextMagnetCorner;
3252 contextEl = contextArgs[0];
3253 elementMagnetCorner = contextArgs[1];
3254 contextMagnetCorner = contextArgs[2];
3258 if (typeof contextEl == "string") {
3260 this.cfg.setProperty("context",
3261 [document.getElementById(contextEl),
3262 elementMagnetCorner, contextMagnetCorner],
3267 if (elementMagnetCorner && contextMagnetCorner) {
3269 this.align(elementMagnetCorner, contextMagnetCorner);
3280 // END BUILT-IN PROPERTY EVENT HANDLERS //
3283 * Aligns the Overlay to its context element using the specified corner
3284 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3287 * @param {String} elementAlign The String representing the corner of
3288 * the Overlay that should be aligned to the context element
3289 * @param {String} contextAlign The corner of the context element
3290 * that the elementAlign corner should stick to.
3292 align: function (elementAlign, contextAlign) {
3294 var contextArgs = this.cfg.getProperty("context"),
3301 function doAlign(v, h) {
3303 switch (elementAlign) {
3305 case Overlay.TOP_LEFT:
3311 case Overlay.TOP_RIGHT:
3313 me.moveTo((h - element.offsetWidth), v);
3317 case Overlay.BOTTOM_LEFT:
3319 me.moveTo(h, (v - element.offsetHeight));
3323 case Overlay.BOTTOM_RIGHT:
3325 me.moveTo((h - element.offsetWidth),
3326 (v - element.offsetHeight));
3337 context = contextArgs[0];
3338 element = this.element;
3341 if (! elementAlign) {
3343 elementAlign = contextArgs[1];
3347 if (! contextAlign) {
3349 contextAlign = contextArgs[2];
3353 if (element && context) {
3355 contextRegion = Dom.getRegion(context);
3357 switch (contextAlign) {
3359 case Overlay.TOP_LEFT:
3361 doAlign(contextRegion.top, contextRegion.left);
3365 case Overlay.TOP_RIGHT:
3367 doAlign(contextRegion.top, contextRegion.right);
3371 case Overlay.BOTTOM_LEFT:
3373 doAlign(contextRegion.bottom, contextRegion.left);
3377 case Overlay.BOTTOM_RIGHT:
3379 doAlign(contextRegion.bottom, contextRegion.right);
3392 * The default event handler executed when the moveEvent is fired, if the
3393 * "constraintoviewport" is set to true.
3394 * @method enforceConstraints
3395 * @param {String} type The CustomEvent type (usually the property name)
3396 * @param {Object[]} args The CustomEvent arguments. For configuration
3397 * handlers, args[0] will equal the newly applied value for the property.
3398 * @param {Object} obj The scope object. For configuration handlers,
3399 * this will usually equal the owner.
3401 enforceConstraints: function (type, args, obj) {
3406 offsetHeight = this.element.offsetHeight,
3407 offsetWidth = this.element.offsetWidth,
3408 viewPortWidth = Dom.getViewportWidth(),
3409 viewPortHeight = Dom.getViewportHeight(),
3410 scrollX = Dom.getDocumentScrollLeft(),
3411 scrollY = Dom.getDocumentScrollTop(),
3412 topConstraint = scrollY + 10,
3413 leftConstraint = scrollX + 10,
3414 bottomConstraint = scrollY + viewPortHeight - offsetHeight - 10,
3415 rightConstraint = scrollX + viewPortWidth - offsetWidth - 10;
3418 if (x < leftConstraint) {
3422 } else if (x > rightConstraint) {
3424 x = rightConstraint;
3428 if (y < topConstraint) {
3432 } else if (y > bottomConstraint) {
3434 y = bottomConstraint;
3438 this.cfg.setProperty("x", x, true);
3439 this.cfg.setProperty("y", y, true);
3440 this.cfg.setProperty("xy", [x, y], true);
3445 * Centers the container in the viewport.
3448 center: function () {
3450 var scrollX = Dom.getDocumentScrollLeft(),
3451 scrollY = Dom.getDocumentScrollTop(),
3453 viewPortWidth = Dom.getClientWidth(),
3454 viewPortHeight = Dom.getClientHeight(),
3455 elementWidth = this.element.offsetWidth,
3456 elementHeight = this.element.offsetHeight,
3457 x = (viewPortWidth / 2) - (elementWidth / 2) + scrollX,
3458 y = (viewPortHeight / 2) - (elementHeight / 2) + scrollY;
3460 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3462 this.cfg.refireEvent("iframe");
3467 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3468 * Panel's position in the DOM. This is primarily used to update
3469 * position information during drag & drop.
3470 * @method syncPosition
3472 syncPosition: function () {
3474 var pos = Dom.getXY(this.element);
3476 this.cfg.setProperty("x", pos[0], true);
3477 this.cfg.setProperty("y", pos[1], true);
3478 this.cfg.setProperty("xy", pos, true);
3483 * Event handler fired when the resize monitor element is resized.
3484 * @method onDomResize
3485 * @param {DOMEvent} e The resize DOM event
3486 * @param {Object} obj The scope object
3488 onDomResize: function (e, obj) {
3492 Overlay.superclass.onDomResize.call(this, e, obj);
3494 setTimeout(function () {
3496 me.cfg.refireEvent("iframe");
3497 me.cfg.refireEvent("context");
3503 * Places the Overlay on top of all other instances of
3504 * YAHOO.widget.Overlay.
3505 * @method bringToTop
3507 bringToTop: function() {
3510 oElement = this.element;
3512 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
3514 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
3516 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
3518 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ?
3519 0 : parseInt(sZIndex1, 10),
3521 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ?
3522 0 : parseInt(sZIndex2, 10);
3524 if (nZIndex1 > nZIndex2) {
3528 } else if (nZIndex1 < nZIndex2) {
3540 function isOverlayElement(p_oElement) {
3542 var oOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
3543 Panel = YAHOO.widget.Panel;
3545 if (oOverlay && !Dom.isAncestor(oElement, oOverlay)) {
3547 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
3549 aOverlays[aOverlays.length] = p_oElement.parentNode;
3554 aOverlays[aOverlays.length] = p_oElement;
3562 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
3564 aOverlays.sort(compareZIndexDesc);
3566 var oTopOverlay = aOverlays[0],
3571 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
3573 if (!isNaN(nTopZIndex) && oTopOverlay != oElement) {
3575 this.cfg.setProperty("zindex",
3576 (parseInt(nTopZIndex, 10) + 2));
3585 * Removes the Overlay element from the DOM and sets all child
3589 destroy: function () {
3593 this.iframe.parentNode.removeChild(this.iframe);
3599 Overlay.windowResizeEvent.unsubscribe(
3600 this.doCenterOnDOMEvent, this);
3602 Overlay.windowScrollEvent.unsubscribe(
3603 this.doCenterOnDOMEvent, this);
3605 Overlay.superclass.destroy.call(this);
3609 * Returns a String representation of the object.
3611 * @return {String} The string representation of the Overlay.
3613 toString: function () {
3615 return "Overlay " + this.id;
3625 * OverlayManager is used for maintaining the focus status of
3626 * multiple Overlays.
3627 * @namespace YAHOO.widget
3628 * @namespace YAHOO.widget
3629 * @class OverlayManager
3631 * @param {Array} overlays Optional. A collection of Overlays to register
3633 * @param {Object} userConfig The object literal representing the user
3634 * configuration of the OverlayManager
3636 YAHOO.widget.OverlayManager = function (userConfig) {
3638 this.init(userConfig);
3643 var Overlay = YAHOO.widget.Overlay,
3644 Event = YAHOO.util.Event,
3645 Dom = YAHOO.util.Dom,
3646 Config = YAHOO.util.Config,
3647 CustomEvent = YAHOO.util.CustomEvent,
3648 OverlayManager = YAHOO.widget.OverlayManager;
3652 * The CSS class representing a focused Overlay
3653 * @property OverlayManager.CSS_FOCUSED
3658 OverlayManager.CSS_FOCUSED = "focused";
3660 OverlayManager.prototype = {
3663 * The class's constructor function
3664 * @property contructor
3667 constructor: OverlayManager,
3670 * The array of Overlays that are currently registered
3671 * @property overlays
3672 * @type YAHOO.widget.Overlay[]
3677 * Initializes the default configuration of the OverlayManager
3678 * @method initDefaultConfig
3680 initDefaultConfig: function () {
3683 * The collection of registered Overlays in use by
3684 * the OverlayManager
3686 * @type YAHOO.widget.Overlay[]
3689 this.cfg.addProperty("overlays", { suppressEvent: true } );
3692 * The default DOM event that should be used to focus an Overlay
3693 * @config focusevent
3695 * @default "mousedown"
3697 this.cfg.addProperty("focusevent", { value: "mousedown" } );
3702 * Initializes the OverlayManager
3704 * @param {Overlay[]} overlays Optional. A collection of Overlays to
3705 * register with the manager.
3706 * @param {Object} userConfig The object literal representing the user
3707 * configuration of the OverlayManager
3709 init: function (userConfig) {
3712 * The OverlayManager's Config object used for monitoring
3713 * configuration properties.
3717 this.cfg = new Config(this);
3719 this.initDefaultConfig();
3722 this.cfg.applyConfig(userConfig, true);
3724 this.cfg.fireQueue();
3727 * The currently activated Overlay
3728 * @property activeOverlay
3730 * @type YAHOO.widget.Overlay
3732 var activeOverlay = null;
3735 * Returns the currently focused Overlay
3737 * @return {Overlay} The currently focused Overlay
3739 this.getActive = function () {
3740 return activeOverlay;
3744 * Focuses the specified Overlay
3746 * @param {Overlay} overlay The Overlay to focus
3747 * @param {String} overlay The id of the Overlay to focus
3749 this.focus = function (overlay) {
3751 var o = this.find(overlay);
3755 if (activeOverlay != o) {
3757 if (activeOverlay) {
3759 activeOverlay.blur();
3767 Dom.addClass(activeOverlay.element,
3768 OverlayManager.CSS_FOCUSED);
3770 o.focusEvent.fire();
3779 * Removes the specified Overlay from the manager
3781 * @param {Overlay} overlay The Overlay to remove
3782 * @param {String} overlay The id of the Overlay to remove
3784 this.remove = function (overlay) {
3786 var o = this.find(overlay),
3791 if (activeOverlay == o) {
3793 activeOverlay = null;
3797 originalZ = Dom.getStyle(o.element, "zIndex");
3799 o.cfg.setProperty("zIndex", -1000, true);
3801 this.overlays.sort(this.compareZIndexDesc);
3804 this.overlays.slice(0, (this.overlays.length - 1));
3806 o.hideEvent.unsubscribe(o.blur);
3807 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
3811 Event.removeListener(o.element,
3812 this.cfg.getProperty("focusevent"),
3813 this._onOverlayElementFocus);
3817 o.cfg.setProperty("zIndex", originalZ, true);
3818 o.cfg.setProperty("manager", null);
3820 o.focusEvent.unsubscribeAll();
3821 o.blurEvent.unsubscribeAll();
3823 o.focusEvent = null;
3833 * Removes focus from all registered Overlays in the manager
3836 this.blurAll = function () {
3838 var nOverlays = this.overlays.length,
3841 if (nOverlays > 0) {
3847 this.overlays[i].blur();
3857 this._onOverlayBlur = function (p_sType, p_aArgs) {
3859 activeOverlay = null;
3864 var overlays = this.cfg.getProperty("overlays");
3866 if (! this.overlays) {
3871 this.register(overlays);
3872 this.overlays.sort(this.compareZIndexDesc);
3878 * @method _onOverlayElementFocus
3879 * @description Event handler for the DOM event that is used to focus
3880 * the Overlay instance as specified by the "focusevent"
3881 * configuration property.
3883 * @param {Event} p_oEvent Object representing the DOM event
3884 * object passed back by the event utility (Event).
3886 _onOverlayElementFocus: function (p_oEvent) {
3888 var oTarget = Event.getTarget(p_oEvent),
3889 oClose = this.close;
3892 if (oClose && (oTarget == oClose ||
3893 Dom.isAncestor(oClose, oTarget))) {
3908 * @method _onOverlayDestroy
3909 * @description "destroy" event handler for the Overlay.
3911 * @param {String} p_sType String representing the name of the event
3913 * @param {Array} p_aArgs Array of arguments sent when the event
3915 * @param {Overlay} p_oOverlay Object representing the menu that
3918 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
3920 this.remove(p_oOverlay);
3925 * Registers an Overlay or an array of Overlays with the manager. Upon
3926 * registration, the Overlay receives functions for focus and blur,
3927 * along with CustomEvents for each.
3929 * @param {Overlay} overlay An Overlay to register with the manager.
3930 * @param {Overlay[]} overlay An array of Overlays to register with
3932 * @return {Boolean} True if any Overlays are registered.
3934 register: function (overlay) {
3942 if (overlay instanceof Overlay) {
3944 overlay.cfg.addProperty("manager", { value: this } );
3946 overlay.focusEvent = overlay.createEvent("focus");
3947 overlay.focusEvent.signature = CustomEvent.LIST;
3949 overlay.blurEvent = overlay.createEvent("blur");
3950 overlay.blurEvent.signature = CustomEvent.LIST;
3952 overlay.focus = function () {
3956 overlay.blur = function () {
3958 if (mgr.getActive() == this) {
3960 Dom.removeClass(this.element,
3961 OverlayManager.CSS_FOCUSED);
3963 this.blurEvent.fire();
3969 overlay.blurEvent.subscribe(mgr._onOverlayBlur);
3971 overlay.hideEvent.subscribe(overlay.blur);
3973 overlay.destroyEvent.subscribe(this._onOverlayDestroy,
3976 Event.on(overlay.element, this.cfg.getProperty("focusevent"),
3977 this._onOverlayElementFocus, null, overlay);
3979 zIndex = Dom.getStyle(overlay.element, "zIndex");
3981 if (!isNaN(zIndex)) {
3983 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
3987 overlay.cfg.setProperty("zIndex", 0);
3992 this.overlays.push(overlay);
3994 this.bringToTop(overlay);
3998 } else if (overlay instanceof Array) {
4001 nOverlays = overlay.length;
4003 for (i = 0; i < nOverlays; i++) {
4005 if (this.register(overlay[i])) {
4027 * Places the specified Overlay instance on top of all other
4028 * Overlay instances.
4029 * @method bringToTop
4030 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4032 * @param {String} p_oOverlay String representing the id of an
4035 bringToTop: function (p_oOverlay) {
4037 var oOverlay = this.find(p_oOverlay),
4044 aOverlays = this.overlays;
4046 aOverlays.sort(this.compareZIndexDesc);
4048 oTopOverlay = aOverlays[0];
4052 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4054 if (!isNaN(nTopZIndex) && oTopOverlay != oOverlay) {
4056 oOverlay.cfg.setProperty("zIndex",
4057 (parseInt(nTopZIndex, 10) + 2));
4061 aOverlays.sort(this.compareZIndexDesc);
4070 * Attempts to locate an Overlay by instance or ID.
4072 * @param {Overlay} overlay An Overlay to locate within the manager
4073 * @param {String} overlay An Overlay id to locate within the manager
4074 * @return {Overlay} The requested Overlay, if found, or null if it
4075 * cannot be located.
4077 find: function (overlay) {
4079 var aOverlays = this.overlays,
4080 nOverlays = aOverlays.length,
4083 if (nOverlays > 0) {
4087 if (overlay instanceof Overlay) {
4091 if (aOverlays[i] == overlay) {
4093 return aOverlays[i];
4100 } else if (typeof overlay == "string") {
4104 if (aOverlays[i].id == overlay) {
4106 return aOverlays[i];
4122 * Used for sorting the manager's Overlays by z-index.
4123 * @method compareZIndexDesc
4125 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4126 * fall in the stacking order.
4128 compareZIndexDesc: function (o1, o2) {
4130 var zIndex1 = o1.cfg.getProperty("zIndex"),
4131 zIndex2 = o2.cfg.getProperty("zIndex");
4133 if (zIndex1 > zIndex2) {
4135 } else if (zIndex1 < zIndex2) {
4143 * Shows all Overlays in the manager.
4146 showAll: function () {
4148 var aOverlays = this.overlays,
4149 nOverlays = aOverlays.length,
4152 if (nOverlays > 0) {
4158 aOverlays[i].show();
4168 * Hides all Overlays in the manager.
4171 hideAll: function () {
4173 var aOverlays = this.overlays,
4174 nOverlays = aOverlays.length,
4177 if (nOverlays > 0) {
4183 aOverlays[i].hide();
4193 * Returns a string representation of the object.
4195 * @return {String} The string representation of the OverlayManager
4197 toString: function () {
4198 return "OverlayManager";
4207 * ContainerEffect encapsulates animation transitions that are executed when
4208 * an Overlay is shown or hidden.
4209 * @namespace YAHOO.widget
4210 * @class ContainerEffect
4212 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
4213 * should be associated with
4214 * @param {Object} attrIn The object literal representing the animation
4215 * arguments to be used for the animate-in transition. The arguments for
4216 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4217 * duration(Number), and method(i.e. Easing.easeIn).
4218 * @param {Object} attrOut The object literal representing the animation
4219 * arguments to be used for the animate-out transition. The arguments for
4220 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4221 * duration(Number), and method(i.e. Easing.easeIn).
4222 * @param {HTMLElement} targetElement Optional. The target element that
4223 * should be animated during the transition. Defaults to overlay.element.
4224 * @param {class} Optional. The animation class to instantiate. Defaults to
4225 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4227 YAHOO.widget.ContainerEffect =
4229 function (overlay, attrIn, attrOut, targetElement, animClass) {
4232 animClass = YAHOO.util.Anim;
4236 * The overlay to animate
4238 * @type YAHOO.widget.Overlay
4240 this.overlay = overlay;
4243 * The animation attributes to use when transitioning into view
4247 this.attrIn = attrIn;
4250 * The animation attributes to use when transitioning out of view
4254 this.attrOut = attrOut;
4257 * The target element to be animated
4258 * @property targetElement
4261 this.targetElement = targetElement || overlay.element;
4264 * The animation class to use for animating the overlay
4265 * @property animClass
4268 this.animClass = animClass;
4273 var Dom = YAHOO.util.Dom,
4274 CustomEvent = YAHOO.util.CustomEvent,
4275 Easing = YAHOO.util.Easing,
4276 ContainerEffect = YAHOO.widget.ContainerEffect;
4280 * A pre-configured ContainerEffect instance that can be used for fading
4281 * an overlay in and out.
4284 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4285 * @param {Number} dur The duration of the animation
4286 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4288 ContainerEffect.FADE = function (overlay, dur) {
4290 var fade = new ContainerEffect(overlay,
4292 { attributes: { opacity: { from: 0, to: 1 } },
4294 method: Easing.easeIn },
4296 { attributes: { opacity: { to: 0 } },
4298 method: Easing.easeOut },
4303 fade.handleStartAnimateIn = function (type,args,obj) {
4304 Dom.addClass(obj.overlay.element, "hide-select");
4306 if (! obj.overlay.underlay) {
4307 obj.overlay.cfg.refireEvent("underlay");
4310 if (obj.overlay.underlay) {
4312 obj.initialUnderlayOpacity =
4313 Dom.getStyle(obj.overlay.underlay, "opacity");
4315 obj.overlay.underlay.style.filter = null;
4319 Dom.setStyle(obj.overlay.element, "visibility", "visible");
4320 Dom.setStyle(obj.overlay.element, "opacity", 0);
4324 fade.handleCompleteAnimateIn = function (type,args,obj) {
4325 Dom.removeClass(obj.overlay.element, "hide-select");
4327 if (obj.overlay.element.style.filter) {
4328 obj.overlay.element.style.filter = null;
4331 if (obj.overlay.underlay) {
4332 Dom.setStyle(obj.overlay.underlay, "opacity",
4333 obj.initialUnderlayOpacity);
4336 obj.overlay.cfg.refireEvent("iframe");
4337 obj.animateInCompleteEvent.fire();
4341 fade.handleStartAnimateOut = function (type, args, obj) {
4342 Dom.addClass(obj.overlay.element, "hide-select");
4344 if (obj.overlay.underlay) {
4345 obj.overlay.underlay.style.filter = null;
4350 fade.handleCompleteAnimateOut = function (type, args, obj) {
4351 Dom.removeClass(obj.overlay.element, "hide-select");
4352 if (obj.overlay.element.style.filter) {
4353 obj.overlay.element.style.filter = null;
4355 Dom.setStyle(obj.overlay.element, "visibility", "hidden");
4356 Dom.setStyle(obj.overlay.element, "opacity", 1);
4358 obj.overlay.cfg.refireEvent("iframe");
4360 obj.animateOutCompleteEvent.fire();
4369 * A pre-configured ContainerEffect instance that can be used for sliding an
4370 * overlay in and out.
4373 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4374 * @param {Number} dur The duration of the animation
4375 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4377 ContainerEffect.SLIDE = function (overlay, dur) {
4379 var x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
4381 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
4383 clientWidth = Dom.getClientWidth(),
4385 offsetWidth = overlay.element.offsetWidth,
4387 slide = new ContainerEffect(overlay,
4389 { attributes: { points: { to: [x, y] } },
4391 method: Easing.easeIn },
4393 { attributes: { points: { to: [(clientWidth + 25), y] } },
4395 method: Easing.easeOut },
4397 overlay.element, YAHOO.util.Motion);
4400 slide.handleStartAnimateIn = function (type,args,obj) {
4401 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
4402 obj.overlay.element.style.top = y + "px";
4405 slide.handleTweenAnimateIn = function (type, args, obj) {
4407 var pos = Dom.getXY(obj.overlay.element),
4411 if (Dom.getStyle(obj.overlay.element, "visibility") ==
4412 "hidden" && currentX < x) {
4414 Dom.setStyle(obj.overlay.element, "visibility", "visible");
4418 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
4419 obj.overlay.cfg.refireEvent("iframe");
4422 slide.handleCompleteAnimateIn = function (type, args, obj) {
4423 obj.overlay.cfg.setProperty("xy", [x, y], true);
4426 obj.overlay.cfg.refireEvent("iframe");
4427 obj.animateInCompleteEvent.fire();
4430 slide.handleStartAnimateOut = function (type, args, obj) {
4432 var vw = Dom.getViewportWidth(),
4433 pos = Dom.getXY(obj.overlay.element),
4435 currentTo = obj.animOut.attributes.points.to;
4437 obj.animOut.attributes.points.to = [(vw + 25), yso];
4441 slide.handleTweenAnimateOut = function (type, args, obj) {
4443 var pos = Dom.getXY(obj.overlay.element),
4447 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
4448 obj.overlay.cfg.refireEvent("iframe");
4451 slide.handleCompleteAnimateOut = function (type, args, obj) {
4452 Dom.setStyle(obj.overlay.element, "visibility", "hidden");
4454 obj.overlay.cfg.setProperty("xy", [x, y]);
4455 obj.animateOutCompleteEvent.fire();
4462 ContainerEffect.prototype = {
4465 * Initializes the animation classes and events.
4470 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
4471 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
4473 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
4474 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
4476 this.animateInCompleteEvent = this.createEvent("animateInComplete");
4477 this.animateInCompleteEvent.signature = CustomEvent.LIST;
4479 this.animateOutCompleteEvent =
4480 this.createEvent("animateOutComplete");
4481 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
4483 this.animIn = new this.animClass(this.targetElement,
4484 this.attrIn.attributes, this.attrIn.duration,
4485 this.attrIn.method);
4487 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
4488 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
4490 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
4493 this.animOut = new this.animClass(this.targetElement,
4494 this.attrOut.attributes, this.attrOut.duration,
4495 this.attrOut.method);
4497 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
4498 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
4499 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
4505 * Triggers the in-animation.
4508 animateIn: function () {
4509 this.beforeAnimateInEvent.fire();
4510 this.animIn.animate();
4514 * Triggers the out-animation.
4515 * @method animateOut
4517 animateOut: function () {
4518 this.beforeAnimateOutEvent.fire();
4519 this.animOut.animate();
4523 * The default onStart handler for the in-animation.
4524 * @method handleStartAnimateIn
4525 * @param {String} type The CustomEvent type
4526 * @param {Object[]} args The CustomEvent arguments
4527 * @param {Object} obj The scope object
4529 handleStartAnimateIn: function (type, args, obj) { },
4532 * The default onTween handler for the in-animation.
4533 * @method handleTweenAnimateIn
4534 * @param {String} type The CustomEvent type
4535 * @param {Object[]} args The CustomEvent arguments
4536 * @param {Object} obj The scope object
4538 handleTweenAnimateIn: function (type, args, obj) { },
4541 * The default onComplete handler for the in-animation.
4542 * @method handleCompleteAnimateIn
4543 * @param {String} type The CustomEvent type
4544 * @param {Object[]} args The CustomEvent arguments
4545 * @param {Object} obj The scope object
4547 handleCompleteAnimateIn: function (type, args, obj) { },
4550 * The default onStart handler for the out-animation.
4551 * @method handleStartAnimateOut
4552 * @param {String} type The CustomEvent type
4553 * @param {Object[]} args The CustomEvent arguments
4554 * @param {Object} obj The scope object
4556 handleStartAnimateOut: function (type, args, obj) { },
4559 * The default onTween handler for the out-animation.
4560 * @method handleTweenAnimateOut
4561 * @param {String} type The CustomEvent type
4562 * @param {Object[]} args The CustomEvent arguments
4563 * @param {Object} obj The scope object
4565 handleTweenAnimateOut: function (type, args, obj) { },
4568 * The default onComplete handler for the out-animation.
4569 * @method handleCompleteAnimateOut
4570 * @param {String} type The CustomEvent type
4571 * @param {Object[]} args The CustomEvent arguments
4572 * @param {Object} obj The scope object
4574 handleCompleteAnimateOut: function (type, args, obj) { },
4577 * Returns a string representation of the object.
4579 * @return {String} The string representation of the ContainerEffect
4581 toString: function () {
4582 var output = "ContainerEffect";
4584 output += " [" + this.overlay.toString() + "]";
4591 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
4594 YAHOO.register("container_core", YAHOO.widget.Module, {version: "2.3.0", build: "442"});