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) {
36 var Lang = YAHOO.lang,
37 CustomEvent = YAHOO.util.CustomEvent,
38 Config = YAHOO.util.Config;
42 * Constant representing the CustomEvent type for the config changed event.
43 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
48 Config.CONFIG_CHANGED_EVENT = "configChanged";
51 * Constant representing the boolean type string
52 * @property YAHOO.util.Config.BOOLEAN_TYPE
57 Config.BOOLEAN_TYPE = "boolean";
62 * Object reference to the owner of this Config Object
69 * Boolean flag that specifies whether a queue is currently
71 * @property queueInProgress
74 queueInProgress: false,
77 * Maintains the local collection of configuration property objects and
78 * their specified values
86 * Maintains the local collection of configuration property objects as
87 * they were initially applied.
88 * This object is used when resetting a property.
89 * @property initialConfig
96 * Maintains the local, normalized CustomEvent queue
97 * @property eventQueue
104 * Custom Event, notifying subscribers when Config properties are set
105 * (setProperty is called without the silent flag
106 * @event configChangedEvent
108 configChangedEvent: null,
111 * Initializes the configuration Object and all of its local members.
113 * @param {Object} owner The owner Object to which this Config
116 init: function (owner) {
120 this.configChangedEvent =
121 this.createEvent(Config.CONFIG_CHANGED_EVENT);
123 this.configChangedEvent.signature = CustomEvent.LIST;
124 this.queueInProgress = false;
126 this.initialConfig = {};
127 this.eventQueue = [];
132 * Validates that the value passed in is a Boolean.
133 * @method checkBoolean
134 * @param {Object} val The value to validate
135 * @return {Boolean} true, if the value is valid
137 checkBoolean: function (val) {
138 return (typeof val == Config.BOOLEAN_TYPE);
142 * Validates that the value passed in is a number.
143 * @method checkNumber
144 * @param {Object} val The value to validate
145 * @return {Boolean} true, if the value is valid
147 checkNumber: function (val) {
148 return (!isNaN(val));
152 * Fires a configuration property event using the specified value.
155 * @param {String} key The configuration property's name
156 * @param {value} Object The value of the correct type for the property
158 fireEvent: function ( key, value ) {
159 var property = this.config[key];
161 if (property && property.event) {
162 property.event.fire(value);
167 * Adds a property to the Config Object's private config hash.
168 * @method addProperty
169 * @param {String} key The configuration property's name
170 * @param {Object} propertyObject The Object containing all of this
171 * property's arguments
173 addProperty: function ( key, propertyObject ) {
174 key = key.toLowerCase();
176 this.config[key] = propertyObject;
178 propertyObject.event = this.createEvent(key, { scope: this.owner });
179 propertyObject.event.signature = CustomEvent.LIST;
182 propertyObject.key = key;
184 if (propertyObject.handler) {
185 propertyObject.event.subscribe(propertyObject.handler,
189 this.setProperty(key, propertyObject.value, true);
191 if (! propertyObject.suppressEvent) {
192 this.queueProperty(key, propertyObject.value);
198 * Returns a key-value configuration map of the values currently set in
201 * @return {Object} The current config, represented in a key-value map
203 getConfig: function () {
209 for (prop in this.config) {
210 property = this.config[prop];
211 if (property && property.event) {
212 cfg[prop] = property.value;
220 * Returns the value of specified property.
221 * @method getProperty
222 * @param {String} key The name of the property
223 * @return {Object} The value of the specified property
225 getProperty: function (key) {
226 var property = this.config[key.toLowerCase()];
227 if (property && property.event) {
228 return property.value;
235 * Resets the specified property's value to its initial value.
236 * @method resetProperty
237 * @param {String} key The name of the property
238 * @return {Boolean} True is the property was reset, false if not
240 resetProperty: function (key) {
242 key = key.toLowerCase();
244 var property = this.config[key];
246 if (property && property.event) {
248 if (this.initialConfig[key] &&
249 !Lang.isUndefined(this.initialConfig[key])) {
251 this.setProperty(key, this.initialConfig[key]);
265 * Sets the value of a property. If the silent property is passed as
266 * true, the property's event will not be fired.
267 * @method setProperty
268 * @param {String} key The name of the property
269 * @param {String} value The value to set the property to
270 * @param {Boolean} silent Whether the value should be set silently,
271 * without firing the property event.
272 * @return {Boolean} True, if the set was successful, false if it failed.
274 setProperty: function (key, value, silent) {
278 key = key.toLowerCase();
280 if (this.queueInProgress && ! silent) {
281 // Currently running through a queue...
282 this.queueProperty(key,value);
286 property = this.config[key];
287 if (property && property.event) {
288 if (property.validator && !property.validator(value)) {
291 property.value = value;
293 this.fireEvent(key, value);
294 this.configChangedEvent.fire([key, value]);
305 * Sets the value of a property and queues its event to execute. If the
306 * event is already scheduled to execute, it is
307 * moved from its current position to the end of the queue.
308 * @method queueProperty
309 * @param {String} key The name of the property
310 * @param {String} value The value to set the property to
311 * @return {Boolean} true, if the set was successful, false if
314 queueProperty: function (key, value) {
316 key = key.toLowerCase();
318 var property = this.config[key],
319 foundDuplicate = false,
334 if (property && property.event) {
336 if (!Lang.isUndefined(value) && property.validator &&
337 !property.validator(value)) { // validator
341 if (!Lang.isUndefined(value)) {
342 property.value = value;
344 value = property.value;
347 foundDuplicate = false;
348 iLen = this.eventQueue.length;
350 for (i = 0; i < iLen; i++) {
351 queueItem = this.eventQueue[i];
354 queueItemKey = queueItem[0];
355 queueItemValue = queueItem[1];
357 if (queueItemKey == key) {
360 found a dupe... push to end of queue, null
361 current item, and break
364 this.eventQueue[i] = null;
366 this.eventQueue.push(
367 [key, (!Lang.isUndefined(value) ?
368 value : queueItemValue)]);
370 foundDuplicate = true;
376 // this is a refire, or a new property in the queue
378 if (! foundDuplicate && !Lang.isUndefined(value)) {
379 this.eventQueue.push([key, value]);
383 if (property.supercedes) {
385 sLen = property.supercedes.length;
387 for (s = 0; s < sLen; s++) {
389 supercedesCheck = property.supercedes[s];
390 qLen = this.eventQueue.length;
392 for (q = 0; q < qLen; q++) {
393 queueItemCheck = this.eventQueue[q];
395 if (queueItemCheck) {
396 queueItemCheckKey = queueItemCheck[0];
397 queueItemCheckValue = queueItemCheck[1];
399 if (queueItemCheckKey ==
400 supercedesCheck.toLowerCase() ) {
402 this.eventQueue.push([queueItemCheckKey,
403 queueItemCheckValue]);
405 this.eventQueue[q] = null;
422 * Fires the event for a property using the property's current value.
423 * @method refireEvent
424 * @param {String} key The name of the property
426 refireEvent: function (key) {
428 key = key.toLowerCase();
430 var property = this.config[key];
432 if (property && property.event &&
434 !Lang.isUndefined(property.value)) {
436 if (this.queueInProgress) {
438 this.queueProperty(key);
442 this.fireEvent(key, property.value);
450 * Applies a key-value Object literal to the configuration, replacing
451 * any existing values, and queueing the property events.
452 * Although the values will be set, fireQueue() must be called for their
453 * associated events to execute.
454 * @method applyConfig
455 * @param {Object} userConfig The configuration Object literal
456 * @param {Boolean} init When set to true, the initialConfig will
457 * be set to the userConfig passed in, so that calling a reset will
458 * reset the properties to the passed values.
460 applyConfig: function (userConfig, init) {
470 for (sKey in userConfig) {
472 if (Lang.hasOwnProperty(userConfig, sKey)) {
474 oConfig[sKey.toLowerCase()] = userConfig[sKey];
480 this.initialConfig = oConfig;
484 for (sKey in userConfig) {
486 if (Lang.hasOwnProperty(userConfig, sKey)) {
488 this.queueProperty(sKey, userConfig[sKey]);
497 * Refires the events for all configuration properties using their
501 refresh: function () {
505 for (prop in this.config) {
506 this.refireEvent(prop);
511 * Fires the normalized list of queued property change events
514 fireQueue: function () {
522 this.queueInProgress = true;
523 for (i = 0;i < this.eventQueue.length; i++) {
524 queueItem = this.eventQueue[i];
528 value = queueItem[1];
529 property = this.config[key];
531 property.value = value;
533 this.fireEvent(key,value);
537 this.queueInProgress = false;
538 this.eventQueue = [];
542 * Subscribes an external handler to the change event for any
544 * @method subscribeToConfigEvent
545 * @param {String} key The property name
546 * @param {Function} handler The handler function to use subscribe to
547 * the property's event
548 * @param {Object} obj The Object to use for scoping the event handler
549 * (see CustomEvent documentation)
550 * @param {Boolean} override Optional. If true, will override "this"
551 * within the handler to map to the scope Object passed into the method.
552 * @return {Boolean} True, if the subscription was successful,
555 subscribeToConfigEvent: function (key, handler, obj, override) {
557 var property = this.config[key.toLowerCase()];
559 if (property && property.event) {
561 if (!Config.alreadySubscribed(property.event, handler, obj)) {
563 property.event.subscribe(handler, obj, override);
578 * Unsubscribes an external handler from the change event for any
580 * @method unsubscribeFromConfigEvent
581 * @param {String} key The property name
582 * @param {Function} handler The handler function to use subscribe to
583 * the property's event
584 * @param {Object} obj The Object to use for scoping the event
585 * handler (see CustomEvent documentation)
586 * @return {Boolean} True, if the unsubscription was successful,
589 unsubscribeFromConfigEvent: function (key, handler, obj) {
590 var property = this.config[key.toLowerCase()];
591 if (property && property.event) {
592 return property.event.unsubscribe(handler, obj);
599 * Returns a string representation of the Config object
601 * @return {String} The Config object in string format.
603 toString: function () {
604 var output = "Config";
606 output += " [" + this.owner.toString() + "]";
612 * Returns a string representation of the Config object's current
614 * @method outputEventQueue
615 * @return {String} The string list of CustomEvents currently queued
618 outputEventQueue: function () {
623 nQueue = this.eventQueue.length;
625 for (q = 0; q < nQueue; q++) {
626 queueItem = this.eventQueue[q];
628 output += queueItem[0] + "=" + queueItem[1] + ", ";
635 * Sets all properties to null, unsubscribes all listeners from each
636 * property's change event and all listeners from the configChangedEvent.
639 destroy: function () {
641 var oConfig = this.config,
646 for (sProperty in oConfig) {
648 if (Lang.hasOwnProperty(oConfig, sProperty)) {
650 oProperty = oConfig[sProperty];
652 oProperty.event.unsubscribeAll();
653 oProperty.event = null;
659 this.configChangedEvent.unsubscribeAll();
661 this.configChangedEvent = null;
664 this.initialConfig = null;
665 this.eventQueue = null;
674 * Checks to determine if a particular function/Object pair are already
675 * subscribed to the specified CustomEvent
676 * @method YAHOO.util.Config.alreadySubscribed
678 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
680 * @param {Function} fn The function to look for in the subscribers list
681 * @param {Object} obj The execution scope Object for the subscription
682 * @return {Boolean} true, if the function/Object pair is already subscribed
683 * to the CustomEvent passed in
685 Config.alreadySubscribed = function (evt, fn, obj) {
687 var nSubscribers = evt.subscribers.length,
691 if (nSubscribers > 0) {
693 i = nSubscribers - 1;
697 subsc = evt.subscribers[i];
699 if (subsc && subsc.obj == obj && subsc.fn == fn) {
714 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
720 * The Container family of components is designed to enable developers to
721 * create different kinds of content-containing modules on the web. Module
722 * and Overlay are the most basic containers, and they can be used directly
723 * or extended to build custom containers. Also part of the Container family
724 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
725 * Dialog, and SimpleDialog.
728 * @requires yahoo, dom, event
729 * @optional dragdrop, animation, button
733 * Module is a JavaScript representation of the Standard Module Format.
734 * Standard Module Format is a simple standard for markup containers where
735 * child nodes representing the header, body, and footer of the content are
736 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
737 * Module is the base class for all other classes in the YUI
739 * @namespace YAHOO.widget
742 * @param {String} el The element ID representing the Module <em>OR</em>
743 * @param {HTMLElement} el The element representing the Module
744 * @param {Object} userConfig The configuration Object literal containing
745 * the configuration that should be set for this module. See configuration
746 * documentation for more details.
748 YAHOO.widget.Module = function (el, userConfig) {
752 this.init(el, userConfig);
762 var Dom = YAHOO.util.Dom,
763 Config = YAHOO.util.Config,
764 Event = YAHOO.util.Event,
765 CustomEvent = YAHOO.util.CustomEvent,
766 Module = YAHOO.widget.Module,
774 * Constant representing the name of the Module's events
775 * @property EVENT_TYPES
782 "BEFORE_INIT": "beforeInit",
785 "BEFORE_RENDER": "beforeRender",
787 "CHANGE_HEADER": "changeHeader",
788 "CHANGE_BODY": "changeBody",
789 "CHANGE_FOOTER": "changeFooter",
790 "CHANGE_CONTENT": "changeContent",
791 "DESTORY": "destroy",
792 "BEFORE_SHOW": "beforeShow",
794 "BEFORE_HIDE": "beforeHide",
800 * Constant representing the Module's configuration properties
801 * @property DEFAULT_CONFIG
811 validator: YAHOO.lang.isBoolean
817 supercedes: ["visible"]
821 key: "monitorresize",
829 * Constant representing the prefix path to use for non-secure images
830 * @property YAHOO.widget.Module.IMG_ROOT
835 Module.IMG_ROOT = null;
838 * Constant representing the prefix path to use for securely served images
839 * @property YAHOO.widget.Module.IMG_ROOT_SSL
844 Module.IMG_ROOT_SSL = null;
847 * Constant for the default CSS class name that represents a Module
848 * @property YAHOO.widget.Module.CSS_MODULE
853 Module.CSS_MODULE = "yui-module";
856 * Constant representing the module header
857 * @property YAHOO.widget.Module.CSS_HEADER
862 Module.CSS_HEADER = "hd";
865 * Constant representing the module body
866 * @property YAHOO.widget.Module.CSS_BODY
871 Module.CSS_BODY = "bd";
874 * Constant representing the module footer
875 * @property YAHOO.widget.Module.CSS_FOOTER
880 Module.CSS_FOOTER = "ft";
883 * Constant representing the url for the "src" attribute of the iframe
884 * used to monitor changes to the browser's base font size
885 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
890 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
893 * Singleton CustomEvent fired when the font size is changed in the browser.
894 * Opera's "zoom" functionality currently does not support text
896 * @event YAHOO.widget.Module.textResizeEvent
898 Module.textResizeEvent = new CustomEvent("textResize");
901 function createModuleTemplate() {
903 if (!m_oModuleTemplate) {
905 m_oModuleTemplate = document.createElement("div");
907 m_oModuleTemplate.innerHTML = ("<div class=\"" +
908 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
909 Module.CSS_BODY + "\"></div><div class=\"" +
910 Module.CSS_FOOTER + "\"></div>");
912 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
913 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
914 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
918 return m_oModuleTemplate;
923 function createHeader() {
925 if (!m_oHeaderTemplate) {
927 createModuleTemplate();
931 return (m_oHeaderTemplate.cloneNode(false));
936 function createBody() {
938 if (!m_oBodyTemplate) {
940 createModuleTemplate();
944 return (m_oBodyTemplate.cloneNode(false));
949 function createFooter() {
951 if (!m_oFooterTemplate) {
953 createModuleTemplate();
957 return (m_oFooterTemplate.cloneNode(false));
965 * The class's constructor function
966 * @property contructor
972 * The main module element that contains the header, body, and footer
979 * The header element, denoted with CSS class "hd"
986 * The body element, denoted with CSS class "bd"
993 * The footer element, denoted with CSS class "ft"
1000 * The id of the element
1007 * A string representing the root path for all images created by
1008 * a Module instance.
1009 * @deprecated It is recommend that any images for a Module be applied
1010 * via CSS using the "background-image" property.
1011 * @property imageRoot
1014 imageRoot: Module.IMG_ROOT,
1017 * Initializes the custom events for Module which are fired
1018 * automatically at appropriate times by the Module class.
1019 * @method initEvents
1021 initEvents: function () {
1023 var SIGNATURE = CustomEvent.LIST;
1026 * CustomEvent fired prior to class initalization.
1027 * @event beforeInitEvent
1028 * @param {class} classRef class reference of the initializing
1029 * class, such as this.beforeInitEvent.fire(Module)
1031 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1032 this.beforeInitEvent.signature = SIGNATURE;
1035 * CustomEvent fired after class initalization.
1037 * @param {class} classRef class reference of the initializing
1038 * class, such as this.beforeInitEvent.fire(Module)
1040 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1041 this.initEvent.signature = SIGNATURE;
1044 * CustomEvent fired when the Module is appended to the DOM
1045 * @event appendEvent
1047 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1048 this.appendEvent.signature = SIGNATURE;
1051 * CustomEvent fired before the Module is rendered
1052 * @event beforeRenderEvent
1054 this.beforeRenderEvent =
1055 this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1056 this.beforeRenderEvent.signature = SIGNATURE;
1059 * CustomEvent fired after the Module is rendered
1060 * @event renderEvent
1062 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1063 this.renderEvent.signature = SIGNATURE;
1066 * CustomEvent fired when the header content of the Module
1068 * @event changeHeaderEvent
1069 * @param {String/HTMLElement} content String/element representing
1070 * the new header content
1072 this.changeHeaderEvent =
1073 this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1074 this.changeHeaderEvent.signature = SIGNATURE;
1077 * CustomEvent fired when the body content of the Module is modified
1078 * @event changeBodyEvent
1079 * @param {String/HTMLElement} content String/element representing
1080 * the new body content
1082 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1083 this.changeBodyEvent.signature = SIGNATURE;
1086 * CustomEvent fired when the footer content of the Module
1088 * @event changeFooterEvent
1089 * @param {String/HTMLElement} content String/element representing
1090 * the new footer content
1092 this.changeFooterEvent =
1093 this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1094 this.changeFooterEvent.signature = SIGNATURE;
1097 * CustomEvent fired when the content of the Module is modified
1098 * @event changeContentEvent
1100 this.changeContentEvent =
1101 this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1102 this.changeContentEvent.signature = SIGNATURE;
1105 * CustomEvent fired when the Module is destroyed
1106 * @event destroyEvent
1108 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
1109 this.destroyEvent.signature = SIGNATURE;
1112 * CustomEvent fired before the Module is shown
1113 * @event beforeShowEvent
1115 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1116 this.beforeShowEvent.signature = SIGNATURE;
1119 * CustomEvent fired after the Module is shown
1122 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1123 this.showEvent.signature = SIGNATURE;
1126 * CustomEvent fired before the Module is hidden
1127 * @event beforeHideEvent
1129 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1130 this.beforeHideEvent.signature = SIGNATURE;
1133 * CustomEvent fired after the Module is hidden
1136 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1137 this.hideEvent.signature = SIGNATURE;
1141 * String representing the current user-agent platform
1142 * @property platform
1145 platform: function () {
1147 var ua = navigator.userAgent.toLowerCase();
1149 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1153 } else if (ua.indexOf("macintosh") != -1) {
1166 * String representing the user-agent of the browser
1167 * @deprecated Use YAHOO.env.ua
1171 browser: function () {
1173 var ua = navigator.userAgent.toLowerCase();
1176 Check Opera first in case of spoof and check Safari before
1177 Gecko since Safari's user agent string includes "like Gecko"
1180 if (ua.indexOf('opera') != -1) {
1184 } else if (ua.indexOf('msie 7') != -1) {
1188 } else if (ua.indexOf('msie') != -1) {
1192 } else if (ua.indexOf('safari') != -1) {
1196 } else if (ua.indexOf('gecko') != -1) {
1209 * Boolean representing whether or not the current browsing context is
1211 * @property isSecure
1214 isSecure: function () {
1216 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1229 * Initializes the custom events for Module which are fired
1230 * automatically at appropriate times by the Module class.
1232 initDefaultConfig: function () {
1234 // Add properties //
1237 * Specifies whether the Module is visible on the page.
1242 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1243 handler: this.configVisible,
1244 value: DEFAULT_CONFIG.VISIBLE.value,
1245 validator: DEFAULT_CONFIG.VISIBLE.validator
1249 * Object or array of objects representing the ContainerEffect
1250 * classes that are active for animating the container.
1255 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1256 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1257 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1261 * Specifies whether to create a special proxy iframe to monitor
1262 * for user font resizing in the document
1263 * @config monitorresize
1267 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1268 handler: this.configMonitorResize,
1269 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1275 * The Module class's initialization method, which is executed for
1276 * Module and all of its subclasses. This method is automatically
1277 * called by the constructor, and sets up all DOM references for
1278 * pre-existing markup, and creates required markup if it is not
1281 * @param {String} el The element ID representing the Module <em>OR</em>
1282 * @param {HTMLElement} el The element representing the Module
1283 * @param {Object} userConfig The configuration Object literal
1284 * containing the configuration that should be set for this module.
1285 * See configuration documentation for more details.
1287 init: function (el, userConfig) {
1293 this.beforeInitEvent.fire(Module);
1296 * The Module's Config object used for monitoring
1297 * configuration properties.
1299 * @type YAHOO.util.Config
1301 this.cfg = new Config(this);
1303 if (this.isSecure) {
1304 this.imageRoot = Module.IMG_ROOT_SSL;
1307 if (typeof el == "string") {
1311 el = document.getElementById(el);
1315 el = (createModuleTemplate()).cloneNode(false);
1329 child = this.element.firstChild;
1335 switch (child.className) {
1337 case Module.CSS_HEADER:
1339 this.header = child;
1343 case Module.CSS_BODY:
1349 case Module.CSS_FOOTER:
1351 this.footer = child;
1357 } while ((child = child.nextSibling));
1362 this.initDefaultConfig();
1364 Dom.addClass(this.element, Module.CSS_MODULE);
1367 this.cfg.applyConfig(userConfig, true);
1371 Subscribe to the fireQueue() method of Config so that any
1372 queued configuration changes are excecuted upon render of
1376 if (!Config.alreadySubscribed(this.renderEvent,
1377 this.cfg.fireQueue, this.cfg)) {
1379 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1383 this.initEvent.fire(Module);
1387 * Initialized an empty IFRAME that is placed out of the visible area
1388 * that can be used to detect text resize.
1389 * @method initResizeMonitor
1391 initResizeMonitor: function () {
1397 function fireTextResize() {
1399 Module.textResizeEvent.fire();
1403 if (!YAHOO.env.ua.opera) {
1405 oIFrame = Dom.get("_yuiResizeMonitor");
1409 oIFrame = document.createElement("iframe");
1411 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL &&
1414 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1420 Need to set "src" attribute of the iframe to
1421 prevent the browser from reporting duplicate
1422 cookies. (See SourceForge bug #1721755)
1425 if (YAHOO.env.ua.gecko) {
1427 sHTML = "<html><head><script " +
1428 "type=\"text/javascript\">" +
1429 "window.onresize=function(){window.parent." +
1430 "YAHOO.widget.Module.textResizeEvent." +
1431 "fire();};window.parent.YAHOO.widget.Module." +
1432 "textResizeEvent.fire();</script></head>" +
1433 "<body></body></html>";
1435 oIFrame.src = "data:text/html;charset=utf-8," +
1436 encodeURIComponent(sHTML);
1440 oIFrame.id = "_yuiResizeMonitor";
1443 Need to set "position" property before inserting the
1444 iframe into the document or Safari's status bar will
1445 forever indicate the iframe is loading
1446 (See SourceForge bug #1723064)
1449 oIFrame.style.position = "absolute";
1450 oIFrame.style.visibility = "hidden";
1452 document.body.appendChild(oIFrame);
1454 oIFrame.style.width = "10em";
1455 oIFrame.style.height = "10em";
1456 oIFrame.style.top = (-1 * oIFrame.offsetHeight) + "px";
1457 oIFrame.style.left = (-1 * oIFrame.offsetWidth) + "px";
1458 oIFrame.style.borderWidth = "0";
1459 oIFrame.style.visibility = "visible";
1461 if (YAHOO.env.ua.webkit) {
1463 oDoc = oIFrame.contentWindow.document;
1472 if (oIFrame && oIFrame.contentWindow) {
1474 Module.textResizeEvent.subscribe(this.onDomResize,
1477 if (!Module.textResizeInitialized) {
1479 if (!Event.on(oIFrame.contentWindow, "resize",
1483 This will fail in IE if document.domain has
1484 changed, so we must change the listener to
1485 use the oIFrame element instead
1488 Event.on(oIFrame, "resize", fireTextResize);
1492 Module.textResizeInitialized = true;
1496 this.resizeMonitor = oIFrame;
1505 * Event handler fired when the resize monitor element is resized.
1506 * @method onDomResize
1507 * @param {DOMEvent} e The DOM resize event
1508 * @param {Object} obj The scope object passed to the handler
1510 onDomResize: function (e, obj) {
1512 var nLeft = -1 * this.resizeMonitor.offsetWidth,
1513 nTop = -1 * this.resizeMonitor.offsetHeight;
1515 this.resizeMonitor.style.top = nTop + "px";
1516 this.resizeMonitor.style.left = nLeft + "px";
1521 * Sets the Module's header content to the HTML specified, or appends
1522 * the passed element to the header. If no header is present, one will
1523 * be automatically created.
1525 * @param {String} headerContent The HTML used to set the header
1527 * @param {HTMLElement} headerContent The HTMLElement to append to
1530 setHeader: function (headerContent) {
1532 var oHeader = this.header || (this.header = createHeader());
1534 if (typeof headerContent == "string") {
1536 oHeader.innerHTML = headerContent;
1540 oHeader.innerHTML = "";
1541 oHeader.appendChild(headerContent);
1545 this.changeHeaderEvent.fire(headerContent);
1546 this.changeContentEvent.fire();
1551 * Appends the passed element to the header. If no header is present,
1552 * one will be automatically created.
1553 * @method appendToHeader
1554 * @param {HTMLElement} element The element to append to the header
1556 appendToHeader: function (element) {
1558 var oHeader = this.header || (this.header = createHeader());
1560 oHeader.appendChild(element);
1562 this.changeHeaderEvent.fire(element);
1563 this.changeContentEvent.fire();
1568 * Sets the Module's body content to the HTML specified, or appends the
1569 * passed element to the body. If no body is present, one will be
1570 * automatically created.
1572 * @param {String} bodyContent The HTML used to set the body <em>OR</em>
1573 * @param {HTMLElement} bodyContent The HTMLElement to append to the body
1575 setBody: function (bodyContent) {
1577 var oBody = this.body || (this.body = createBody());
1579 if (typeof bodyContent == "string") {
1581 oBody.innerHTML = bodyContent;
1585 oBody.innerHTML = "";
1586 oBody.appendChild(bodyContent);
1590 this.changeBodyEvent.fire(bodyContent);
1591 this.changeContentEvent.fire();
1596 * Appends the passed element to the body. If no body is present, one
1597 * will be automatically created.
1598 * @method appendToBody
1599 * @param {HTMLElement} element The element to append to the body
1601 appendToBody: function (element) {
1603 var oBody = this.body || (this.body = createBody());
1605 oBody.appendChild(element);
1607 this.changeBodyEvent.fire(element);
1608 this.changeContentEvent.fire();
1613 * Sets the Module's footer content to the HTML specified, or appends
1614 * the passed element to the footer. If no footer is present, one will
1615 * be automatically created.
1617 * @param {String} footerContent The HTML used to set the footer
1619 * @param {HTMLElement} footerContent The HTMLElement to append to
1622 setFooter: function (footerContent) {
1624 var oFooter = this.footer || (this.footer = createFooter());
1626 if (typeof footerContent == "string") {
1628 oFooter.innerHTML = footerContent;
1632 oFooter.innerHTML = "";
1633 oFooter.appendChild(footerContent);
1637 this.changeFooterEvent.fire(footerContent);
1638 this.changeContentEvent.fire();
1643 * Appends the passed element to the footer. If no footer is present,
1644 * one will be automatically created.
1645 * @method appendToFooter
1646 * @param {HTMLElement} element The element to append to the footer
1648 appendToFooter: function (element) {
1650 var oFooter = this.footer || (this.footer = createFooter());
1652 oFooter.appendChild(element);
1654 this.changeFooterEvent.fire(element);
1655 this.changeContentEvent.fire();
1660 * Renders the Module by inserting the elements that are not already
1661 * in the main Module into their correct places. Optionally appends
1662 * the Module to the specified node prior to the render's execution.
1663 * NOTE: For Modules without existing markup, the appendToNode argument
1664 * is REQUIRED. If this argument is ommitted and the current element is
1665 * not present in the document, the function will return false,
1666 * indicating that the render was a failure.
1668 * @param {String} appendToNode The element id to which the Module
1669 * should be appended to prior to rendering <em>OR</em>
1670 * @param {HTMLElement} appendToNode The element to which the Module
1671 * should be appended to prior to rendering
1672 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1673 * represents the actual Standard Module container.
1674 * @return {Boolean} Success or failure of the render
1676 render: function (appendToNode, moduleElement) {
1681 function appendTo(element) {
1682 if (typeof element == "string") {
1683 element = document.getElementById(element);
1687 element.appendChild(me.element);
1688 me.appendEvent.fire();
1692 this.beforeRenderEvent.fire();
1694 if (! moduleElement) {
1695 moduleElement = this.element;
1700 appendTo(appendToNode);
1705 No node was passed in. If the element is not already in
1709 if (! Dom.inDocument(this.element)) {
1718 // Need to get everything into the DOM if it isn't already
1720 if (this.header && ! Dom.inDocument(this.header)) {
1723 There is a header, but it's not in the DOM yet...
1727 firstChild = moduleElement.firstChild;
1729 if (firstChild) { // Insert before first child if exists
1731 moduleElement.insertBefore(this.header, firstChild);
1733 } else { // Append to empty body because there are no children
1735 moduleElement.appendChild(this.header);
1741 if (this.body && ! Dom.inDocument(this.body)) {
1744 There is a body, but it's not in the DOM yet...
1749 // Insert before footer if exists in DOM
1751 if (this.footer && Dom.isAncestor(
1752 this.moduleElement, this.footer)) {
1754 moduleElement.insertBefore(this.body, this.footer);
1756 } else { // Append to element because there is no footer
1758 moduleElement.appendChild(this.body);
1764 if (this.footer && ! Dom.inDocument(this.footer)) {
1767 There is a footer, but it's not in the DOM yet...
1771 moduleElement.appendChild(this.footer);
1775 this.renderEvent.fire();
1780 * Removes the Module element from the DOM and sets all child elements
1784 destroy: function () {
1790 Event.purgeElement(this.element, true);
1791 parent = this.element.parentNode;
1795 parent.removeChild(this.element);
1798 this.element = null;
1803 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1808 this.destroyEvent.fire();
1811 if (e instanceof CustomEvent) {
1819 * Shows the Module element by setting the visible configuration
1820 * property to true. Also fires two events: beforeShowEvent prior to
1821 * the visibility change, and showEvent after.
1825 this.cfg.setProperty("visible", true);
1829 * Hides the Module element by setting the visible configuration
1830 * property to false. Also fires two events: beforeHideEvent prior to
1831 * the visibility change, and hideEvent after.
1835 this.cfg.setProperty("visible", false);
1838 // BUILT-IN EVENT HANDLERS FOR MODULE //
1841 * Default event handler for changing the visibility property of a
1842 * Module. By default, this is achieved by switching the "display" style
1843 * between "block" and "none".
1844 * This method is responsible for firing showEvent and hideEvent.
1845 * @param {String} type The CustomEvent type (usually the property name)
1846 * @param {Object[]} args The CustomEvent arguments. For configuration
1847 * handlers, args[0] will equal the newly applied value for the property.
1848 * @param {Object} obj The scope object. For configuration handlers,
1849 * this will usually equal the owner.
1850 * @method configVisible
1852 configVisible: function (type, args, obj) {
1853 var visible = args[0];
1855 this.beforeShowEvent.fire();
1856 Dom.setStyle(this.element, "display", "block");
1857 this.showEvent.fire();
1859 this.beforeHideEvent.fire();
1860 Dom.setStyle(this.element, "display", "none");
1861 this.hideEvent.fire();
1866 * Default event handler for the "monitorresize" configuration property
1867 * @param {String} type The CustomEvent type (usually the property name)
1868 * @param {Object[]} args The CustomEvent arguments. For configuration
1869 * handlers, args[0] will equal the newly applied value for the property.
1870 * @param {Object} obj The scope object. For configuration handlers,
1871 * this will usually equal the owner.
1872 * @method configMonitorResize
1874 configMonitorResize: function (type, args, obj) {
1876 var monitor = args[0];
1880 this.initResizeMonitor();
1884 Module.textResizeEvent.unsubscribe(
1885 this.onDomResize, this, true);
1887 this.resizeMonitor = null;
1893 * Returns a String representation of the Object.
1895 * @return {String} The string representation of the Module
1897 toString: function () {
1898 return "Module " + this.id;
1903 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1909 * Overlay is a Module that is absolutely positioned above the page flow. It
1910 * has convenience methods for positioning and sizing, as well as options for
1911 * controlling zIndex and constraining the Overlay's position to the current
1912 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1913 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1914 * properly rendered above SELECT elements.
1915 * @namespace YAHOO.widget
1918 * @param {String} el The element ID representing the Overlay <em>OR</em>
1919 * @param {HTMLElement} el The element representing the Overlay
1920 * @param {Object} userConfig The configuration object literal containing
1921 * the configuration that should be set for this Overlay. See configuration
1922 * documentation for more details.
1925 YAHOO.widget.Overlay = function (el, userConfig) {
1927 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1932 var Lang = YAHOO.lang,
1933 CustomEvent = YAHOO.util.CustomEvent,
1934 Module = YAHOO.widget.Module,
1935 Event = YAHOO.util.Event,
1936 Dom = YAHOO.util.Dom,
1937 Config = YAHOO.util.Config,
1938 Overlay = YAHOO.widget.Overlay,
1943 * Constant representing the name of the Overlay's events
1944 * @property EVENT_TYPES
1951 "BEFORE_MOVE": "beforeMove",
1957 * Constant representing the Overlay's configuration properties
1958 * @property DEFAULT_CONFIG
1967 validator: Lang.isNumber,
1968 suppressEvent: true,
1969 supercedes: ["iframe"]
1974 validator: Lang.isNumber,
1975 suppressEvent: true,
1976 supercedes: ["iframe"]
1981 suppressEvent: true,
1982 supercedes: ["iframe"]
1987 suppressEvent: true,
1988 supercedes: ["iframe"]
1994 validator: Lang.isBoolean,
1995 supercedes: ["iframe", "visible"]
2000 suppressEvent: true,
2001 supercedes: ["context", "fixedcenter", "iframe"]
2006 suppressEvent: true,
2007 supercedes: ["context", "fixedcenter", "iframe"]
2015 "CONSTRAIN_TO_VIEWPORT": {
2016 key: "constraintoviewport",
2018 validator: Lang.isBoolean,
2019 supercedes: ["iframe", "x", "y", "xy"]
2024 value: (YAHOO.env.ua.ie == 6 ? true : false),
2025 validator: Lang.isBoolean,
2026 supercedes: ["zindex"]
2033 * The URL that will be placed in the iframe
2034 * @property YAHOO.widget.Overlay.IFRAME_SRC
2039 Overlay.IFRAME_SRC = "javascript:false;";
2042 * Number representing how much the iframe shim should be offset from each
2043 * side of an Overlay instance.
2044 * @property YAHOO.widget.Overlay.IFRAME_SRC
2050 Overlay.IFRAME_OFFSET = 3;
2053 * Constant representing the top left corner of an element, used for
2054 * configuring the context element alignment
2055 * @property YAHOO.widget.Overlay.TOP_LEFT
2060 Overlay.TOP_LEFT = "tl";
2063 * Constant representing the top right corner of an element, used for
2064 * configuring the context element alignment
2065 * @property YAHOO.widget.Overlay.TOP_RIGHT
2070 Overlay.TOP_RIGHT = "tr";
2073 * Constant representing the top bottom left corner of an element, used for
2074 * configuring the context element alignment
2075 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2080 Overlay.BOTTOM_LEFT = "bl";
2083 * Constant representing the bottom right corner of an element, used for
2084 * configuring the context element alignment
2085 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2090 Overlay.BOTTOM_RIGHT = "br";
2093 * Constant representing the default CSS class used for an Overlay
2094 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2099 Overlay.CSS_OVERLAY = "yui-overlay";
2103 * A singleton CustomEvent used for reacting to the DOM event for
2105 * @event YAHOO.widget.Overlay.windowScrollEvent
2107 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2110 * A singleton CustomEvent used for reacting to the DOM event for
2112 * @event YAHOO.widget.Overlay.windowResizeEvent
2114 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2117 * The DOM event handler used to fire the CustomEvent for window scroll
2118 * @method YAHOO.widget.Overlay.windowScrollHandler
2120 * @param {DOMEvent} e The DOM scroll event
2122 Overlay.windowScrollHandler = function (e) {
2124 if (YAHOO.env.ua.ie) {
2126 if (! window.scrollEnd) {
2128 window.scrollEnd = -1;
2132 clearTimeout(window.scrollEnd);
2134 window.scrollEnd = setTimeout(function () {
2136 Overlay.windowScrollEvent.fire();
2142 Overlay.windowScrollEvent.fire();
2149 * The DOM event handler used to fire the CustomEvent for window resize
2150 * @method YAHOO.widget.Overlay.windowResizeHandler
2152 * @param {DOMEvent} e The DOM resize event
2154 Overlay.windowResizeHandler = function (e) {
2156 if (YAHOO.env.ua.ie) {
2158 if (! window.resizeEnd) {
2159 window.resizeEnd = -1;
2162 clearTimeout(window.resizeEnd);
2164 window.resizeEnd = setTimeout(function () {
2166 Overlay.windowResizeEvent.fire();
2172 Overlay.windowResizeEvent.fire();
2179 * A boolean that indicated whether the window resize and scroll events have
2180 * already been subscribed to.
2181 * @property YAHOO.widget.Overlay._initialized
2185 Overlay._initialized = null;
2187 if (Overlay._initialized === null) {
2189 Event.on(window, "scroll", Overlay.windowScrollHandler);
2190 Event.on(window, "resize", Overlay.windowResizeHandler);
2192 Overlay._initialized = true;
2196 YAHOO.extend(Overlay, Module, {
2199 * The Overlay initialization method, which is executed for Overlay and
2200 * all of its subclasses. This method is automatically called by the
2201 * constructor, and sets up all DOM references for pre-existing markup,
2202 * and creates required markup if it is not already present.
2204 * @param {String} el The element ID representing the Overlay <em>OR</em>
2205 * @param {HTMLElement} el The element representing the Overlay
2206 * @param {Object} userConfig The configuration object literal
2207 * containing the configuration that should be set for this Overlay.
2208 * See configuration documentation for more details.
2210 init: function (el, userConfig) {
2213 Note that we don't pass the user config in here yet because we
2214 only want it executed once, at the lowest subclass level
2217 Overlay.superclass.init.call(this, el/*, userConfig*/);
2219 this.beforeInitEvent.fire(Overlay);
2221 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2225 this.cfg.applyConfig(userConfig, true);
2229 if (this.platform == "mac" && YAHOO.env.ua.gecko) {
2231 if (! Config.alreadySubscribed(this.showEvent,
2232 this.showMacGeckoScrollbars, this)) {
2234 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2239 if (! Config.alreadySubscribed(this.hideEvent,
2240 this.hideMacGeckoScrollbars, this)) {
2242 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2249 this.initEvent.fire(Overlay);
2254 * Initializes the custom events for Overlay which are fired
2255 * automatically at appropriate times by the Overlay class.
2256 * @method initEvents
2258 initEvents: function () {
2260 Overlay.superclass.initEvents.call(this);
2262 var SIGNATURE = CustomEvent.LIST;
2265 * CustomEvent fired before the Overlay is moved.
2266 * @event beforeMoveEvent
2267 * @param {Number} x x coordinate
2268 * @param {Number} y y coordinate
2270 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2271 this.beforeMoveEvent.signature = SIGNATURE;
2274 * CustomEvent fired after the Overlay is moved.
2276 * @param {Number} x x coordinate
2277 * @param {Number} y y coordinate
2279 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2280 this.moveEvent.signature = SIGNATURE;
2285 * Initializes the class's configurable properties which can be changed
2286 * using the Overlay's Config object (cfg).
2287 * @method initDefaultConfig
2289 initDefaultConfig: function () {
2291 Overlay.superclass.initDefaultConfig.call(this);
2294 // Add overlay config properties //
2297 * The absolute x-coordinate position of the Overlay
2302 this.cfg.addProperty(DEFAULT_CONFIG.X.key, {
2304 handler: this.configX,
2305 validator: DEFAULT_CONFIG.X.validator,
2306 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2307 supercedes: DEFAULT_CONFIG.X.supercedes
2313 * The absolute y-coordinate position of the Overlay
2318 this.cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2320 handler: this.configY,
2321 validator: DEFAULT_CONFIG.Y.validator,
2322 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2323 supercedes: DEFAULT_CONFIG.Y.supercedes
2329 * An array with the absolute x and y positions of the Overlay
2334 this.cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2336 handler: this.configXY,
2337 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2338 supercedes: DEFAULT_CONFIG.XY.supercedes
2344 * The array of context arguments for context-sensitive positioning.
2345 * The format is: [id or element, element corner, context corner].
2346 * For example, setting this property to ["img1", "tl", "bl"] would
2347 * align the Overlay's top left corner to the context element's
2348 * bottom left corner.
2353 this.cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2355 handler: this.configContext,
2356 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2357 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2363 * True if the Overlay should be anchored to the center of
2365 * @config fixedcenter
2369 this.cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2371 handler: this.configFixedCenter,
2372 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2373 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2374 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2380 * CSS width of the Overlay.
2385 this.cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2387 handler: this.configWidth,
2388 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2389 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2394 * CSS height of the Overlay.
2399 this.cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2401 handler: this.configHeight,
2402 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2403 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2408 * CSS z-index of the Overlay.
2413 this.cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2415 handler: this.configzIndex,
2416 value: DEFAULT_CONFIG.ZINDEX.value
2421 * True if the Overlay should be prevented from being positioned
2422 * out of the viewport.
2423 * @config constraintoviewport
2427 this.cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2429 handler: this.configConstrainToViewport,
2430 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2431 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2432 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2438 * @description Boolean indicating whether or not the Overlay should
2439 * have an IFRAME shim; used to prevent <SELECT> elements from
2440 * poking through an Overlay instance in IE6. When set to "true",
2441 * the iframe shim is created when the Overlay instance is intially
2444 * @default true for IE6 and below, false for all other browsers.
2446 this.cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2448 handler: this.configIframe,
2449 value: DEFAULT_CONFIG.IFRAME.value,
2450 validator: DEFAULT_CONFIG.IFRAME.validator,
2451 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2458 * Moves the Overlay to the specified position. This function is
2459 * identical to calling this.cfg.setProperty("xy", [x,y]);
2461 * @param {Number} x The Overlay's new x position
2462 * @param {Number} y The Overlay's new y position
2464 moveTo: function (x, y) {
2466 this.cfg.setProperty("xy", [x, y]);
2471 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2472 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2473 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2474 * @method hideMacGeckoScrollbars
2476 hideMacGeckoScrollbars: function () {
2478 Dom.removeClass(this.element, "show-scrollbars");
2479 Dom.addClass(this.element, "hide-scrollbars");
2484 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2485 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2486 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2487 * @method showMacGeckoScrollbars
2489 showMacGeckoScrollbars: function () {
2491 Dom.removeClass(this.element, "hide-scrollbars");
2492 Dom.addClass(this.element, "show-scrollbars");
2496 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2499 * The default event handler fired when the "visible" property is
2500 * changed. This method is responsible for firing showEvent
2502 * @method configVisible
2503 * @param {String} type The CustomEvent type (usually the property name)
2504 * @param {Object[]} args The CustomEvent arguments. For configuration
2505 * handlers, args[0] will equal the newly applied value for the property.
2506 * @param {Object} obj The scope object. For configuration handlers,
2507 * this will usually equal the owner.
2509 configVisible: function (type, args, obj) {
2511 var visible = args[0],
2512 currentVis = Dom.getStyle(this.element, "visibility"),
2513 effect = this.cfg.getProperty("effect"),
2514 effectInstances = [],
2515 isMacGecko = (this.platform == "mac" && YAHOO.env.ua.gecko),
2516 alreadySubscribed = Config.alreadySubscribed,
2517 eff, ei, e, i, j, k, h,
2522 if (currentVis == "inherit") {
2524 e = this.element.parentNode;
2526 while (e.nodeType != 9 && e.nodeType != 11) {
2528 currentVis = Dom.getStyle(e, "visibility");
2530 if (currentVis != "inherit") {
2540 if (currentVis == "inherit") {
2542 currentVis = "visible";
2551 if (effect instanceof Array) {
2553 nEffects = effect.length;
2555 for (i = 0; i < nEffects; i++) {
2559 effectInstances[effectInstances.length] =
2560 eff.effect(this, eff.duration);
2566 effectInstances[effectInstances.length] =
2567 effect.effect(this, effect.duration);
2574 if (visible) { // Show
2578 this.showMacGeckoScrollbars();
2583 if (effect) { // Animate in
2586 if (visible) { // Animate in if not showing
2589 if (currentVis != "visible" || currentVis === "") {
2591 this.beforeShowEvent.fire();
2593 nEffectInstances = effectInstances.length;
2595 for (j = 0; j < nEffectInstances; j++) {
2597 ei = effectInstances[j];
2599 if (j === 0 && !alreadySubscribed(
2600 ei.animateInCompleteEvent,
2601 this.showEvent.fire, this.showEvent)) {
2604 Delegate showEvent until end
2605 of animateInComplete
2608 ei.animateInCompleteEvent.subscribe(
2609 this.showEvent.fire, this.showEvent, true);
2623 if (currentVis != "visible" || currentVis === "") {
2625 this.beforeShowEvent.fire();
2627 Dom.setStyle(this.element, "visibility", "visible");
2629 this.cfg.refireEvent("iframe");
2630 this.showEvent.fire();
2640 this.hideMacGeckoScrollbars();
2644 if (effect) { // Animate out if showing
2646 if (currentVis == "visible") {
2648 this.beforeHideEvent.fire();
2650 nEffectInstances = effectInstances.length;
2652 for (k = 0; k < nEffectInstances; k++) {
2654 h = effectInstances[k];
2656 if (k === 0 && !alreadySubscribed(
2657 h.animateOutCompleteEvent, this.hideEvent.fire,
2661 Delegate hideEvent until end
2662 of animateOutComplete
2665 h.animateOutCompleteEvent.subscribe(
2666 this.hideEvent.fire, this.hideEvent, true);
2674 } else if (currentVis === "") {
2676 Dom.setStyle(this.element, "visibility", "hidden");
2680 } else { // Simple hide
2682 if (currentVis == "visible" || currentVis === "") {
2684 this.beforeHideEvent.fire();
2686 Dom.setStyle(this.element, "visibility", "hidden");
2688 this.hideEvent.fire();
2699 * Center event handler used for centering on scroll/resize, but only if
2700 * the Overlay is visible
2701 * @method doCenterOnDOMEvent
2703 doCenterOnDOMEvent: function () {
2705 if (this.cfg.getProperty("visible")) {
2714 * The default event handler fired when the "fixedcenter" property
2716 * @method configFixedCenter
2717 * @param {String} type The CustomEvent type (usually the property name)
2718 * @param {Object[]} args The CustomEvent arguments. For configuration
2719 * handlers, args[0] will equal the newly applied value for the property.
2720 * @param {Object} obj The scope object. For configuration handlers,
2721 * this will usually equal the owner.
2723 configFixedCenter: function (type, args, obj) {
2726 alreadySubscribed = Config.alreadySubscribed,
2727 windowResizeEvent = Overlay.windowResizeEvent,
2728 windowScrollEvent = Overlay.windowScrollEvent;
2734 if (!alreadySubscribed(this.beforeShowEvent,
2735 this.center, this)) {
2737 this.beforeShowEvent.subscribe(this.center);
2741 if (!alreadySubscribed(windowResizeEvent,
2742 this.doCenterOnDOMEvent, this)) {
2744 windowResizeEvent.subscribe(this.doCenterOnDOMEvent,
2749 if (!alreadySubscribed(windowScrollEvent,
2750 this.doCenterOnDOMEvent, this)) {
2752 windowScrollEvent.subscribe(this.doCenterOnDOMEvent,
2759 this.beforeShowEvent.unsubscribe(this.center);
2761 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2762 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2769 * The default event handler fired when the "height" property is changed.
2770 * @method configHeight
2771 * @param {String} type The CustomEvent type (usually the property name)
2772 * @param {Object[]} args The CustomEvent arguments. For configuration
2773 * handlers, args[0] will equal the newly applied value for the property.
2774 * @param {Object} obj The scope object. For configuration handlers,
2775 * this will usually equal the owner.
2777 configHeight: function (type, args, obj) {
2779 var height = args[0],
2782 Dom.setStyle(el, "height", height);
2783 this.cfg.refireEvent("iframe");
2788 * The default event handler fired when the "width" property is changed.
2789 * @method configWidth
2790 * @param {String} type The CustomEvent type (usually the property name)
2791 * @param {Object[]} args The CustomEvent arguments. For configuration
2792 * handlers, args[0] will equal the newly applied value for the property.
2793 * @param {Object} obj The scope object. For configuration handlers,
2794 * this will usually equal the owner.
2796 configWidth: function (type, args, obj) {
2798 var width = args[0],
2801 Dom.setStyle(el, "width", width);
2802 this.cfg.refireEvent("iframe");
2807 * The default event handler fired when the "zIndex" property is changed.
2808 * @method configzIndex
2809 * @param {String} type The CustomEvent type (usually the property name)
2810 * @param {Object[]} args The CustomEvent arguments. For configuration
2811 * handlers, args[0] will equal the newly applied value for the property.
2812 * @param {Object} obj The scope object. For configuration handlers,
2813 * this will usually equal the owner.
2815 configzIndex: function (type, args, obj) {
2817 var zIndex = args[0],
2822 zIndex = Dom.getStyle(el, "zIndex");
2824 if (! zIndex || isNaN(zIndex)) {
2840 Dom.setStyle(this.iframe, "zIndex", (zIndex - 1));
2843 Dom.setStyle(el, "zIndex", zIndex);
2844 this.cfg.setProperty("zIndex", zIndex, true);
2849 * The default event handler fired when the "xy" property is changed.
2851 * @param {String} type The CustomEvent type (usually the property name)
2852 * @param {Object[]} args The CustomEvent arguments. For configuration
2853 * handlers, args[0] will equal the newly applied value for the property.
2854 * @param {Object} obj The scope object. For configuration handlers,
2855 * this will usually equal the owner.
2857 configXY: function (type, args, obj) {
2863 this.cfg.setProperty("x", x);
2864 this.cfg.setProperty("y", y);
2866 this.beforeMoveEvent.fire([x, y]);
2868 x = this.cfg.getProperty("x");
2869 y = this.cfg.getProperty("y");
2872 this.cfg.refireEvent("iframe");
2873 this.moveEvent.fire([x, y]);
2878 * The default event handler fired when the "x" property is changed.
2880 * @param {String} type The CustomEvent type (usually the property name)
2881 * @param {Object[]} args The CustomEvent arguments. For configuration
2882 * handlers, args[0] will equal the newly applied value for the property.
2883 * @param {Object} obj The scope object. For configuration handlers,
2884 * this will usually equal the owner.
2886 configX: function (type, args, obj) {
2889 y = this.cfg.getProperty("y");
2891 this.cfg.setProperty("x", x, true);
2892 this.cfg.setProperty("y", y, true);
2894 this.beforeMoveEvent.fire([x, y]);
2896 x = this.cfg.getProperty("x");
2897 y = this.cfg.getProperty("y");
2899 Dom.setX(this.element, x, true);
2901 this.cfg.setProperty("xy", [x, y], true);
2903 this.cfg.refireEvent("iframe");
2904 this.moveEvent.fire([x, y]);
2909 * The default event handler fired when the "y" property is changed.
2911 * @param {String} type The CustomEvent type (usually the property name)
2912 * @param {Object[]} args The CustomEvent arguments. For configuration
2913 * handlers, args[0] will equal the newly applied value for the property.
2914 * @param {Object} obj The scope object. For configuration handlers,
2915 * this will usually equal the owner.
2917 configY: function (type, args, obj) {
2919 var x = this.cfg.getProperty("x"),
2922 this.cfg.setProperty("x", x, true);
2923 this.cfg.setProperty("y", y, true);
2925 this.beforeMoveEvent.fire([x, y]);
2927 x = this.cfg.getProperty("x");
2928 y = this.cfg.getProperty("y");
2930 Dom.setY(this.element, y, true);
2932 this.cfg.setProperty("xy", [x, y], true);
2934 this.cfg.refireEvent("iframe");
2935 this.moveEvent.fire([x, y]);
2940 * Shows the iframe shim, if it has been enabled.
2941 * @method showIframe
2943 showIframe: function () {
2945 var oIFrame = this.iframe,
2950 oParentNode = this.element.parentNode;
2952 if (oParentNode != oIFrame.parentNode) {
2954 oParentNode.appendChild(oIFrame);
2958 oIFrame.style.display = "block";
2965 * Hides the iframe shim, if it has been enabled.
2966 * @method hideIframe
2968 hideIframe: function () {
2972 this.iframe.style.display = "none";
2979 * Syncronizes the size and position of iframe shim to that of its
2980 * corresponding Overlay instance.
2981 * @method syncIframe
2983 syncIframe: function () {
2985 var oIFrame = this.iframe,
2986 oElement = this.element,
2987 nOffset = Overlay.IFRAME_OFFSET,
2988 nDimensionOffset = (nOffset * 2),
2996 oIFrame.style.width =
2997 (oElement.offsetWidth + nDimensionOffset + "px");
2999 oIFrame.style.height =
3000 (oElement.offsetHeight + nDimensionOffset + "px");
3003 // Position <iframe>
3005 aXY = this.cfg.getProperty("xy");
3007 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3009 this.syncPosition();
3011 aXY = this.cfg.getProperty("xy");
3015 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3023 * The default event handler fired when the "iframe" property is changed.
3024 * @method configIframe
3025 * @param {String} type The CustomEvent type (usually the property name)
3026 * @param {Object[]} args The CustomEvent arguments. For configuration
3027 * handlers, args[0] will equal the newly applied value for the property.
3028 * @param {Object} obj The scope object. For configuration handlers,
3029 * this will usually equal the owner.
3031 configIframe: function (type, args, obj) {
3033 var bIFrame = args[0];
3035 function createIFrame() {
3037 var oIFrame = this.iframe,
3038 oElement = this.element,
3045 if (!m_oIFrameTemplate) {
3047 m_oIFrameTemplate = document.createElement("iframe");
3049 if (this.isSecure) {
3051 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3056 Set the opacity of the <iframe> to 0 so that it
3057 doesn't modify the opacity of any transparent
3058 elements that may be on top of it (like a shadow).
3061 if (YAHOO.env.ua.ie) {
3063 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3066 Need to set the "frameBorder" property to 0
3067 supress the default <iframe> border in IE.
3068 Setting the CSS "border" property alone
3072 m_oIFrameTemplate.frameBorder = 0;
3077 m_oIFrameTemplate.style.opacity = "0";
3081 m_oIFrameTemplate.style.position = "absolute";
3082 m_oIFrameTemplate.style.border = "none";
3083 m_oIFrameTemplate.style.margin = "0";
3084 m_oIFrameTemplate.style.padding = "0";
3085 m_oIFrameTemplate.style.display = "none";
3089 oIFrame = m_oIFrameTemplate.cloneNode(false);
3091 oParent = oElement.parentNode;
3095 oParent.appendChild(oIFrame);
3099 document.body.appendChild(oIFrame);
3103 this.iframe = oIFrame;
3109 Show the <iframe> before positioning it since the "setXY"
3110 method of DOM requires the element be in the document
3118 Syncronize the size and position of the <iframe> to that
3125 // Add event listeners to update the <iframe> when necessary
3127 if (!this._hasIframeEventListeners) {
3129 this.showEvent.subscribe(this.showIframe);
3130 this.hideEvent.subscribe(this.hideIframe);
3131 this.changeContentEvent.subscribe(this.syncIframe);
3133 this._hasIframeEventListeners = true;
3140 function onBeforeShow() {
3142 createIFrame.call(this);
3144 this.beforeShowEvent.unsubscribe(onBeforeShow);
3146 this._iframeDeferred = false;
3151 if (bIFrame) { // <iframe> shim is enabled
3153 if (this.cfg.getProperty("visible")) {
3155 createIFrame.call(this);
3160 if (!this._iframeDeferred) {
3162 this.beforeShowEvent.subscribe(onBeforeShow);
3164 this._iframeDeferred = true;
3170 } else { // <iframe> shim is disabled
3174 if (this._hasIframeEventListeners) {
3176 this.showEvent.unsubscribe(this.showIframe);
3177 this.hideEvent.unsubscribe(this.hideIframe);
3178 this.changeContentEvent.unsubscribe(this.syncIframe);
3180 this._hasIframeEventListeners = false;
3190 * The default event handler fired when the "constraintoviewport"
3191 * property is changed.
3192 * @method configConstrainToViewport
3193 * @param {String} type The CustomEvent type (usually the property name)
3194 * @param {Object[]} args The CustomEvent arguments. For configuration
3195 * handlers, args[0] will equal the newly applied value for
3197 * @param {Object} obj The scope object. For configuration handlers,
3198 * this will usually equal the owner.
3200 configConstrainToViewport: function (type, args, obj) {
3206 if (! Config.alreadySubscribed(this.beforeMoveEvent,
3207 this.enforceConstraints, this)) {
3209 this.beforeMoveEvent.subscribe(this.enforceConstraints,
3216 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3223 * The default event handler fired when the "context" property
3225 * @method configContext
3226 * @param {String} type The CustomEvent type (usually the property name)
3227 * @param {Object[]} args The CustomEvent arguments. For configuration
3228 * handlers, args[0] will equal the newly applied value for the property.
3229 * @param {Object} obj The scope object. For configuration handlers,
3230 * this will usually equal the owner.
3232 configContext: function (type, args, obj) {
3234 var contextArgs = args[0],
3236 elementMagnetCorner,
3237 contextMagnetCorner;
3241 contextEl = contextArgs[0];
3242 elementMagnetCorner = contextArgs[1];
3243 contextMagnetCorner = contextArgs[2];
3247 if (typeof contextEl == "string") {
3249 this.cfg.setProperty("context",
3250 [document.getElementById(contextEl),
3251 elementMagnetCorner, contextMagnetCorner],
3256 if (elementMagnetCorner && contextMagnetCorner) {
3258 this.align(elementMagnetCorner, contextMagnetCorner);
3269 // END BUILT-IN PROPERTY EVENT HANDLERS //
3272 * Aligns the Overlay to its context element using the specified corner
3273 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3276 * @param {String} elementAlign The String representing the corner of
3277 * the Overlay that should be aligned to the context element
3278 * @param {String} contextAlign The corner of the context element
3279 * that the elementAlign corner should stick to.
3281 align: function (elementAlign, contextAlign) {
3283 var contextArgs = this.cfg.getProperty("context"),
3290 function doAlign(v, h) {
3292 switch (elementAlign) {
3294 case Overlay.TOP_LEFT:
3300 case Overlay.TOP_RIGHT:
3302 me.moveTo((h - element.offsetWidth), v);
3306 case Overlay.BOTTOM_LEFT:
3308 me.moveTo(h, (v - element.offsetHeight));
3312 case Overlay.BOTTOM_RIGHT:
3314 me.moveTo((h - element.offsetWidth),
3315 (v - element.offsetHeight));
3326 context = contextArgs[0];
3327 element = this.element;
3330 if (! elementAlign) {
3332 elementAlign = contextArgs[1];
3336 if (! contextAlign) {
3338 contextAlign = contextArgs[2];
3342 if (element && context) {
3344 contextRegion = Dom.getRegion(context);
3346 switch (contextAlign) {
3348 case Overlay.TOP_LEFT:
3350 doAlign(contextRegion.top, contextRegion.left);
3354 case Overlay.TOP_RIGHT:
3356 doAlign(contextRegion.top, contextRegion.right);
3360 case Overlay.BOTTOM_LEFT:
3362 doAlign(contextRegion.bottom, contextRegion.left);
3366 case Overlay.BOTTOM_RIGHT:
3368 doAlign(contextRegion.bottom, contextRegion.right);
3381 * The default event handler executed when the moveEvent is fired, if the
3382 * "constraintoviewport" is set to true.
3383 * @method enforceConstraints
3384 * @param {String} type The CustomEvent type (usually the property name)
3385 * @param {Object[]} args The CustomEvent arguments. For configuration
3386 * handlers, args[0] will equal the newly applied value for the property.
3387 * @param {Object} obj The scope object. For configuration handlers,
3388 * this will usually equal the owner.
3390 enforceConstraints: function (type, args, obj) {
3395 offsetHeight = this.element.offsetHeight,
3396 offsetWidth = this.element.offsetWidth,
3397 viewPortWidth = Dom.getViewportWidth(),
3398 viewPortHeight = Dom.getViewportHeight(),
3399 scrollX = Dom.getDocumentScrollLeft(),
3400 scrollY = Dom.getDocumentScrollTop(),
3401 topConstraint = scrollY + 10,
3402 leftConstraint = scrollX + 10,
3403 bottomConstraint = scrollY + viewPortHeight - offsetHeight - 10,
3404 rightConstraint = scrollX + viewPortWidth - offsetWidth - 10;
3407 if (x < leftConstraint) {
3411 } else if (x > rightConstraint) {
3413 x = rightConstraint;
3417 if (y < topConstraint) {
3421 } else if (y > bottomConstraint) {
3423 y = bottomConstraint;
3427 this.cfg.setProperty("x", x, true);
3428 this.cfg.setProperty("y", y, true);
3429 this.cfg.setProperty("xy", [x, y], true);
3434 * Centers the container in the viewport.
3437 center: function () {
3439 var scrollX = Dom.getDocumentScrollLeft(),
3440 scrollY = Dom.getDocumentScrollTop(),
3442 viewPortWidth = Dom.getClientWidth(),
3443 viewPortHeight = Dom.getClientHeight(),
3444 elementWidth = this.element.offsetWidth,
3445 elementHeight = this.element.offsetHeight,
3446 x = (viewPortWidth / 2) - (elementWidth / 2) + scrollX,
3447 y = (viewPortHeight / 2) - (elementHeight / 2) + scrollY;
3449 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3451 this.cfg.refireEvent("iframe");
3456 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3457 * Panel's position in the DOM. This is primarily used to update
3458 * position information during drag & drop.
3459 * @method syncPosition
3461 syncPosition: function () {
3463 var pos = Dom.getXY(this.element);
3465 this.cfg.setProperty("x", pos[0], true);
3466 this.cfg.setProperty("y", pos[1], true);
3467 this.cfg.setProperty("xy", pos, true);
3472 * Event handler fired when the resize monitor element is resized.
3473 * @method onDomResize
3474 * @param {DOMEvent} e The resize DOM event
3475 * @param {Object} obj The scope object
3477 onDomResize: function (e, obj) {
3481 Overlay.superclass.onDomResize.call(this, e, obj);
3483 setTimeout(function () {
3485 me.cfg.refireEvent("iframe");
3486 me.cfg.refireEvent("context");
3492 * Places the Overlay on top of all other instances of
3493 * YAHOO.widget.Overlay.
3494 * @method bringToTop
3496 bringToTop: function() {
3499 oElement = this.element;
3501 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
3503 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
3505 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
3507 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ?
3508 0 : parseInt(sZIndex1, 10),
3510 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ?
3511 0 : parseInt(sZIndex2, 10);
3513 if (nZIndex1 > nZIndex2) {
3517 } else if (nZIndex1 < nZIndex2) {
3529 function isOverlayElement(p_oElement) {
3531 var oOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
3532 Panel = YAHOO.widget.Panel;
3534 if (oOverlay && !Dom.isAncestor(oElement, oOverlay)) {
3536 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
3538 aOverlays[aOverlays.length] = p_oElement.parentNode;
3543 aOverlays[aOverlays.length] = p_oElement;
3551 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
3553 aOverlays.sort(compareZIndexDesc);
3555 var oTopOverlay = aOverlays[0],
3560 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
3562 if (!isNaN(nTopZIndex) && oTopOverlay != oElement) {
3564 this.cfg.setProperty("zindex",
3565 (parseInt(nTopZIndex, 10) + 2));
3574 * Removes the Overlay element from the DOM and sets all child
3578 destroy: function () {
3582 this.iframe.parentNode.removeChild(this.iframe);
3588 Overlay.windowResizeEvent.unsubscribe(
3589 this.doCenterOnDOMEvent, this);
3591 Overlay.windowScrollEvent.unsubscribe(
3592 this.doCenterOnDOMEvent, this);
3594 Overlay.superclass.destroy.call(this);
3598 * Returns a String representation of the object.
3600 * @return {String} The string representation of the Overlay.
3602 toString: function () {
3604 return "Overlay " + this.id;
3614 * OverlayManager is used for maintaining the focus status of
3615 * multiple Overlays.
3616 * @namespace YAHOO.widget
3617 * @namespace YAHOO.widget
3618 * @class OverlayManager
3620 * @param {Array} overlays Optional. A collection of Overlays to register
3622 * @param {Object} userConfig The object literal representing the user
3623 * configuration of the OverlayManager
3625 YAHOO.widget.OverlayManager = function (userConfig) {
3627 this.init(userConfig);
3632 var Overlay = YAHOO.widget.Overlay,
3633 Event = YAHOO.util.Event,
3634 Dom = YAHOO.util.Dom,
3635 Config = YAHOO.util.Config,
3636 CustomEvent = YAHOO.util.CustomEvent,
3637 OverlayManager = YAHOO.widget.OverlayManager;
3641 * The CSS class representing a focused Overlay
3642 * @property OverlayManager.CSS_FOCUSED
3647 OverlayManager.CSS_FOCUSED = "focused";
3649 OverlayManager.prototype = {
3652 * The class's constructor function
3653 * @property contructor
3656 constructor: OverlayManager,
3659 * The array of Overlays that are currently registered
3660 * @property overlays
3661 * @type YAHOO.widget.Overlay[]
3666 * Initializes the default configuration of the OverlayManager
3667 * @method initDefaultConfig
3669 initDefaultConfig: function () {
3672 * The collection of registered Overlays in use by
3673 * the OverlayManager
3675 * @type YAHOO.widget.Overlay[]
3678 this.cfg.addProperty("overlays", { suppressEvent: true } );
3681 * The default DOM event that should be used to focus an Overlay
3682 * @config focusevent
3684 * @default "mousedown"
3686 this.cfg.addProperty("focusevent", { value: "mousedown" } );
3691 * Initializes the OverlayManager
3693 * @param {Overlay[]} overlays Optional. A collection of Overlays to
3694 * register with the manager.
3695 * @param {Object} userConfig The object literal representing the user
3696 * configuration of the OverlayManager
3698 init: function (userConfig) {
3701 * The OverlayManager's Config object used for monitoring
3702 * configuration properties.
3706 this.cfg = new Config(this);
3708 this.initDefaultConfig();
3711 this.cfg.applyConfig(userConfig, true);
3713 this.cfg.fireQueue();
3716 * The currently activated Overlay
3717 * @property activeOverlay
3719 * @type YAHOO.widget.Overlay
3721 var activeOverlay = null;
3724 * Returns the currently focused Overlay
3726 * @return {Overlay} The currently focused Overlay
3728 this.getActive = function () {
3729 return activeOverlay;
3733 * Focuses the specified Overlay
3735 * @param {Overlay} overlay The Overlay to focus
3736 * @param {String} overlay The id of the Overlay to focus
3738 this.focus = function (overlay) {
3740 var o = this.find(overlay);
3744 if (activeOverlay != o) {
3746 if (activeOverlay) {
3748 activeOverlay.blur();
3756 Dom.addClass(activeOverlay.element,
3757 OverlayManager.CSS_FOCUSED);
3759 o.focusEvent.fire();
3768 * Removes the specified Overlay from the manager
3770 * @param {Overlay} overlay The Overlay to remove
3771 * @param {String} overlay The id of the Overlay to remove
3773 this.remove = function (overlay) {
3775 var o = this.find(overlay),
3780 if (activeOverlay == o) {
3782 activeOverlay = null;
3786 originalZ = Dom.getStyle(o.element, "zIndex");
3788 o.cfg.setProperty("zIndex", -1000, true);
3790 this.overlays.sort(this.compareZIndexDesc);
3793 this.overlays.slice(0, (this.overlays.length - 1));
3795 o.hideEvent.unsubscribe(o.blur);
3796 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
3800 Event.removeListener(o.element,
3801 this.cfg.getProperty("focusevent"),
3802 this._onOverlayElementFocus);
3806 o.cfg.setProperty("zIndex", originalZ, true);
3807 o.cfg.setProperty("manager", null);
3809 o.focusEvent.unsubscribeAll();
3810 o.blurEvent.unsubscribeAll();
3812 o.focusEvent = null;
3822 * Removes focus from all registered Overlays in the manager
3825 this.blurAll = function () {
3827 var nOverlays = this.overlays.length,
3830 if (nOverlays > 0) {
3836 this.overlays[i].blur();
3846 this._onOverlayBlur = function (p_sType, p_aArgs) {
3848 activeOverlay = null;
3853 var overlays = this.cfg.getProperty("overlays");
3855 if (! this.overlays) {
3860 this.register(overlays);
3861 this.overlays.sort(this.compareZIndexDesc);
3867 * @method _onOverlayElementFocus
3868 * @description Event handler for the DOM event that is used to focus
3869 * the Overlay instance as specified by the "focusevent"
3870 * configuration property.
3872 * @param {Event} p_oEvent Object representing the DOM event
3873 * object passed back by the event utility (Event).
3875 _onOverlayElementFocus: function (p_oEvent) {
3877 var oTarget = Event.getTarget(p_oEvent),
3878 oClose = this.close;
3881 if (oClose && (oTarget == oClose ||
3882 Dom.isAncestor(oClose, oTarget))) {
3897 * @method _onOverlayDestroy
3898 * @description "destroy" event handler for the Overlay.
3900 * @param {String} p_sType String representing the name of the event
3902 * @param {Array} p_aArgs Array of arguments sent when the event
3904 * @param {Overlay} p_oOverlay Object representing the menu that
3907 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
3909 this.remove(p_oOverlay);
3914 * Registers an Overlay or an array of Overlays with the manager. Upon
3915 * registration, the Overlay receives functions for focus and blur,
3916 * along with CustomEvents for each.
3918 * @param {Overlay} overlay An Overlay to register with the manager.
3919 * @param {Overlay[]} overlay An array of Overlays to register with
3921 * @return {Boolean} True if any Overlays are registered.
3923 register: function (overlay) {
3931 if (overlay instanceof Overlay) {
3933 overlay.cfg.addProperty("manager", { value: this } );
3935 overlay.focusEvent = overlay.createEvent("focus");
3936 overlay.focusEvent.signature = CustomEvent.LIST;
3938 overlay.blurEvent = overlay.createEvent("blur");
3939 overlay.blurEvent.signature = CustomEvent.LIST;
3941 overlay.focus = function () {
3945 overlay.blur = function () {
3947 if (mgr.getActive() == this) {
3949 Dom.removeClass(this.element,
3950 OverlayManager.CSS_FOCUSED);
3952 this.blurEvent.fire();
3958 overlay.blurEvent.subscribe(mgr._onOverlayBlur);
3960 overlay.hideEvent.subscribe(overlay.blur);
3962 overlay.destroyEvent.subscribe(this._onOverlayDestroy,
3965 Event.on(overlay.element, this.cfg.getProperty("focusevent"),
3966 this._onOverlayElementFocus, null, overlay);
3968 zIndex = Dom.getStyle(overlay.element, "zIndex");
3970 if (!isNaN(zIndex)) {
3972 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
3976 overlay.cfg.setProperty("zIndex", 0);
3981 this.overlays.push(overlay);
3983 this.bringToTop(overlay);
3987 } else if (overlay instanceof Array) {
3990 nOverlays = overlay.length;
3992 for (i = 0; i < nOverlays; i++) {
3994 if (this.register(overlay[i])) {
4016 * Places the specified Overlay instance on top of all other
4017 * Overlay instances.
4018 * @method bringToTop
4019 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4021 * @param {String} p_oOverlay String representing the id of an
4024 bringToTop: function (p_oOverlay) {
4026 var oOverlay = this.find(p_oOverlay),
4033 aOverlays = this.overlays;
4035 aOverlays.sort(this.compareZIndexDesc);
4037 oTopOverlay = aOverlays[0];
4041 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4043 if (!isNaN(nTopZIndex) && oTopOverlay != oOverlay) {
4045 oOverlay.cfg.setProperty("zIndex",
4046 (parseInt(nTopZIndex, 10) + 2));
4050 aOverlays.sort(this.compareZIndexDesc);
4059 * Attempts to locate an Overlay by instance or ID.
4061 * @param {Overlay} overlay An Overlay to locate within the manager
4062 * @param {String} overlay An Overlay id to locate within the manager
4063 * @return {Overlay} The requested Overlay, if found, or null if it
4064 * cannot be located.
4066 find: function (overlay) {
4068 var aOverlays = this.overlays,
4069 nOverlays = aOverlays.length,
4072 if (nOverlays > 0) {
4076 if (overlay instanceof Overlay) {
4080 if (aOverlays[i] == overlay) {
4082 return aOverlays[i];
4089 } else if (typeof overlay == "string") {
4093 if (aOverlays[i].id == overlay) {
4095 return aOverlays[i];
4111 * Used for sorting the manager's Overlays by z-index.
4112 * @method compareZIndexDesc
4114 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4115 * fall in the stacking order.
4117 compareZIndexDesc: function (o1, o2) {
4119 var zIndex1 = o1.cfg.getProperty("zIndex"),
4120 zIndex2 = o2.cfg.getProperty("zIndex");
4122 if (zIndex1 > zIndex2) {
4124 } else if (zIndex1 < zIndex2) {
4132 * Shows all Overlays in the manager.
4135 showAll: function () {
4137 var aOverlays = this.overlays,
4138 nOverlays = aOverlays.length,
4141 if (nOverlays > 0) {
4147 aOverlays[i].show();
4157 * Hides all Overlays in the manager.
4160 hideAll: function () {
4162 var aOverlays = this.overlays,
4163 nOverlays = aOverlays.length,
4166 if (nOverlays > 0) {
4172 aOverlays[i].hide();
4182 * Returns a string representation of the object.
4184 * @return {String} The string representation of the OverlayManager
4186 toString: function () {
4187 return "OverlayManager";
4196 * ContainerEffect encapsulates animation transitions that are executed when
4197 * an Overlay is shown or hidden.
4198 * @namespace YAHOO.widget
4199 * @class ContainerEffect
4201 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
4202 * should be associated with
4203 * @param {Object} attrIn The object literal representing the animation
4204 * arguments to be used for the animate-in transition. The arguments for
4205 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4206 * duration(Number), and method(i.e. Easing.easeIn).
4207 * @param {Object} attrOut The object literal representing the animation
4208 * arguments to be used for the animate-out transition. The arguments for
4209 * this literal are: attributes(object, see YAHOO.util.Anim for description),
4210 * duration(Number), and method(i.e. Easing.easeIn).
4211 * @param {HTMLElement} targetElement Optional. The target element that
4212 * should be animated during the transition. Defaults to overlay.element.
4213 * @param {class} Optional. The animation class to instantiate. Defaults to
4214 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4216 YAHOO.widget.ContainerEffect =
4218 function (overlay, attrIn, attrOut, targetElement, animClass) {
4221 animClass = YAHOO.util.Anim;
4225 * The overlay to animate
4227 * @type YAHOO.widget.Overlay
4229 this.overlay = overlay;
4232 * The animation attributes to use when transitioning into view
4236 this.attrIn = attrIn;
4239 * The animation attributes to use when transitioning out of view
4243 this.attrOut = attrOut;
4246 * The target element to be animated
4247 * @property targetElement
4250 this.targetElement = targetElement || overlay.element;
4253 * The animation class to use for animating the overlay
4254 * @property animClass
4257 this.animClass = animClass;
4262 var Dom = YAHOO.util.Dom,
4263 CustomEvent = YAHOO.util.CustomEvent,
4264 Easing = YAHOO.util.Easing,
4265 ContainerEffect = YAHOO.widget.ContainerEffect;
4269 * A pre-configured ContainerEffect instance that can be used for fading
4270 * an overlay in and out.
4273 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4274 * @param {Number} dur The duration of the animation
4275 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4277 ContainerEffect.FADE = function (overlay, dur) {
4279 var fade = new ContainerEffect(overlay,
4281 { attributes: { opacity: { from: 0, to: 1 } },
4283 method: Easing.easeIn },
4285 { attributes: { opacity: { to: 0 } },
4287 method: Easing.easeOut },
4292 fade.handleStartAnimateIn = function (type,args,obj) {
4293 Dom.addClass(obj.overlay.element, "hide-select");
4295 if (! obj.overlay.underlay) {
4296 obj.overlay.cfg.refireEvent("underlay");
4299 if (obj.overlay.underlay) {
4301 obj.initialUnderlayOpacity =
4302 Dom.getStyle(obj.overlay.underlay, "opacity");
4304 obj.overlay.underlay.style.filter = null;
4308 Dom.setStyle(obj.overlay.element, "visibility", "visible");
4309 Dom.setStyle(obj.overlay.element, "opacity", 0);
4313 fade.handleCompleteAnimateIn = function (type,args,obj) {
4314 Dom.removeClass(obj.overlay.element, "hide-select");
4316 if (obj.overlay.element.style.filter) {
4317 obj.overlay.element.style.filter = null;
4320 if (obj.overlay.underlay) {
4321 Dom.setStyle(obj.overlay.underlay, "opacity",
4322 obj.initialUnderlayOpacity);
4325 obj.overlay.cfg.refireEvent("iframe");
4326 obj.animateInCompleteEvent.fire();
4330 fade.handleStartAnimateOut = function (type, args, obj) {
4331 Dom.addClass(obj.overlay.element, "hide-select");
4333 if (obj.overlay.underlay) {
4334 obj.overlay.underlay.style.filter = null;
4339 fade.handleCompleteAnimateOut = function (type, args, obj) {
4340 Dom.removeClass(obj.overlay.element, "hide-select");
4341 if (obj.overlay.element.style.filter) {
4342 obj.overlay.element.style.filter = null;
4344 Dom.setStyle(obj.overlay.element, "visibility", "hidden");
4345 Dom.setStyle(obj.overlay.element, "opacity", 1);
4347 obj.overlay.cfg.refireEvent("iframe");
4349 obj.animateOutCompleteEvent.fire();
4358 * A pre-configured ContainerEffect instance that can be used for sliding an
4359 * overlay in and out.
4362 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4363 * @param {Number} dur The duration of the animation
4364 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4366 ContainerEffect.SLIDE = function (overlay, dur) {
4368 var x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
4370 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
4372 clientWidth = Dom.getClientWidth(),
4374 offsetWidth = overlay.element.offsetWidth,
4376 slide = new ContainerEffect(overlay,
4378 { attributes: { points: { to: [x, y] } },
4380 method: Easing.easeIn },
4382 { attributes: { points: { to: [(clientWidth + 25), y] } },
4384 method: Easing.easeOut },
4386 overlay.element, YAHOO.util.Motion);
4389 slide.handleStartAnimateIn = function (type,args,obj) {
4390 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
4391 obj.overlay.element.style.top = y + "px";
4394 slide.handleTweenAnimateIn = function (type, args, obj) {
4396 var pos = Dom.getXY(obj.overlay.element),
4400 if (Dom.getStyle(obj.overlay.element, "visibility") ==
4401 "hidden" && currentX < x) {
4403 Dom.setStyle(obj.overlay.element, "visibility", "visible");
4407 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
4408 obj.overlay.cfg.refireEvent("iframe");
4411 slide.handleCompleteAnimateIn = function (type, args, obj) {
4412 obj.overlay.cfg.setProperty("xy", [x, y], true);
4415 obj.overlay.cfg.refireEvent("iframe");
4416 obj.animateInCompleteEvent.fire();
4419 slide.handleStartAnimateOut = function (type, args, obj) {
4421 var vw = Dom.getViewportWidth(),
4422 pos = Dom.getXY(obj.overlay.element),
4424 currentTo = obj.animOut.attributes.points.to;
4426 obj.animOut.attributes.points.to = [(vw + 25), yso];
4430 slide.handleTweenAnimateOut = function (type, args, obj) {
4432 var pos = Dom.getXY(obj.overlay.element),
4436 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
4437 obj.overlay.cfg.refireEvent("iframe");
4440 slide.handleCompleteAnimateOut = function (type, args, obj) {
4441 Dom.setStyle(obj.overlay.element, "visibility", "hidden");
4443 obj.overlay.cfg.setProperty("xy", [x, y]);
4444 obj.animateOutCompleteEvent.fire();
4451 ContainerEffect.prototype = {
4454 * Initializes the animation classes and events.
4459 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
4460 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
4462 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
4463 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
4465 this.animateInCompleteEvent = this.createEvent("animateInComplete");
4466 this.animateInCompleteEvent.signature = CustomEvent.LIST;
4468 this.animateOutCompleteEvent =
4469 this.createEvent("animateOutComplete");
4470 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
4472 this.animIn = new this.animClass(this.targetElement,
4473 this.attrIn.attributes, this.attrIn.duration,
4474 this.attrIn.method);
4476 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
4477 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
4479 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
4482 this.animOut = new this.animClass(this.targetElement,
4483 this.attrOut.attributes, this.attrOut.duration,
4484 this.attrOut.method);
4486 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
4487 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
4488 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
4494 * Triggers the in-animation.
4497 animateIn: function () {
4498 this.beforeAnimateInEvent.fire();
4499 this.animIn.animate();
4503 * Triggers the out-animation.
4504 * @method animateOut
4506 animateOut: function () {
4507 this.beforeAnimateOutEvent.fire();
4508 this.animOut.animate();
4512 * The default onStart handler for the in-animation.
4513 * @method handleStartAnimateIn
4514 * @param {String} type The CustomEvent type
4515 * @param {Object[]} args The CustomEvent arguments
4516 * @param {Object} obj The scope object
4518 handleStartAnimateIn: function (type, args, obj) { },
4521 * The default onTween handler for the in-animation.
4522 * @method handleTweenAnimateIn
4523 * @param {String} type The CustomEvent type
4524 * @param {Object[]} args The CustomEvent arguments
4525 * @param {Object} obj The scope object
4527 handleTweenAnimateIn: function (type, args, obj) { },
4530 * The default onComplete handler for the in-animation.
4531 * @method handleCompleteAnimateIn
4532 * @param {String} type The CustomEvent type
4533 * @param {Object[]} args The CustomEvent arguments
4534 * @param {Object} obj The scope object
4536 handleCompleteAnimateIn: function (type, args, obj) { },
4539 * The default onStart handler for the out-animation.
4540 * @method handleStartAnimateOut
4541 * @param {String} type The CustomEvent type
4542 * @param {Object[]} args The CustomEvent arguments
4543 * @param {Object} obj The scope object
4545 handleStartAnimateOut: function (type, args, obj) { },
4548 * The default onTween handler for the out-animation.
4549 * @method handleTweenAnimateOut
4550 * @param {String} type The CustomEvent type
4551 * @param {Object[]} args The CustomEvent arguments
4552 * @param {Object} obj The scope object
4554 handleTweenAnimateOut: function (type, args, obj) { },
4557 * The default onComplete handler for the out-animation.
4558 * @method handleCompleteAnimateOut
4559 * @param {String} type The CustomEvent type
4560 * @param {Object[]} args The CustomEvent arguments
4561 * @param {Object} obj The scope object
4563 handleCompleteAnimateOut: function (type, args, obj) { },
4566 * Returns a string representation of the object.
4568 * @return {String} The string representation of the ContainerEffect
4570 toString: function () {
4571 var output = "ContainerEffect";
4573 output += " [" + this.overlay.toString() + "]";
4580 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
4583 YAHOO.register("container_core", YAHOO.widget.Module, {version: "2.3.0", build: "442"});