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 * Tooltip is an implementation of Overlay that behaves like an OS tooltip,
4208 * displaying when the user mouses over a particular element, and
4209 * disappearing on mouse out.
4210 * @namespace YAHOO.widget
4212 * @extends YAHOO.widget.Overlay
4214 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4215 * @param {HTMLElement} el The element representing the Tooltip
4216 * @param {Object} userConfig The configuration object literal containing
4217 * the configuration that should be set for this Overlay. See configuration
4218 * documentation for more details.
4220 YAHOO.widget.Tooltip = function (el, userConfig) {
4222 YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4227 var Lang = YAHOO.lang,
4228 Event = YAHOO.util.Event,
4229 Dom = YAHOO.util.Dom,
4230 Tooltip = YAHOO.widget.Tooltip,
4235 * Constant representing the Tooltip's configuration properties
4236 * @property DEFAULT_CONFIG
4243 "PREVENT_OVERLAP": {
4244 key: "preventoverlap",
4246 validator: Lang.isBoolean,
4247 supercedes: ["x", "y", "xy"]
4253 validator: Lang.isNumber
4256 "AUTO_DISMISS_DELAY": {
4257 key: "autodismissdelay",
4259 validator: Lang.isNumber
4265 validator: Lang.isNumber
4281 * Constant representing the Tooltip CSS class
4282 * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4287 Tooltip.CSS_TOOLTIP = "yui-tt";
4291 "hide" event handler that sets a Tooltip instance's "width"
4292 configuration property back to its original value before
4293 "setWidthToOffsetWidth" was called.
4296 function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
4298 var sOriginalWidth = p_oObject[0],
4299 sNewWidth = p_oObject[1],
4301 sCurrentWidth = oConfig.getProperty("width");
4303 if (sCurrentWidth == sNewWidth) {
4305 oConfig.setProperty("width", sOriginalWidth);
4309 this.unsubscribe("hide", this._onHide, p_oObject);
4314 "beforeShow" event handler that sets a Tooltip instance's "width"
4315 configuration property to the value of its root HTML
4316 elements's offsetWidth
4319 function setWidthToOffsetWidth(p_sType, p_aArgs) {
4321 var oBody = document.body,
4323 sOriginalWidth = oConfig.getProperty("width"),
4328 if ((!sOriginalWidth || sOriginalWidth == "auto") &&
4329 (oConfig.getProperty("container") != oBody ||
4330 oConfig.getProperty("x") >= Dom.getViewportWidth() ||
4331 oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4333 oClone = this.element.cloneNode(true);
4334 oClone.style.visibility = "hidden";
4335 oClone.style.top = "0px";
4336 oClone.style.left = "0px";
4338 oBody.appendChild(oClone);
4340 sNewWidth = (oClone.offsetWidth + "px");
4342 oBody.removeChild(oClone);
4346 oConfig.setProperty("width", sNewWidth);
4348 oConfig.refireEvent("xy");
4350 this.subscribe("hide", restoreOriginalWidth,
4351 [(sOriginalWidth || ""), sNewWidth]);
4358 // "onDOMReady" that renders the ToolTip
4360 function onDOMReady(p_sType, p_aArgs, p_oObject) {
4362 this.render(p_oObject);
4367 // "init" event handler that automatically renders the Tooltip
4371 Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4376 YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
4379 * The Tooltip initialization method. This method is automatically
4380 * called by the constructor. A Tooltip is automatically rendered by
4381 * the init method, and it also is set to be invisible by default,
4382 * and constrained to viewport by default as well.
4384 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4385 * @param {HTMLElement} el The element representing the Tooltip
4386 * @param {Object} userConfig The configuration object literal
4387 * containing the configuration that should be set for this Tooltip.
4388 * See configuration documentation for more details.
4390 init: function (el, userConfig) {
4392 this.logger = new YAHOO.widget.LogWriter(this.toString());
4394 Tooltip.superclass.init.call(this, el);
4396 this.beforeInitEvent.fire(Tooltip);
4398 Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
4402 this.cfg.applyConfig(userConfig, true);
4406 this.cfg.queueProperty("visible", false);
4407 this.cfg.queueProperty("constraintoviewport", true);
4411 this.subscribe("beforeShow", setWidthToOffsetWidth);
4412 this.subscribe("init", onInit);
4413 this.subscribe("render", this.onRender);
4415 this.initEvent.fire(Tooltip);
4420 * Initializes the class's configurable properties which can be
4421 * changed using the Overlay's Config object (cfg).
4422 * @method initDefaultConfig
4424 initDefaultConfig: function () {
4426 Tooltip.superclass.initDefaultConfig.call(this);
4429 * Specifies whether the Tooltip should be kept from overlapping
4430 * its context element.
4431 * @config preventoverlap
4435 this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
4436 value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
4437 validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
4438 supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
4442 * The number of milliseconds to wait before showing a Tooltip
4448 this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
4449 handler: this.configShowDelay,
4451 validator: DEFAULT_CONFIG.SHOW_DELAY.validator
4455 * The number of milliseconds to wait before automatically
4456 * dismissing a Tooltip after the mouse has been resting on the
4458 * @config autodismissdelay
4462 this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
4463 handler: this.configAutoDismissDelay,
4464 value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
4465 validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
4469 * The number of milliseconds to wait before hiding a Tooltip
4475 this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
4476 handler: this.configHideDelay,
4477 value: DEFAULT_CONFIG.HIDE_DELAY.value,
4478 validator: DEFAULT_CONFIG.HIDE_DELAY.validator
4482 * Specifies the Tooltip's text.
4487 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
4488 handler: this.configText,
4489 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
4493 * Specifies the container element that the Tooltip's markup
4494 * should be rendered into.
4496 * @type HTMLElement/String
4497 * @default document.body
4499 this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
4500 handler: this.configContainer,
4501 value: document.body
4505 * Specifies the element or elements that the Tooltip should be
4506 * anchored to on mouseover.
4508 * @type HTMLElement[]/String[]
4513 * String representing the width of the Tooltip. <em>Please note:
4514 * </em> As of version 2.3 if either no value or a value of "auto"
4515 * is specified, and the Toolip's "container" configuration property
4516 * is set to something other than <code>document.body</code> or
4517 * its "context" element resides outside the immediately visible
4518 * portion of the document, the width of the Tooltip will be
4519 * calculated based on the offsetWidth of its root HTML and set just
4520 * before it is made visible. The original value will be
4521 * restored when the Tooltip is hidden. This ensures the Tooltip is
4522 * rendered at a usable width. For more information see
4523 * SourceForge bug #1685496 and SourceForge
4532 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
4535 * The default event handler fired when the "text" property is changed.
4536 * @method configText
4537 * @param {String} type The CustomEvent type (usually the property name)
4538 * @param {Object[]} args The CustomEvent arguments. For configuration
4539 * handlers, args[0] will equal the newly applied value for the property.
4540 * @param {Object} obj The scope object. For configuration handlers,
4541 * this will usually equal the owner.
4543 configText: function (type, args, obj) {
4551 * The default event handler fired when the "container" property
4553 * @method configContainer
4554 * @param {String} type The CustomEvent type (usually the property name)
4555 * @param {Object[]} args The CustomEvent arguments. For
4556 * configuration handlers, args[0] will equal the newly applied value
4558 * @param {Object} obj The scope object. For configuration handlers,
4559 * this will usually equal the owner.
4561 configContainer: function (type, args, obj) {
4563 var container = args[0];
4565 if (typeof container == 'string') {
4567 this.cfg.setProperty("container",
4568 document.getElementById(container), true);
4575 * @method _removeEventListeners
4576 * @description Removes all of the DOM event handlers from the HTML
4577 * element(s) that trigger the display of the tooltip.
4580 _removeEventListeners: function () {
4582 var aElements = this._context,
4590 nElements = aElements.length;
4592 if (nElements > 0) {
4598 oElement = aElements[i];
4600 Event.removeListener(oElement, "mouseover",
4601 this.onContextMouseOver);
4603 Event.removeListener(oElement, "mousemove",
4604 this.onContextMouseMove);
4606 Event.removeListener(oElement, "mouseout",
4607 this.onContextMouseOut);
4619 * The default event handler fired when the "context" property
4621 * @method configContext
4622 * @param {String} type The CustomEvent type (usually the property name)
4623 * @param {Object[]} args The CustomEvent arguments. For configuration
4624 * handlers, args[0] will equal the newly applied value for the property.
4625 * @param {Object} obj The scope object. For configuration handlers,
4626 * this will usually equal the owner.
4628 configContext: function (type, args, obj) {
4630 var context = args[0],
4639 // Normalize parameter into an array
4640 if (! (context instanceof Array)) {
4642 if (typeof context == "string") {
4644 this.cfg.setProperty("context",
4645 [document.getElementById(context)], true);
4647 } else { // Assuming this is an element
4649 this.cfg.setProperty("context", [context], true);
4653 context = this.cfg.getProperty("context");
4658 // Remove any existing mouseover/mouseout listeners
4659 this._removeEventListeners();
4661 // Add mouseover/mouseout listeners to context elements
4662 this._context = context;
4664 aElements = this._context;
4668 nElements = aElements.length;
4670 if (nElements > 0) {
4676 oElement = aElements[i];
4678 Event.on(oElement, "mouseover",
4679 this.onContextMouseOver, this);
4681 Event.on(oElement, "mousemove",
4682 this.onContextMouseMove, this);
4684 Event.on(oElement, "mouseout",
4685 this.onContextMouseOut, this);
4697 // END BUILT-IN PROPERTY EVENT HANDLERS //
4699 // BEGIN BUILT-IN DOM EVENT HANDLERS //
4702 * The default event handler fired when the user moves the mouse while
4703 * over the context element.
4704 * @method onContextMouseMove
4705 * @param {DOMEvent} e The current DOM event
4706 * @param {Object} obj The object argument
4708 onContextMouseMove: function (e, obj) {
4709 obj.pageX = Event.getPageX(e);
4710 obj.pageY = Event.getPageY(e);
4715 * The default event handler fired when the user mouses over the
4717 * @method onContextMouseOver
4718 * @param {DOMEvent} e The current DOM event
4719 * @param {Object} obj The object argument
4721 onContextMouseOver: function (e, obj) {
4725 if (obj.hideProcId) {
4727 clearTimeout(obj.hideProcId);
4729 obj.logger.log("Clearing hide timer: " +
4730 obj.hideProcId, "time");
4732 obj.hideProcId = null;
4736 Event.on(context, "mousemove", obj.onContextMouseMove, obj);
4738 if (context.title) {
4739 obj._tempTitle = context.title;
4744 * The unique process ID associated with the thread responsible
4745 * for showing the Tooltip.
4748 obj.showProcId = obj.doShow(e, context);
4749 obj.logger.log("Setting show tooltip timeout: " +
4750 obj.showProcId, "time");
4755 * The default event handler fired when the user mouses out of
4756 * the context element.
4757 * @method onContextMouseOut
4758 * @param {DOMEvent} e The current DOM event
4759 * @param {Object} obj The object argument
4761 onContextMouseOut: function (e, obj) {
4764 if (obj._tempTitle) {
4765 el.title = obj._tempTitle;
4766 obj._tempTitle = null;
4769 if (obj.showProcId) {
4770 clearTimeout(obj.showProcId);
4771 obj.logger.log("Clearing show timer: " +
4772 obj.showProcId, "time");
4773 obj.showProcId = null;
4776 if (obj.hideProcId) {
4777 clearTimeout(obj.hideProcId);
4778 obj.logger.log("Clearing hide timer: " +
4779 obj.hideProcId, "time");
4780 obj.hideProcId = null;
4784 obj.hideProcId = setTimeout(function () {
4787 }, obj.cfg.getProperty("hidedelay"));
4791 // END BUILT-IN DOM EVENT HANDLERS //
4794 * Processes the showing of the Tooltip by setting the timeout delay
4795 * and offset of the Tooltip.
4797 * @param {DOMEvent} e The current DOM event
4798 * @return {Number} The process ID of the timeout function associated
4801 doShow: function (e, context) {
4806 if (YAHOO.env.ua.opera && context.tagName &&
4807 context.tagName.toUpperCase() == "A") {
4813 return setTimeout(function () {
4815 if (me._tempTitle) {
4816 me.setBody(me._tempTitle);
4818 me.cfg.refireEvent("text");
4821 me.logger.log("Show tooltip", "time");
4822 me.moveTo(me.pageX, me.pageY + yOffset);
4824 if (me.cfg.getProperty("preventoverlap")) {
4825 me.preventOverlap(me.pageX, me.pageY);
4828 Event.removeListener(context, "mousemove",
4829 me.onContextMouseMove);
4832 me.hideProcId = me.doHide();
4834 me.logger.log("Hide tooltip time active: " +
4835 me.hideProcId, "time");
4837 }, this.cfg.getProperty("showdelay"));
4842 * Sets the timeout for the auto-dismiss delay, which by default is 5
4843 * seconds, meaning that a tooltip will automatically dismiss itself
4844 * after 5 seconds of being displayed.
4847 doHide: function () {
4851 me.logger.log("Setting hide tooltip timeout", "time");
4853 return setTimeout(function () {
4855 me.logger.log("Hide tooltip", "time");
4858 }, this.cfg.getProperty("autodismissdelay"));
4863 * Fired when the Tooltip is moved, this event handler is used to
4864 * prevent the Tooltip from overlapping with its context element.
4865 * @method preventOverlay
4866 * @param {Number} pageX The x coordinate position of the mouse pointer
4867 * @param {Number} pageY The y coordinate position of the mouse pointer
4869 preventOverlap: function (pageX, pageY) {
4871 var height = this.element.offsetHeight,
4872 mousePoint = new YAHOO.util.Point(pageX, pageY),
4873 elementRegion = Dom.getRegion(this.element);
4875 elementRegion.top -= 5;
4876 elementRegion.left -= 5;
4877 elementRegion.right += 5;
4878 elementRegion.bottom += 5;
4880 this.logger.log("context " + elementRegion, "ttip");
4881 this.logger.log("mouse " + mousePoint, "ttip");
4883 if (elementRegion.contains(mousePoint)) {
4884 this.logger.log("OVERLAP", "warn");
4885 this.cfg.setProperty("y", (pageY - height - 5));
4892 * @description "render" event handler for the Tooltip.
4893 * @param {String} p_sType String representing the name of the event
4895 * @param {Array} p_aArgs Array of arguments sent when the event
4898 onRender: function (p_sType, p_aArgs) {
4900 function sizeShadow() {
4902 var oElement = this.element,
4903 oShadow = this._shadow;
4907 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
4908 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
4915 function addShadowVisibleClass() {
4917 Dom.addClass(this._shadow, "yui-tt-shadow-visible");
4922 function removeShadowVisibleClass() {
4924 Dom.removeClass(this._shadow, "yui-tt-shadow-visible");
4929 function createShadow() {
4931 var oShadow = this._shadow,
4939 oElement = this.element;
4940 Module = YAHOO.widget.Module;
4941 nIE = YAHOO.env.ua.ie;
4944 if (!m_oShadowTemplate) {
4946 m_oShadowTemplate = document.createElement("div");
4947 m_oShadowTemplate.className = "yui-tt-shadow";
4951 oShadow = m_oShadowTemplate.cloneNode(false);
4953 oElement.appendChild(oShadow);
4955 this._shadow = oShadow;
4957 addShadowVisibleClass.call(this);
4959 this.subscribe("beforeShow", addShadowVisibleClass);
4960 this.subscribe("beforeHide", removeShadowVisibleClass);
4963 (nIE == 7 && document.compatMode == "BackCompat")) {
4965 window.setTimeout(function () {
4967 sizeShadow.call(me);
4971 this.cfg.subscribeToConfigEvent("width", sizeShadow);
4972 this.cfg.subscribeToConfigEvent("height", sizeShadow);
4973 this.subscribe("changeContent", sizeShadow);
4975 Module.textResizeEvent.subscribe(sizeShadow,
4978 this.subscribe("destroy", function () {
4980 Module.textResizeEvent.unsubscribe(sizeShadow,
4992 function onBeforeShow() {
4994 createShadow.call(this);
4996 this.unsubscribe("beforeShow", onBeforeShow);
5001 if (this.cfg.getProperty("visible")) {
5003 createShadow.call(this);
5008 this.subscribe("beforeShow", onBeforeShow);
5015 * Removes the Tooltip element from the DOM and sets all child
5019 destroy: function () {
5021 // Remove any existing mouseover/mouseout listeners
5022 this._removeEventListeners();
5024 Tooltip.superclass.destroy.call(this);
5029 * Returns a string representation of the object.
5031 * @return {String} The string representation of the Tooltip
5033 toString: function () {
5034 return "Tooltip " + this.id;
5043 * Panel is an implementation of Overlay that behaves like an OS window,
5044 * with a draggable header and an optional close icon at the top right.
5045 * @namespace YAHOO.widget
5049 * @param {String} el The element ID representing the Panel <em>OR</em>
5050 * @param {HTMLElement} el The element representing the Panel
5051 * @param {Object} userConfig The configuration object literal containing
5052 * the configuration that should be set for this Panel. See configuration
5053 * documentation for more details.
5055 YAHOO.widget.Panel = function (el, userConfig) {
5057 YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5062 var Lang = YAHOO.lang,
5064 Dom = YAHOO.util.Dom,
5065 Event = YAHOO.util.Event,
5066 Overlay = YAHOO.widget.Overlay,
5067 CustomEvent = YAHOO.util.CustomEvent,
5068 Config = YAHOO.util.Config,
5069 Panel = YAHOO.widget.Panel,
5072 m_oUnderlayTemplate,
5073 m_oCloseIconTemplate,
5076 * Constant representing the name of the Panel's events
5077 * @property EVENT_TYPES
5084 "SHOW_MASK": "showMask",
5085 "HIDE_MASK": "hideMask",
5091 * Constant representing the Panel's configuration properties
5092 * @property DEFAULT_CONFIG
5102 validator: Lang.isBoolean,
5103 supercedes: ["visible"]
5108 value: (DD ? true : false),
5109 validator: Lang.isBoolean,
5110 supercedes: ["visible"]
5116 supercedes: ["visible"]
5122 validator: Lang.isBoolean,
5123 supercedes: ["visible"]
5127 key: "keylisteners",
5128 suppressEvent: true,
5129 supercedes: ["visible"]
5136 * Constant representing the default CSS class used for a Panel
5137 * @property YAHOO.widget.Panel.CSS_PANEL
5142 Panel.CSS_PANEL = "yui-panel";
5145 * Constant representing the default CSS class used for a Panel's
5146 * wrapping container
5147 * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5152 Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5155 // Private CustomEvent listeners
5158 "beforeRender" event handler that creates an empty header for a Panel
5159 instance if its "draggable" configuration property is set to "true"
5160 and no header has been created.
5163 function createHeader(p_sType, p_aArgs) {
5167 this.setHeader(" ");
5175 "hide" event handler that sets a Panel instance's "width"
5176 configuration property back to its original value before
5177 "setWidthToOffsetWidth" was called.
5180 function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5182 var sOriginalWidth = p_oObject[0],
5183 sNewWidth = p_oObject[1],
5185 sCurrentWidth = oConfig.getProperty("width");
5187 if (sCurrentWidth == sNewWidth) {
5189 oConfig.setProperty("width", sOriginalWidth);
5193 this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5199 "beforeShow" event handler that sets a Panel instance's "width"
5200 configuration property to the value of its root HTML
5201 elements's offsetWidth
5204 function setWidthToOffsetWidth(p_sType, p_aArgs) {
5206 var nIE = YAHOO.env.ua.ie,
5211 if (nIE == 6 || (nIE == 7 && document.compatMode == "BackCompat")) {
5214 sOriginalWidth = oConfig.getProperty("width");
5216 if (!sOriginalWidth || sOriginalWidth == "auto") {
5218 sNewWidth = (this.element.offsetWidth + "px");
5220 oConfig.setProperty("width", sNewWidth);
5222 this.subscribe("hide", restoreOriginalWidth,
5223 [(sOriginalWidth || ""), sNewWidth]);
5232 "focus" event handler for a focuable element. Used to automatically
5233 blur the element when it receives focus to ensure that a Panel
5234 instance's modality is not compromised.
5237 function onElementFocus() {
5244 "showMask" event handler that adds a "focus" event handler to all
5245 focusable elements in the document to enforce a Panel instance's
5246 modality from being compromised.
5249 function addFocusEventHandlers(p_sType, p_aArgs) {
5253 function isFocusable(el) {
5255 var sTagName = el.tagName.toUpperCase(),
5265 if (!Dom.isAncestor(me.element, el)) {
5266 Event.on(el, "focus", onElementFocus, el, true);
5274 if (el.type != "hidden" &&
5275 !Dom.isAncestor(me.element, el)) {
5277 Event.on(el, "focus", onElementFocus, el, true);
5290 this.focusableElements = Dom.getElementsBy(isFocusable);
5295 "hideMask" event handler that removes all "focus" event handlers added
5296 by the "addFocusEventHandlers" method.
5299 function removeFocusEventHandlers(p_sType, p_aArgs) {
5301 var aElements = this.focusableElements,
5302 nElements = aElements.length,
5306 for (i = 0; i < nElements; i++) {
5308 Event.removeListener(el2, "focus", onElementFocus);
5314 YAHOO.extend(Panel, Overlay, {
5317 * The Overlay initialization method, which is executed for Overlay and
5318 * all of its subclasses. This method is automatically called by the
5319 * constructor, and sets up all DOM references for pre-existing markup,
5320 * and creates required markup if it is not already present.
5322 * @param {String} el The element ID representing the Overlay <em>OR</em>
5323 * @param {HTMLElement} el The element representing the Overlay
5324 * @param {Object} userConfig The configuration object literal
5325 * containing the configuration that should be set for this Overlay.
5326 * See configuration documentation for more details.
5328 init: function (el, userConfig) {
5331 Note that we don't pass the user config in here yet because
5332 we only want it executed once, at the lowest subclass level
5335 Panel.superclass.init.call(this, el/*, userConfig*/);
5337 this.beforeInitEvent.fire(Panel);
5339 Dom.addClass(this.element, Panel.CSS_PANEL);
5341 this.buildWrapper();
5345 this.cfg.applyConfig(userConfig, true);
5349 this.subscribe("showMask", addFocusEventHandlers);
5350 this.subscribe("hideMask", removeFocusEventHandlers);
5352 this.initEvent.fire(Panel);
5357 * Initializes the custom events for Module which are fired
5358 * automatically at appropriate times by the Module class.
5360 initEvents: function () {
5361 Panel.superclass.initEvents.call(this);
5363 var SIGNATURE = CustomEvent.LIST;
5366 * CustomEvent fired after the modality mask is shown
5367 * @event showMaskEvent
5369 this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
5370 this.showMaskEvent.signature = SIGNATURE;
5373 * CustomEvent fired after the modality mask is hidden
5374 * @event hideMaskEvent
5376 this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
5377 this.hideMaskEvent.signature = SIGNATURE;
5380 * CustomEvent when the Panel is dragged
5383 this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
5384 this.dragEvent.signature = SIGNATURE;
5389 * Initializes the class's configurable properties which can be changed
5390 * using the Panel's Config object (cfg).
5391 * @method initDefaultConfig
5393 initDefaultConfig: function () {
5394 Panel.superclass.initDefaultConfig.call(this);
5396 // Add panel config properties //
5399 * True if the Panel should display a "close" button
5404 this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
5405 handler: this.configClose,
5406 value: DEFAULT_CONFIG.CLOSE.value,
5407 validator: DEFAULT_CONFIG.CLOSE.validator,
5408 supercedes: DEFAULT_CONFIG.CLOSE.supercedes
5412 * Boolean specifying if the Panel should be draggable. The default
5413 * value is "true" if the Drag and Drop utility is included,
5414 * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
5415 * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
5416 * (Quirks Mode) where Panels that either don't have a value set for
5417 * their "width" configuration property, or their "width"
5418 * configuration property is set to "auto" will only be draggable by
5419 * placing the mouse on the text of the Panel's header element.
5420 * To fix this bug, draggable Panels missing a value for their
5421 * "width" configuration property, or whose "width" configuration
5422 * property is set to "auto" will have it set to the value of
5423 * their root HTML element's offsetWidth before they are made
5424 * visible. The calculated width is then removed when the Panel is
5425 * hidden. <em>This fix is only applied to draggable Panels in IE 6
5426 * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
5427 * more information on this issue see:
5428 * SourceForge bugs #1726972 and #1589210.
5433 this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
5434 handler: this.configDraggable,
5435 value: DEFAULT_CONFIG.DRAGGABLE.value,
5436 validator: DEFAULT_CONFIG.DRAGGABLE.validator,
5437 supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
5441 * Sets the type of underlay to display for the Panel. Valid values
5442 * are "shadow," "matte," and "none". <strong>PLEASE NOTE:</strong>
5443 * The creation of the underlay element is deferred until the Panel
5444 * is initially made visible. For Gecko-based browsers on Mac
5445 * OS X the underlay elment is always created as it is used as a
5446 * shim to prevent Aqua scrollbars below a Panel instance from poking
5447 * through it (See SourceForge bug #836476).
5452 this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
5453 handler: this.configUnderlay,
5454 value: DEFAULT_CONFIG.UNDERLAY.value,
5455 supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
5459 * True if the Panel should be displayed in a modal fashion,
5460 * automatically creating a transparent mask over the document that
5461 * will not be removed until the Panel is dismissed.
5466 this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
5467 handler: this.configModal,
5468 value: DEFAULT_CONFIG.MODAL.value,
5469 validator: DEFAULT_CONFIG.MODAL.validator,
5470 supercedes: DEFAULT_CONFIG.MODAL.supercedes
5474 * A KeyListener (or array of KeyListeners) that will be enabled
5475 * when the Panel is shown, and disabled when the Panel is hidden.
5476 * @config keylisteners
5477 * @type YAHOO.util.KeyListener[]
5480 this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
5481 handler: this.configKeyListeners,
5482 suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
5483 supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
5488 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5491 * The default event handler fired when the "close" property is changed.
5492 * The method controls the appending or hiding of the close icon at the
5493 * top right of the Panel.
5494 * @method configClose
5495 * @param {String} type The CustomEvent type (usually the property name)
5496 * @param {Object[]} args The CustomEvent arguments. For configuration
5497 * handlers, args[0] will equal the newly applied value for the property.
5498 * @param {Object} obj The scope object. For configuration handlers,
5499 * this will usually equal the owner.
5501 configClose: function (type, args, obj) {
5504 oClose = this.close;
5506 function doHide(e, obj) {
5516 if (!m_oCloseIconTemplate) {
5518 m_oCloseIconTemplate = document.createElement("span");
5519 m_oCloseIconTemplate.innerHTML = " ";
5520 m_oCloseIconTemplate.className = "container-close";
5524 oClose = m_oCloseIconTemplate.cloneNode(true);
5526 this.innerElement.appendChild(oClose);
5528 Event.on(oClose, "click", doHide, this);
5530 this.close = oClose;
5535 oClose.style.display = "block";
5543 oClose.style.display = "none";
5554 * The default event handler fired when the "draggable" property
5556 * @method configDraggable
5557 * @param {String} type The CustomEvent type (usually the property name)
5558 * @param {Object[]} args The CustomEvent arguments. For configuration
5559 * handlers, args[0] will equal the newly applied value for the property.
5560 * @param {Object} obj The scope object. For configuration handlers,
5561 * this will usually equal the owner.
5563 configDraggable: function (type, args, obj) {
5571 YAHOO.log("DD dependency not met.", "error");
5573 this.cfg.setProperty("draggable", false);
5581 Dom.setStyle(this.header, "cursor", "move");
5583 this.registerDragDrop();
5587 this.subscribe("beforeRender", createHeader);
5588 this.subscribe("beforeShow", setWidthToOffsetWidth);
5600 Dom.setStyle(this.header,"cursor","auto");
5604 this.unsubscribe("beforeRender", createHeader);
5605 this.unsubscribe("beforeShow", setWidthToOffsetWidth);
5613 * The default event handler fired when the "underlay" property
5615 * @method configUnderlay
5616 * @param {String} type The CustomEvent type (usually the property name)
5617 * @param {Object[]} args The CustomEvent arguments. For configuration
5618 * handlers, args[0] will equal the newly applied value for the property.
5619 * @param {Object} obj The scope object. For configuration handlers,
5620 * this will usually equal the owner.
5622 configUnderlay: function (type, args, obj) {
5624 var UA = YAHOO.env.ua,
5625 bMacGecko = (this.platform == "mac" && UA.gecko),
5626 sUnderlay = args[0].toLowerCase(),
5627 oUnderlay = this.underlay,
5628 oElement = this.element;
5631 function createUnderlay() {
5635 if (!oUnderlay) { // create if not already in DOM
5637 if (!m_oUnderlayTemplate) {
5639 m_oUnderlayTemplate = document.createElement("div");
5640 m_oUnderlayTemplate.className = "underlay";
5644 oUnderlay = m_oUnderlayTemplate.cloneNode(false);
5645 this.element.appendChild(oUnderlay);
5647 this.underlay = oUnderlay;
5652 (nIE == 7 && document.compatMode == "BackCompat")) {
5654 this.sizeUnderlay();
5656 this.cfg.subscribeToConfigEvent("width",
5659 this.cfg.subscribeToConfigEvent("height",
5662 this.changeContentEvent.subscribe(this.sizeUnderlay);
5664 YAHOO.widget.Module.textResizeEvent.subscribe(
5665 this.sizeUnderlay, this, true);
5674 function onBeforeShow() {
5676 createUnderlay.call(this);
5678 this._underlayDeferred = false;
5680 this.beforeShowEvent.unsubscribe(onBeforeShow);
5685 function destroyUnderlay() {
5687 if (this._underlayDeferred) {
5689 this.beforeShowEvent.unsubscribe(onBeforeShow);
5691 this._underlayDeferred = false;
5697 this.cfg.unsubscribeFromConfigEvent("width",
5700 this.cfg.unsubscribeFromConfigEvent("height",
5703 this.changeContentEvent.unsubscribe(this.sizeUnderlay);
5705 YAHOO.widget.Module.textResizeEvent.unsubscribe(
5706 this.sizeUnderlay, this, true);
5708 this.element.removeChild(oUnderlay);
5710 this.underlay = null;
5717 switch (sUnderlay) {
5721 Dom.removeClass(oElement, "matte");
5722 Dom.addClass(oElement, "shadow");
5730 destroyUnderlay.call(this);
5734 Dom.removeClass(oElement, "shadow");
5735 Dom.addClass(oElement, "matte");
5743 destroyUnderlay.call(this);
5747 Dom.removeClass(oElement, "shadow");
5748 Dom.removeClass(oElement, "matte");
5755 if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
5757 if (this.cfg.getProperty("visible")) {
5759 createUnderlay.call(this);
5764 if (!this._underlayDeferred) {
5766 this.beforeShowEvent.subscribe(onBeforeShow);
5768 this._underlayDeferred = true;
5779 * The default event handler fired when the "modal" property is
5780 * changed. This handler subscribes or unsubscribes to the show and hide
5781 * events to handle the display or hide of the modality mask.
5782 * @method configModal
5783 * @param {String} type The CustomEvent type (usually the property name)
5784 * @param {Object[]} args The CustomEvent arguments. For configuration
5785 * handlers, args[0] will equal the newly applied value for the property.
5786 * @param {Object} obj The scope object. For configuration handlers,
5787 * this will usually equal the owner.
5789 configModal: function (type, args, obj) {
5791 var modal = args[0];
5795 if (!this._hasModalityEventListeners) {
5797 this.subscribe("beforeShow", this.buildMask);
5798 this.subscribe("beforeShow", this.bringToTop);
5799 this.subscribe("beforeShow", this.showMask);
5800 this.subscribe("hide", this.hideMask);
5802 Overlay.windowResizeEvent.subscribe(this.sizeMask,
5805 this._hasModalityEventListeners = true;
5811 if (this._hasModalityEventListeners) {
5813 if (this.cfg.getProperty("visible")) {
5820 this.unsubscribe("beforeShow", this.buildMask);
5821 this.unsubscribe("beforeShow", this.bringToTop);
5822 this.unsubscribe("beforeShow", this.showMask);
5823 this.unsubscribe("hide", this.hideMask);
5825 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
5827 this._hasModalityEventListeners = false;
5836 * Removes the modality mask.
5837 * @method removeMask
5839 removeMask: function () {
5841 var oMask = this.mask,
5847 Hide the mask before destroying it to ensure that DOM
5848 event handlers on focusable elements get removed.
5853 oParentNode = oMask.parentNode;
5857 oParentNode.removeChild(oMask);
5867 * The default event handler fired when the "keylisteners" property
5869 * @method configKeyListeners
5870 * @param {String} type The CustomEvent type (usually the property name)
5871 * @param {Object[]} args The CustomEvent arguments. For configuration
5872 * handlers, args[0] will equal the newly applied value for the property.
5873 * @param {Object} obj The scope object. For configuration handlers,
5874 * this will usually equal the owner.
5876 configKeyListeners: function (type, args, obj) {
5878 var listeners = args[0],
5885 if (listeners instanceof Array) {
5887 nListeners = listeners.length;
5889 for (i = 0; i < nListeners; i++) {
5891 listener = listeners[i];
5893 if (!Config.alreadySubscribed(this.showEvent,
5894 listener.enable, listener)) {
5896 this.showEvent.subscribe(listener.enable,
5901 if (!Config.alreadySubscribed(this.hideEvent,
5902 listener.disable, listener)) {
5904 this.hideEvent.subscribe(listener.disable,
5907 this.destroyEvent.subscribe(listener.disable,
5915 if (!Config.alreadySubscribed(this.showEvent,
5916 listeners.enable, listeners)) {
5918 this.showEvent.subscribe(listeners.enable,
5922 if (!Config.alreadySubscribed(this.hideEvent,
5923 listeners.disable, listeners)) {
5925 this.hideEvent.subscribe(listeners.disable,
5928 this.destroyEvent.subscribe(listeners.disable,
5940 * The default event handler fired when the "height" property is changed.
5941 * @method configHeight
5942 * @param {String} type The CustomEvent type (usually the property name)
5943 * @param {Object[]} args The CustomEvent arguments. For configuration
5944 * handlers, args[0] will equal the newly applied value for the property.
5945 * @param {Object} obj The scope object. For configuration handlers,
5946 * this will usually equal the owner.
5948 configHeight: function (type, args, obj) {
5950 var height = args[0],
5951 el = this.innerElement;
5953 Dom.setStyle(el, "height", height);
5954 this.cfg.refireEvent("iframe");
5959 * The default event handler fired when the "width" property is changed.
5960 * @method configWidth
5961 * @param {String} type The CustomEvent type (usually the property name)
5962 * @param {Object[]} args The CustomEvent arguments. For configuration
5963 * handlers, args[0] will equal the newly applied value for the property.
5964 * @param {Object} obj The scope object. For configuration handlers,
5965 * this will usually equal the owner.
5967 configWidth: function (type, args, obj) {
5969 var width = args[0],
5970 el = this.innerElement;
5972 Dom.setStyle(el, "width", width);
5973 this.cfg.refireEvent("iframe");
5978 * The default event handler fired when the "zIndex" property is changed.
5979 * @method configzIndex
5980 * @param {String} type The CustomEvent type (usually the property name)
5981 * @param {Object[]} args The CustomEvent arguments. For configuration
5982 * handlers, args[0] will equal the newly applied value for the property.
5983 * @param {Object} obj The scope object. For configuration handlers,
5984 * this will usually equal the owner.
5986 configzIndex: function (type, args, obj) {
5988 Panel.superclass.configzIndex.call(this, type, args, obj);
5991 currentZ = Dom.getStyle(this.element, "zIndex");
5995 if (!currentZ || isNaN(currentZ)) {
5999 if (currentZ === 0) {
6001 this.cfg.setProperty("zIndex", 1);
6005 maskZ = currentZ - 1;
6006 Dom.setStyle(this.mask, "zIndex", maskZ);
6013 // END BUILT-IN PROPERTY EVENT HANDLERS //
6017 * Builds the wrapping container around the Panel that is used for
6018 * positioning the shadow and matte underlays. The container element is
6019 * assigned to a local instance variable called container, and the
6020 * element is reinserted inside of it.
6021 * @method buildWrapper
6023 buildWrapper: function () {
6025 var elementParent = this.element.parentNode,
6026 originalElement = this.element,
6027 wrapper = document.createElement("div");
6029 wrapper.className = Panel.CSS_PANEL_CONTAINER;
6030 wrapper.id = originalElement.id + "_c";
6032 if (elementParent) {
6033 elementParent.insertBefore(wrapper, originalElement);
6036 wrapper.appendChild(originalElement);
6038 this.element = wrapper;
6039 this.innerElement = originalElement;
6041 Dom.setStyle(this.innerElement, "visibility", "inherit");
6045 * Adjusts the size of the shadow based on the size of the element.
6046 * @method sizeUnderlay
6048 sizeUnderlay: function () {
6050 var oUnderlay = this.underlay,
6055 oElement = this.element;
6057 oUnderlay.style.width = oElement.offsetWidth + "px";
6058 oUnderlay.style.height = oElement.offsetHeight + "px";
6066 * Registers the Panel's header for drag & drop capability.
6067 * @method registerDragDrop
6069 registerDragDrop: function () {
6077 YAHOO.log("DD dependency not met.", "error");
6083 this.dd = new DD(this.element.id, this.id);
6085 if (!this.header.id) {
6086 this.header.id = this.id + "_h";
6090 this.dd.startDrag = function () {
6103 if (YAHOO.env.ua.ie == 6) {
6104 Dom.addClass(me.element,"drag");
6107 if (me.cfg.getProperty("constraintoviewport")) {
6109 offsetHeight = me.element.offsetHeight;
6110 offsetWidth = me.element.offsetWidth;
6112 viewPortWidth = Dom.getViewportWidth();
6113 viewPortHeight = Dom.getViewportHeight();
6115 scrollX = Dom.getDocumentScrollLeft();
6116 scrollY = Dom.getDocumentScrollTop();
6118 topConstraint = scrollY + 10;
6119 leftConstraint = scrollX + 10;
6122 scrollY + viewPortHeight - offsetHeight - 10;
6125 scrollX + viewPortWidth - offsetWidth - 10;
6127 this.minX = leftConstraint;
6128 this.maxX = rightConstraint;
6129 this.constrainX = true;
6131 this.minY = topConstraint;
6132 this.maxY = bottomConstraint;
6133 this.constrainY = true;
6137 this.constrainX = false;
6138 this.constrainY = false;
6142 me.dragEvent.fire("startDrag", arguments);
6145 this.dd.onDrag = function () {
6147 me.cfg.refireEvent("iframe");
6148 if (this.platform == "mac" && YAHOO.env.ua.gecko) {
6149 this.showMacGeckoScrollbars();
6152 me.dragEvent.fire("onDrag", arguments);
6155 this.dd.endDrag = function () {
6157 if (YAHOO.env.ua.ie == 6) {
6158 Dom.removeClass(me.element,"drag");
6161 me.dragEvent.fire("endDrag", arguments);
6162 me.moveEvent.fire(me.cfg.getProperty("xy"));
6166 this.dd.setHandleElId(this.header.id);
6167 this.dd.addInvalidHandleType("INPUT");
6168 this.dd.addInvalidHandleType("SELECT");
6169 this.dd.addInvalidHandleType("TEXTAREA");
6174 * Builds the mask that is laid over the document when the Panel is
6175 * configured to be modal.
6178 buildMask: function () {
6180 var oMask = this.mask;
6184 if (!m_oMaskTemplate) {
6186 m_oMaskTemplate = document.createElement("div");
6187 m_oMaskTemplate.className = "mask";
6188 m_oMaskTemplate.innerHTML = " ";
6192 oMask = m_oMaskTemplate.cloneNode(true);
6193 oMask.id = this.id + "_mask";
6195 document.body.insertBefore(oMask, document.body.firstChild);
6204 * Hides the modality mask.
6207 hideMask: function () {
6208 if (this.cfg.getProperty("modal") && this.mask) {
6209 this.mask.style.display = "none";
6210 this.hideMaskEvent.fire();
6211 Dom.removeClass(document.body, "masked");
6216 * Shows the modality mask.
6219 showMask: function () {
6220 if (this.cfg.getProperty("modal") && this.mask) {
6221 Dom.addClass(document.body, "masked");
6223 this.mask.style.display = "block";
6224 this.showMaskEvent.fire();
6229 * Sets the size of the modality mask to cover the entire scrollable
6230 * area of the document
6233 sizeMask: function () {
6237 this.mask.style.height = Dom.getDocumentHeight() + "px";
6238 this.mask.style.width = Dom.getDocumentWidth() + "px";
6246 * Renders the Panel by inserting the elements that are not already in
6247 * the main Panel into their correct places. Optionally appends the
6248 * Panel to the specified node prior to the render's execution. NOTE:
6249 * For Panels without existing markup, the appendToNode argument is
6250 * REQUIRED. If this argument is ommitted and the current element is
6251 * not present in the document, the function will return false,
6252 * indicating that the render was a failure.
6254 * @param {String} appendToNode The element id to which the Module
6255 * should be appended to prior to rendering <em>OR</em>
6256 * @param {HTMLElement} appendToNode The element to which the Module
6257 * should be appended to prior to rendering
6258 * @return {boolean} Success or failure of the render
6260 render: function (appendToNode) {
6262 return Panel.superclass.render.call(this,
6263 appendToNode, this.innerElement);
6268 * Removes the Panel element from the DOM and sets all child elements
6272 destroy: function () {
6274 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6280 Event.purgeElement(this.close);
6284 Panel.superclass.destroy.call(this);
6289 * Returns a String representation of the object.
6291 * @return {String} The string representation of the Panel.
6293 toString: function () {
6294 return "Panel " + this.id;
6303 * Dialog is an implementation of Panel that can be used to submit form
6304 * data. Built-in functionality for buttons with event handlers is included,
6305 * and button sets can be build dynamically, or the preincluded ones for
6306 * Submit/Cancel and OK/Cancel can be utilized. Forms can be processed in 3
6307 * ways -- via an asynchronous Connection utility call, a simple form
6308 * POST or GET, or manually.
6309 * @namespace YAHOO.widget
6311 * @extends YAHOO.widget.Panel
6313 * @param {String} el The element ID representing the Dialog <em>OR</em>
6314 * @param {HTMLElement} el The element representing the Dialog
6315 * @param {Object} userConfig The configuration object literal containing
6316 * the configuration that should be set for this Dialog. See configuration
6317 * documentation for more details.
6319 YAHOO.widget.Dialog = function (el, userConfig) {
6321 YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
6326 var Event = YAHOO.util.Event,
6327 CustomEvent = YAHOO.util.CustomEvent,
6328 Dom = YAHOO.util.Dom,
6329 KeyListener = YAHOO.util.KeyListener,
6330 Connect = YAHOO.util.Connect,
6331 Dialog = YAHOO.widget.Dialog,
6335 * Constant representing the name of the Dialog's events
6336 * @property EVENT_TYPES
6343 "BEFORE_SUBMIT": "beforeSubmit",
6345 "MANUAL_SUBMIT": "manualSubmit",
6346 "ASYNC_SUBMIT": "asyncSubmit",
6347 "FORM_SUBMIT": "formSubmit",
6353 * Constant representing the Dialog's configuration properties
6354 * @property DEFAULT_CONFIG
6375 * Constant representing the default CSS class used for a Dialog
6376 * @property YAHOO.widget.Dialog.CSS_DIALOG
6381 Dialog.CSS_DIALOG = "yui-dialog";
6384 function removeButtonEventHandlers() {
6386 var aButtons = this._aButtons,
6391 if (Lang.isArray(aButtons)) {
6393 nButtons = aButtons.length;
6401 oButton = aButtons[i];
6403 if (oButton instanceof YAHOO.widget.Button) {
6408 else if (oButton.tagName.toUpperCase() == "BUTTON") {
6410 Event.purgeElement(oButton);
6411 Event.purgeElement(oButton, false);
6425 YAHOO.extend(Dialog, YAHOO.widget.Panel, {
6430 * @description Object reference to the Dialog's
6431 * <code><form></code> element.
6433 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
6434 * level-one-html.html#ID-40002357">HTMLFormElement</a>
6439 * Initializes the class's configurable properties which can be changed
6440 * using the Dialog's Config object (cfg).
6441 * @method initDefaultConfig
6443 initDefaultConfig: function () {
6444 Dialog.superclass.initDefaultConfig.call(this);
6447 * The internally maintained callback object for use with the
6448 * Connection utility
6449 * @property callback
6455 * The function to execute upon success of the
6456 * Connection submission
6457 * @property callback.success
6463 * The function to execute upon failure of the
6464 * Connection submission
6465 * @property callback.failure
6471 * The arbitraty argument or arguments to pass to the Connection
6472 * callback functions
6473 * @property callback.argument
6481 // Add form dialog config properties //
6484 * The method to use for posting the Dialog's form. Possible values
6485 * are "async", "form", and "manual".
6486 * @config postmethod
6490 this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
6491 handler: this.configPostMethod,
6492 value: DEFAULT_CONFIG.POST_METHOD.value,
6493 validator: function (val) {
6494 if (val != "form" && val != "async" && val != "none" &&
6504 * Array of object literals, each containing a set of properties
6505 * defining a button to be appended into the Dialog's footer.
6506 * Each button object in the buttons array can have three properties:
6508 * <dd>The text that will display on the face of the button. <em>
6509 * Please note:</em> As of version 2.3, the text can include
6512 * <dd>Can be either:
6514 * <li>A reference to a function that should fire when the
6515 * button is clicked. (In this case scope of this function is
6516 * always its Dialog instance.)</li>
6517 * <li>An object literal representing the code to be
6518 * executed when the button is clicked. Format:<br> <code> {<br>
6519 * <strong>fn:</strong> Function, // The handler to call
6520 * when the event fires.<br> <strong>obj:</strong> Object,
6521 * // An object to pass back to the handler.<br> <strong>
6522 * scope:</strong> Object // The object to use for the
6523 * scope of the handler. <br> } </code> <br><em>Please note: this
6524 * functionality was added in version 2.3.</em></li>
6527 * <dt>isDefault:</dt>
6528 * <dd>An optional boolean value that specifies that a button
6529 * should be highlighted and focused by default.</dd>
6531 * @type {Array|String}
6534 this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
6535 handler: this.configButtons,
6536 value: DEFAULT_CONFIG.BUTTONS.value
6542 * Initializes the custom events for Dialog which are fired
6543 * automatically at appropriate times by the Dialog class.
6544 * @method initEvents
6546 initEvents: function () {
6547 Dialog.superclass.initEvents.call(this);
6549 var SIGNATURE = CustomEvent.LIST;
6552 * CustomEvent fired prior to submission
6553 * @event beforeSubmitEvent
6555 this.beforeSubmitEvent =
6556 this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
6557 this.beforeSubmitEvent.signature = SIGNATURE;
6560 * CustomEvent fired after submission
6561 * @event submitEvent
6563 this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
6564 this.submitEvent.signature = SIGNATURE;
6567 * CustomEvent fired prior to manual submission
6568 * @event manualSubmitEvent
6570 this.manualSubmitEvent =
6571 this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
6572 this.manualSubmitEvent.signature = SIGNATURE;
6575 * CustomEvent fired prior to asynchronous submission
6576 * @event asyncSubmitEvent
6578 this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
6579 this.asyncSubmitEvent.signature = SIGNATURE;
6582 * CustomEvent fired prior to form-based submission
6583 * @event formSubmitEvent
6585 this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
6586 this.formSubmitEvent.signature = SIGNATURE;
6589 * CustomEvent fired after cancel
6590 * @event cancelEvent
6592 this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
6593 this.cancelEvent.signature = SIGNATURE;
6598 * The Dialog initialization method, which is executed for Dialog and
6599 * all of its subclasses. This method is automatically called by the
6600 * constructor, and sets up all DOM references for pre-existing markup,
6601 * and creates required markup if it is not already present.
6603 * @param {String} el The element ID representing the Dialog <em>OR</em>
6604 * @param {HTMLElement} el The element representing the Dialog
6605 * @param {Object} userConfig The configuration object literal
6606 * containing the configuration that should be set for this Dialog.
6607 * See configuration documentation for more details.
6609 init: function (el, userConfig) {
6612 Note that we don't pass the user config in here yet because
6613 we only want it executed once, at the lowest subclass level
6616 Dialog.superclass.init.call(this, el/*, userConfig*/);
6618 this.beforeInitEvent.fire(Dialog);
6620 Dom.addClass(this.element, Dialog.CSS_DIALOG);
6622 this.cfg.setProperty("visible", false);
6625 this.cfg.applyConfig(userConfig, true);
6628 this.showEvent.subscribe(this.focusFirst, this, true);
6629 this.beforeHideEvent.subscribe(this.blurButtons, this, true);
6631 this.subscribe("changeBody", this.registerForm);
6633 this.initEvent.fire(Dialog);
6637 * Submits the Dialog's form depending on the value of the
6638 * "postmethod" configuration property. <strong>Please note:
6639 * </strong> As of version 2.3 this method will automatically handle
6640 * asyncronous file uploads should the Dialog instance's form contain
6641 * <code><input type="file"></code> elements. If a Dialog
6642 * instance will be handling asyncronous file uploads, its
6643 * <code>callback</code> property will need to be setup with a
6644 * <code>upload</code> handler rather than the standard
6645 * <code>success</code> and, or <code>failure</code> handlers. For more
6646 * information, see the <a href="http://developer.yahoo.com/yui/
6647 * connection/#file">Connection Manager documenation on file uploads</a>.
6650 doSubmit: function () {
6652 var oForm = this.form,
6653 bUseFileUpload = false,
6654 bUseSecureFileUpload = false,
6661 switch (this.cfg.getProperty("postmethod")) {
6665 aElements = oForm.elements;
6666 nElements = aElements.length;
6668 if (nElements > 0) {
6674 if (aElements[i].type == "file") {
6676 bUseFileUpload = true;
6686 if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
6688 bUseSecureFileUpload = true;
6693 (oForm.getAttribute("method") || "POST").toUpperCase();
6695 Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
6697 Connect.asyncRequest(sMethod, oForm.getAttribute("action"),
6700 this.asyncSubmitEvent.fire();
6707 this.formSubmitEvent.fire();
6714 this.manualSubmitEvent.fire();
6724 * Prepares the Dialog's internal FORM object, creating one if one is
6725 * not currently present.
6726 * @method registerForm
6728 registerForm: function () {
6730 var form = this.element.getElementsByTagName("form")[0],
6738 if (this.form == form &&
6739 Dom.isAncestor(this.element, this.form)) {
6746 Event.purgeElement(this.form);
6757 form = document.createElement("form");
6758 form.name = "frm_" + this.id;
6760 this.body.appendChild(form);
6769 Event.on(form, "submit", function (e) {
6779 this.firstFormElement = function () {
6781 var f, el, nElements = form.elements.length;
6783 for (f = 0; f < nElements; f++) {
6785 el = form.elements[f];
6787 if (el.focus && !el.disabled && el.type != "hidden") {
6799 this.lastFormElement = function () {
6801 var f, el, nElements = form.elements.length;
6803 for (f = nElements - 1; f >= 0; f--) {
6805 el = form.elements[f];
6807 if (el.focus && !el.disabled && el.type != "hidden") {
6819 if (this.cfg.getProperty("modal")) {
6821 firstElement = this.firstFormElement || this.firstButton;
6825 this.preventBackTab = new KeyListener(firstElement,
6826 { shift: true, keys: 9 },
6827 { fn: me.focusLast, scope: me,
6828 correctScope: true });
6830 this.showEvent.subscribe(this.preventBackTab.enable,
6831 this.preventBackTab, true);
6833 this.hideEvent.subscribe(this.preventBackTab.disable,
6834 this.preventBackTab, true);
6837 lastElement = this.lastButton || this.lastFormElement;
6841 this.preventTabOut = new KeyListener(lastElement,
6842 { shift: false, keys: 9 },
6843 { fn: me.focusFirst, scope: me,
6844 correctScope: true });
6846 this.showEvent.subscribe(this.preventTabOut.enable,
6847 this.preventTabOut, true);
6849 this.hideEvent.subscribe(this.preventTabOut.disable,
6850 this.preventTabOut, true);
6859 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6862 * The default event handler fired when the "close" property is
6863 * changed. The method controls the appending or hiding of the close
6864 * icon at the top right of the Dialog.
6865 * @method configClose
6866 * @param {String} type The CustomEvent type (usually the property name)
6867 * @param {Object[]} args The CustomEvent arguments. For
6868 * configuration handlers, args[0] will equal the newly applied value
6870 * @param {Object} obj The scope object. For configuration handlers,
6871 * this will usually equal the owner.
6873 configClose: function (type, args, obj) {
6876 function doCancel(e, obj) {
6882 this.close = document.createElement("div");
6883 Dom.addClass(this.close, "container-close");
6885 this.close.innerHTML = " ";
6886 this.innerElement.appendChild(this.close);
6887 Event.on(this.close, "click", doCancel, this);
6889 this.close.style.display = "block";
6893 this.close.style.display = "none";
6899 * The default event handler for the "buttons" configuration property
6900 * @method configButtons
6901 * @param {String} type The CustomEvent type (usually the property name)
6902 * @param {Object[]} args The CustomEvent arguments. For configuration
6903 * handlers, args[0] will equal the newly applied value for the property.
6904 * @param {Object} obj The scope object. For configuration handlers,
6905 * this will usually equal the owner.
6907 configButtons: function (type, args, obj) {
6909 var Button = YAHOO.widget.Button,
6911 oInnerElement = this.innerElement,
6920 removeButtonEventHandlers.call(this);
6922 this._aButtons = null;
6924 if (Lang.isArray(aButtons)) {
6926 oSpan = document.createElement("span");
6927 oSpan.className = "button-group";
6929 nButtons = aButtons.length;
6931 this._aButtons = [];
6933 for (i = 0; i < nButtons; i++) {
6935 oButton = aButtons[i];
6939 oYUIButton = new Button({ label: oButton.text,
6940 container: oSpan });
6942 oButtonEl = oYUIButton.get("element");
6944 if (oButton.isDefault) {
6946 oYUIButton.addClass("default");
6948 this.defaultHtmlButton = oButtonEl;
6952 if (Lang.isFunction(oButton.handler)) {
6954 oYUIButton.set("onclick", { fn: oButton.handler,
6955 obj: this, scope: this });
6958 else if (Lang.isObject(oButton.handler) &&
6959 Lang.isFunction(oButton.handler.fn)) {
6961 oYUIButton.set("onclick", { fn: oButton.handler.fn,
6962 obj: ((!Lang.isUndefined(oButton.handler.obj)) ?
6963 oButton.handler.obj : this),
6964 scope: (oButton.handler.scope || this) });
6968 this._aButtons[this._aButtons.length] = oYUIButton;
6973 oButtonEl = document.createElement("button");
6974 oButtonEl.setAttribute("type", "button");
6976 if (oButton.isDefault) {
6977 oButtonEl.className = "default";
6978 this.defaultHtmlButton = oButtonEl;
6981 oButtonEl.innerHTML = oButton.text;
6983 if (Lang.isFunction(oButton.handler)) {
6985 Event.on(oButtonEl, "click", oButton.handler,
6989 else if (Lang.isObject(oButton.handler) &&
6990 Lang.isFunction(oButton.handler.fn)) {
6992 Event.on(oButtonEl, "click", oButton.handler.fn,
6993 ((!Lang.isUndefined(oButton.handler.obj)) ?
6994 oButton.handler.obj : this),
6995 (oButton.handler.scope || this));
6999 oSpan.appendChild(oButtonEl);
7001 this._aButtons[this._aButtons.length] = oButtonEl;
7005 oButton.htmlButton = oButtonEl;
7008 this.firstButton = oButtonEl;
7011 if (i == (nButtons - 1)) {
7012 this.lastButton = oButtonEl;
7017 this.setFooter(oSpan);
7019 oFooter = this.footer;
7021 if (Dom.inDocument(this.element) &&
7022 !Dom.isAncestor(oInnerElement, oFooter)) {
7024 oInnerElement.appendChild(oFooter);
7028 this.buttonSpan = oSpan;
7030 } else { // Do cleanup
7032 oSpan = this.buttonSpan;
7033 oFooter = this.footer;
7035 if (oSpan && oFooter) {
7037 oFooter.removeChild(oSpan);
7039 this.buttonSpan = null;
7040 this.firstButton = null;
7041 this.lastButton = null;
7042 this.defaultHtmlButton = null;
7048 this.cfg.refireEvent("iframe");
7049 this.cfg.refireEvent("underlay");
7055 * @method getButtons
7056 * @description Returns an array containing each of the Dialog's
7057 * buttons, by default an array of HTML <code><BUTTON<</code>
7058 * elements. If the Dialog's buttons were created using the
7059 * YAHOO.widget.Button class (via the inclusion of the optional Button
7060 * dependancy on the page), an array of YAHOO.widget.Button instances
7064 getButtons: function () {
7066 var aButtons = this._aButtons;
7078 * Sets focus to the first element in the Dialog's form or the first
7079 * button defined via the "buttons" configuration property. Called
7080 * when the Dialog is made visible.
7081 * @method focusFirst
7083 focusFirst: function (type, args, obj) {
7085 var oElement = this.firstFormElement,
7094 Event.stopEvent(oEvent);
7104 Place the call to the "focus" method inside a try/catch
7105 block to prevent IE from throwing JavaScript errors if
7106 the element is disabled or hidden.
7120 this.focusDefaultButton();
7127 * Sets focus to the last element in the Dialog's form or the last
7128 * button defined via the "buttons" configuration property.
7131 focusLast: function (type, args, obj) {
7133 var aButtons = this.cfg.getProperty("buttons"),
7134 oElement = this.lastFormElement,
7143 Event.stopEvent(oEvent);
7149 if (aButtons && Lang.isArray(aButtons)) {
7151 this.focusLastButton();
7158 Place the call to the "focus" method inside a try/catch
7159 block to prevent IE from throwing JavaScript errors if
7160 the element is disabled or hidden.
7179 * Sets the focus to the button that is designated as the default via
7180 * the "buttons" configuration property. By default, this method is
7181 * called when the Dialog is made visible.
7182 * @method focusDefaultButton
7184 focusDefaultButton: function () {
7186 var oElement = this.defaultHtmlButton;
7191 Place the call to the "focus" method inside a try/catch
7192 block to prevent IE from throwing JavaScript errors if
7193 the element is disabled or hidden.
7209 * Blurs all the buttons defined via the "buttons"
7210 * configuration property.
7211 * @method blurButtons
7213 blurButtons: function () {
7215 var aButtons = this.cfg.getProperty("buttons"),
7221 if (aButtons && Lang.isArray(aButtons)) {
7223 nButtons = aButtons.length;
7231 oButton = aButtons[i];
7235 oElement = oButton.htmlButton;
7240 Place the call to the "blur" method inside
7241 a try/catch block to prevent IE from
7242 throwing JavaScript errors if the element
7243 is disabled or hidden.
7270 * Sets the focus to the first button created via the "buttons"
7271 * configuration property.
7272 * @method focusFirstButton
7274 focusFirstButton: function () {
7276 var aButtons = this.cfg.getProperty("buttons"),
7280 if (aButtons && Lang.isArray(aButtons)) {
7282 oButton = aButtons[0];
7286 oElement = oButton.htmlButton;
7291 Place the call to the "focus" method inside a
7292 try/catch block to prevent IE from throwing
7293 JavaScript errors if the element is disabled
7315 * Sets the focus to the last button created via the "buttons"
7316 * configuration property.
7317 * @method focusLastButton
7319 focusLastButton: function () {
7321 var aButtons = this.cfg.getProperty("buttons"),
7326 if (aButtons && Lang.isArray(aButtons)) {
7328 nButtons = aButtons.length;
7332 oButton = aButtons[(nButtons - 1)];
7336 oElement = oButton.htmlButton;
7341 Place the call to the "focus" method inside a
7342 try/catch block to prevent IE from throwing
7343 JavaScript errors if the element is disabled
7368 * The default event handler for the "postmethod" configuration property
7369 * @method configPostMethod
7370 * @param {String} type The CustomEvent type (usually the property name)
7371 * @param {Object[]} args The CustomEvent arguments. For
7372 * configuration handlers, args[0] will equal the newly applied value
7374 * @param {Object} obj The scope object. For configuration handlers,
7375 * this will usually equal the owner.
7377 configPostMethod: function (type, args, obj) {
7379 var postmethod = args[0];
7381 this.registerForm();
7385 // END BUILT-IN PROPERTY EVENT HANDLERS //
7388 * Built-in function hook for writing a validation function that will
7389 * be checked for a "true" value prior to a submit. This function, as
7390 * implemented by default, always returns true, so it should be
7391 * overridden if validation is necessary.
7394 validate: function () {
7399 * Executes a submit of the Dialog followed by a hide, if validation
7403 submit: function () {
7404 if (this.validate()) {
7405 this.beforeSubmitEvent.fire();
7407 this.submitEvent.fire();
7416 * Executes the cancel of the Dialog followed by a hide.
7419 cancel: function () {
7420 this.cancelEvent.fire();
7425 * Returns a JSON-compatible data structure representing the data
7426 * currently contained in the form.
7428 * @return {Object} A JSON object reprsenting the data of the
7431 getData: function () {
7433 var oForm = this.form,
7452 function isFormElement(p_oElement) {
7454 var sTag = p_oElement.tagName.toUpperCase();
7456 return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
7457 sTag == "SELECT") && p_oElement.name == sName);
7464 aElements = oForm.elements;
7465 nTotalElements = aElements.length;
7469 for (i = 0; i < nTotalElements; i++) {
7471 sName = aElements[i].name;
7474 Using "Dom.getElementsBy" to safeguard user from JS
7475 errors that result from giving a form field (or set of
7476 fields) the same name as a native method of a form
7477 (like "submit") or a DOM collection (such as the "item"
7478 method). Originally tried accessing fields via the
7479 "namedItem" method of the "element" collection, but
7480 discovered that it won't return a collection of fields
7484 oElement = Dom.getElementsBy(isFormElement, "*", oForm);
7485 nElements = oElement.length;
7487 if (nElements > 0) {
7489 if (nElements == 1) {
7491 oElement = oElement[0];
7493 sType = oElement.type;
7494 sTagName = oElement.tagName.toUpperCase();
7500 if (sType == "checkbox") {
7502 oData[sName] = oElement.checked;
7505 else if (sType != "radio") {
7507 oData[sName] = oElement.value;
7515 oData[sName] = oElement.value;
7521 aOptions = oElement.options;
7522 nOptions = aOptions.length;
7525 for (n = 0; n < nOptions; n++) {
7527 oOption = aOptions[n];
7529 if (oOption.selected) {
7531 sValue = oOption.value;
7533 if (!sValue || sValue === "") {
7535 sValue = oOption.text;
7539 aValues[aValues.length] = sValue;
7545 oData[sName] = aValues;
7555 sType = oElement[0].type;
7561 for (n = 0; n < nElements; n++) {
7563 oRadio = oElement[n];
7565 if (oRadio.checked) {
7567 oData[sName] = oRadio.value;
7580 for (n = 0; n < nElements; n++) {
7582 oCheckbox = oElement[n];
7584 if (oCheckbox.checked) {
7586 aValues[aValues.length] =
7593 oData[sName] = aValues;
7613 * Removes the Panel element from the DOM and sets all child elements
7617 destroy: function () {
7619 removeButtonEventHandlers.call(this);
7621 this._aButtons = null;
7623 var aForms = this.element.getElementsByTagName("form"),
7626 if (aForms.length > 0) {
7632 Event.purgeElement(oForm);
7634 this.body.removeChild(oForm);
7642 Dialog.superclass.destroy.call(this);
7647 * Returns a string representation of the object.
7649 * @return {String} The string representation of the Dialog
7651 toString: function () {
7652 return "Dialog " + this.id;
7661 * SimpleDialog is a simple implementation of Dialog that can be used to
7662 * submit a single value. Forms can be processed in 3 ways -- via an
7663 * asynchronous Connection utility call, a simple form POST or GET,
7665 * @namespace YAHOO.widget
7666 * @class SimpleDialog
7667 * @extends YAHOO.widget.Dialog
7669 * @param {String} el The element ID representing the SimpleDialog
7671 * @param {HTMLElement} el The element representing the SimpleDialog
7672 * @param {Object} userConfig The configuration object literal containing
7673 * the configuration that should be set for this SimpleDialog. See
7674 * configuration documentation for more details.
7676 YAHOO.widget.SimpleDialog = function (el, userConfig) {
7678 YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
7683 var Dom = YAHOO.util.Dom,
7684 SimpleDialog = YAHOO.widget.SimpleDialog,
7687 * Constant representing the SimpleDialog's configuration properties
7688 * @property DEFAULT_CONFIG
7704 suppressEvent: true,
7705 supercedes: ["icon"]
7711 * Constant for the standard network icon for a blocking action
7712 * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
7717 SimpleDialog.ICON_BLOCK = "blckicon";
7720 * Constant for the standard network icon for alarm
7721 * @property YAHOO.widget.SimpleDialog.ICON_ALARM
7726 SimpleDialog.ICON_ALARM = "alrticon";
7729 * Constant for the standard network icon for help
7730 * @property YAHOO.widget.SimpleDialog.ICON_HELP
7735 SimpleDialog.ICON_HELP = "hlpicon";
7738 * Constant for the standard network icon for info
7739 * @property YAHOO.widget.SimpleDialog.ICON_INFO
7744 SimpleDialog.ICON_INFO = "infoicon";
7747 * Constant for the standard network icon for warn
7748 * @property YAHOO.widget.SimpleDialog.ICON_WARN
7753 SimpleDialog.ICON_WARN = "warnicon";
7756 * Constant for the standard network icon for a tip
7757 * @property YAHOO.widget.SimpleDialog.ICON_TIP
7762 SimpleDialog.ICON_TIP = "tipicon";
7765 * Constant representing the name of the CSS class applied to the element
7766 * created by the "icon" configuration property.
7767 * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
7772 SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
7775 * Constant representing the default CSS class used for a SimpleDialog
7776 * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
7781 SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
7784 YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
7787 * Initializes the class's configurable properties which can be changed
7788 * using the SimpleDialog's Config object (cfg).
7789 * @method initDefaultConfig
7791 initDefaultConfig: function () {
7793 SimpleDialog.superclass.initDefaultConfig.call(this);
7795 // Add dialog config properties //
7798 * Sets the informational icon for the SimpleDialog
7803 this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
7804 handler: this.configIcon,
7805 value: DEFAULT_CONFIG.ICON.value,
7806 suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
7810 * Sets the text for the SimpleDialog
7815 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
7816 handler: this.configText,
7817 value: DEFAULT_CONFIG.TEXT.value,
7818 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
7819 supercedes: DEFAULT_CONFIG.TEXT.supercedes
7826 * The SimpleDialog initialization method, which is executed for
7827 * SimpleDialog and all of its subclasses. This method is automatically
7828 * called by the constructor, and sets up all DOM references for
7829 * pre-existing markup, and creates required markup if it is not
7832 * @param {String} el The element ID representing the SimpleDialog
7834 * @param {HTMLElement} el The element representing the SimpleDialog
7835 * @param {Object} userConfig The configuration object literal
7836 * containing the configuration that should be set for this
7837 * SimpleDialog. See configuration documentation for more details.
7839 init: function (el, userConfig) {
7842 Note that we don't pass the user config in here yet because we
7843 only want it executed once, at the lowest subclass level
7846 SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
7848 this.beforeInitEvent.fire(SimpleDialog);
7850 Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
7852 this.cfg.queueProperty("postmethod", "manual");
7855 this.cfg.applyConfig(userConfig, true);
7858 this.beforeRenderEvent.subscribe(function () {
7864 this.initEvent.fire(SimpleDialog);
7869 * Prepares the SimpleDialog's internal FORM object, creating one if one
7870 * is not currently present, and adding the value hidden field.
7871 * @method registerForm
7873 registerForm: function () {
7875 SimpleDialog.superclass.registerForm.call(this);
7877 this.form.innerHTML += "<input type=\"hidden\" name=\"" +
7878 this.id + "\" value=\"\"/>";
7882 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7885 * Fired when the "icon" property is set.
7886 * @method configIcon
7887 * @param {String} type The CustomEvent type (usually the property name)
7888 * @param {Object[]} args The CustomEvent arguments. For configuration
7889 * handlers, args[0] will equal the newly applied value for the property.
7890 * @param {Object} obj The scope object. For configuration handlers,
7891 * this will usually equal the owner.
7893 configIcon: function (type,args,obj) {
7895 var sIcon = args[0],
7897 sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
7901 if (sIcon && sIcon != "none") {
7903 oIcon = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
7907 oIconParent = oIcon.parentNode;
7911 oIconParent.removeChild(oIcon);
7920 if (sIcon.indexOf(".") == -1) {
7922 oIcon = document.createElement("span");
7923 oIcon.className = (sCSSClass + " " + sIcon);
7924 oIcon.innerHTML = " ";
7928 oIcon = document.createElement("img");
7929 oIcon.src = (this.imageRoot + sIcon);
7930 oIcon.className = sCSSClass;
7937 oBody.insertBefore(oIcon, oBody.firstChild);
7946 * Fired when the "text" property is set.
7947 * @method configText
7948 * @param {String} type The CustomEvent type (usually the property name)
7949 * @param {Object[]} args The CustomEvent arguments. For configuration
7950 * handlers, args[0] will equal the newly applied value for the property.
7951 * @param {Object} obj The scope object. For configuration handlers,
7952 * this will usually equal the owner.
7954 configText: function (type,args,obj) {
7958 this.cfg.refireEvent("icon");
7962 // END BUILT-IN PROPERTY EVENT HANDLERS //
7965 * Returns a string representation of the object.
7967 * @return {String} The string representation of the SimpleDialog
7969 toString: function () {
7970 return "SimpleDialog " + this.id;
7979 * ContainerEffect encapsulates animation transitions that are executed when
7980 * an Overlay is shown or hidden.
7981 * @namespace YAHOO.widget
7982 * @class ContainerEffect
7984 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
7985 * should be associated with
7986 * @param {Object} attrIn The object literal representing the animation
7987 * arguments to be used for the animate-in transition. The arguments for
7988 * this literal are: attributes(object, see YAHOO.util.Anim for description),
7989 * duration(Number), and method(i.e. Easing.easeIn).
7990 * @param {Object} attrOut The object literal representing the animation
7991 * arguments to be used for the animate-out transition. The arguments for
7992 * this literal are: attributes(object, see YAHOO.util.Anim for description),
7993 * duration(Number), and method(i.e. Easing.easeIn).
7994 * @param {HTMLElement} targetElement Optional. The target element that
7995 * should be animated during the transition. Defaults to overlay.element.
7996 * @param {class} Optional. The animation class to instantiate. Defaults to
7997 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
7999 YAHOO.widget.ContainerEffect =
8001 function (overlay, attrIn, attrOut, targetElement, animClass) {
8004 animClass = YAHOO.util.Anim;
8008 * The overlay to animate
8010 * @type YAHOO.widget.Overlay
8012 this.overlay = overlay;
8015 * The animation attributes to use when transitioning into view
8019 this.attrIn = attrIn;
8022 * The animation attributes to use when transitioning out of view
8026 this.attrOut = attrOut;
8029 * The target element to be animated
8030 * @property targetElement
8033 this.targetElement = targetElement || overlay.element;
8036 * The animation class to use for animating the overlay
8037 * @property animClass
8040 this.animClass = animClass;
8045 var Dom = YAHOO.util.Dom,
8046 CustomEvent = YAHOO.util.CustomEvent,
8047 Easing = YAHOO.util.Easing,
8048 ContainerEffect = YAHOO.widget.ContainerEffect;
8052 * A pre-configured ContainerEffect instance that can be used for fading
8053 * an overlay in and out.
8056 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8057 * @param {Number} dur The duration of the animation
8058 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8060 ContainerEffect.FADE = function (overlay, dur) {
8062 var fade = new ContainerEffect(overlay,
8064 { attributes: { opacity: { from: 0, to: 1 } },
8066 method: Easing.easeIn },
8068 { attributes: { opacity: { to: 0 } },
8070 method: Easing.easeOut },
8075 fade.handleStartAnimateIn = function (type,args,obj) {
8076 Dom.addClass(obj.overlay.element, "hide-select");
8078 if (! obj.overlay.underlay) {
8079 obj.overlay.cfg.refireEvent("underlay");
8082 if (obj.overlay.underlay) {
8084 obj.initialUnderlayOpacity =
8085 Dom.getStyle(obj.overlay.underlay, "opacity");
8087 obj.overlay.underlay.style.filter = null;
8091 Dom.setStyle(obj.overlay.element, "visibility", "visible");
8092 Dom.setStyle(obj.overlay.element, "opacity", 0);
8096 fade.handleCompleteAnimateIn = function (type,args,obj) {
8097 Dom.removeClass(obj.overlay.element, "hide-select");
8099 if (obj.overlay.element.style.filter) {
8100 obj.overlay.element.style.filter = null;
8103 if (obj.overlay.underlay) {
8104 Dom.setStyle(obj.overlay.underlay, "opacity",
8105 obj.initialUnderlayOpacity);
8108 obj.overlay.cfg.refireEvent("iframe");
8109 obj.animateInCompleteEvent.fire();
8113 fade.handleStartAnimateOut = function (type, args, obj) {
8114 Dom.addClass(obj.overlay.element, "hide-select");
8116 if (obj.overlay.underlay) {
8117 obj.overlay.underlay.style.filter = null;
8122 fade.handleCompleteAnimateOut = function (type, args, obj) {
8123 Dom.removeClass(obj.overlay.element, "hide-select");
8124 if (obj.overlay.element.style.filter) {
8125 obj.overlay.element.style.filter = null;
8127 Dom.setStyle(obj.overlay.element, "visibility", "hidden");
8128 Dom.setStyle(obj.overlay.element, "opacity", 1);
8130 obj.overlay.cfg.refireEvent("iframe");
8132 obj.animateOutCompleteEvent.fire();
8141 * A pre-configured ContainerEffect instance that can be used for sliding an
8142 * overlay in and out.
8145 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8146 * @param {Number} dur The duration of the animation
8147 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8149 ContainerEffect.SLIDE = function (overlay, dur) {
8151 var x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
8153 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
8155 clientWidth = Dom.getClientWidth(),
8157 offsetWidth = overlay.element.offsetWidth,
8159 slide = new ContainerEffect(overlay,
8161 { attributes: { points: { to: [x, y] } },
8163 method: Easing.easeIn },
8165 { attributes: { points: { to: [(clientWidth + 25), y] } },
8167 method: Easing.easeOut },
8169 overlay.element, YAHOO.util.Motion);
8172 slide.handleStartAnimateIn = function (type,args,obj) {
8173 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
8174 obj.overlay.element.style.top = y + "px";
8177 slide.handleTweenAnimateIn = function (type, args, obj) {
8179 var pos = Dom.getXY(obj.overlay.element),
8183 if (Dom.getStyle(obj.overlay.element, "visibility") ==
8184 "hidden" && currentX < x) {
8186 Dom.setStyle(obj.overlay.element, "visibility", "visible");
8190 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
8191 obj.overlay.cfg.refireEvent("iframe");
8194 slide.handleCompleteAnimateIn = function (type, args, obj) {
8195 obj.overlay.cfg.setProperty("xy", [x, y], true);
8198 obj.overlay.cfg.refireEvent("iframe");
8199 obj.animateInCompleteEvent.fire();
8202 slide.handleStartAnimateOut = function (type, args, obj) {
8204 var vw = Dom.getViewportWidth(),
8205 pos = Dom.getXY(obj.overlay.element),
8207 currentTo = obj.animOut.attributes.points.to;
8209 obj.animOut.attributes.points.to = [(vw + 25), yso];
8213 slide.handleTweenAnimateOut = function (type, args, obj) {
8215 var pos = Dom.getXY(obj.overlay.element),
8219 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
8220 obj.overlay.cfg.refireEvent("iframe");
8223 slide.handleCompleteAnimateOut = function (type, args, obj) {
8224 Dom.setStyle(obj.overlay.element, "visibility", "hidden");
8226 obj.overlay.cfg.setProperty("xy", [x, y]);
8227 obj.animateOutCompleteEvent.fire();
8234 ContainerEffect.prototype = {
8237 * Initializes the animation classes and events.
8242 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
8243 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
8245 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
8246 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
8248 this.animateInCompleteEvent = this.createEvent("animateInComplete");
8249 this.animateInCompleteEvent.signature = CustomEvent.LIST;
8251 this.animateOutCompleteEvent =
8252 this.createEvent("animateOutComplete");
8253 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
8255 this.animIn = new this.animClass(this.targetElement,
8256 this.attrIn.attributes, this.attrIn.duration,
8257 this.attrIn.method);
8259 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
8260 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
8262 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
8265 this.animOut = new this.animClass(this.targetElement,
8266 this.attrOut.attributes, this.attrOut.duration,
8267 this.attrOut.method);
8269 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
8270 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
8271 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
8277 * Triggers the in-animation.
8280 animateIn: function () {
8281 this.beforeAnimateInEvent.fire();
8282 this.animIn.animate();
8286 * Triggers the out-animation.
8287 * @method animateOut
8289 animateOut: function () {
8290 this.beforeAnimateOutEvent.fire();
8291 this.animOut.animate();
8295 * The default onStart handler for the in-animation.
8296 * @method handleStartAnimateIn
8297 * @param {String} type The CustomEvent type
8298 * @param {Object[]} args The CustomEvent arguments
8299 * @param {Object} obj The scope object
8301 handleStartAnimateIn: function (type, args, obj) { },
8304 * The default onTween handler for the in-animation.
8305 * @method handleTweenAnimateIn
8306 * @param {String} type The CustomEvent type
8307 * @param {Object[]} args The CustomEvent arguments
8308 * @param {Object} obj The scope object
8310 handleTweenAnimateIn: function (type, args, obj) { },
8313 * The default onComplete handler for the in-animation.
8314 * @method handleCompleteAnimateIn
8315 * @param {String} type The CustomEvent type
8316 * @param {Object[]} args The CustomEvent arguments
8317 * @param {Object} obj The scope object
8319 handleCompleteAnimateIn: function (type, args, obj) { },
8322 * The default onStart handler for the out-animation.
8323 * @method handleStartAnimateOut
8324 * @param {String} type The CustomEvent type
8325 * @param {Object[]} args The CustomEvent arguments
8326 * @param {Object} obj The scope object
8328 handleStartAnimateOut: function (type, args, obj) { },
8331 * The default onTween handler for the out-animation.
8332 * @method handleTweenAnimateOut
8333 * @param {String} type The CustomEvent type
8334 * @param {Object[]} args The CustomEvent arguments
8335 * @param {Object} obj The scope object
8337 handleTweenAnimateOut: function (type, args, obj) { },
8340 * The default onComplete handler for the out-animation.
8341 * @method handleCompleteAnimateOut
8342 * @param {String} type The CustomEvent type
8343 * @param {Object[]} args The CustomEvent arguments
8344 * @param {Object} obj The scope object
8346 handleCompleteAnimateOut: function (type, args, obj) { },
8349 * Returns a string representation of the object.
8351 * @return {String} The string representation of the ContainerEffect
8353 toString: function () {
8354 var output = "ContainerEffect";
8356 output += " [" + this.overlay.toString() + "]";
8363 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
8366 YAHOO.register("container", YAHOO.widget.Module, {version: "2.3.0", build: "442"});