2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
10 * Config is a utility used within an Object to allow the implementer to
11 * maintain a list of local configuration properties and listen for changes
12 * to those properties dynamically using CustomEvent. The initial values are
13 * also maintained so that the configuration can be reset at any given point
14 * to its initial state.
15 * @namespace YAHOO.util
18 * @param {Object} owner The owner Object to which this Config Object belongs
20 YAHOO.util.Config = function (owner) {
30 var Lang = YAHOO.lang,
31 CustomEvent = YAHOO.util.CustomEvent,
32 Config = YAHOO.util.Config;
36 * Constant representing the CustomEvent type for the config changed event.
37 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
42 Config.CONFIG_CHANGED_EVENT = "configChanged";
45 * Constant representing the boolean type string
46 * @property YAHOO.util.Config.BOOLEAN_TYPE
51 Config.BOOLEAN_TYPE = "boolean";
56 * Object reference to the owner of this Config Object
63 * Boolean flag that specifies whether a queue is currently
65 * @property queueInProgress
68 queueInProgress: false,
71 * Maintains the local collection of configuration property objects and
72 * their specified values
80 * Maintains the local collection of configuration property objects as
81 * they were initially applied.
82 * This object is used when resetting a property.
83 * @property initialConfig
90 * Maintains the local, normalized CustomEvent queue
91 * @property eventQueue
98 * Custom Event, notifying subscribers when Config properties are set
99 * (setProperty is called without the silent flag
100 * @event configChangedEvent
102 configChangedEvent: null,
105 * Initializes the configuration Object and all of its local members.
107 * @param {Object} owner The owner Object to which this Config
110 init: function (owner) {
114 this.configChangedEvent =
115 this.createEvent(Config.CONFIG_CHANGED_EVENT);
117 this.configChangedEvent.signature = CustomEvent.LIST;
118 this.queueInProgress = false;
120 this.initialConfig = {};
121 this.eventQueue = [];
126 * Validates that the value passed in is a Boolean.
127 * @method checkBoolean
128 * @param {Object} val The value to validate
129 * @return {Boolean} true, if the value is valid
131 checkBoolean: function (val) {
132 return (typeof val == Config.BOOLEAN_TYPE);
136 * Validates that the value passed in is a number.
137 * @method checkNumber
138 * @param {Object} val The value to validate
139 * @return {Boolean} true, if the value is valid
141 checkNumber: function (val) {
142 return (!isNaN(val));
146 * Fires a configuration property event using the specified value.
149 * @param {String} key The configuration property's name
150 * @param {value} Object The value of the correct type for the property
152 fireEvent: function ( key, value ) {
153 var property = this.config[key];
155 if (property && property.event) {
156 property.event.fire(value);
161 * Adds a property to the Config Object's private config hash.
162 * @method addProperty
163 * @param {String} key The configuration property's name
164 * @param {Object} propertyObject The Object containing all of this
165 * property's arguments
167 addProperty: function ( key, propertyObject ) {
168 key = key.toLowerCase();
170 this.config[key] = propertyObject;
172 propertyObject.event = this.createEvent(key, { scope: this.owner });
173 propertyObject.event.signature = CustomEvent.LIST;
176 propertyObject.key = key;
178 if (propertyObject.handler) {
179 propertyObject.event.subscribe(propertyObject.handler,
183 this.setProperty(key, propertyObject.value, true);
185 if (! propertyObject.suppressEvent) {
186 this.queueProperty(key, propertyObject.value);
192 * Returns a key-value configuration map of the values currently set in
195 * @return {Object} The current config, represented in a key-value map
197 getConfig: function () {
200 currCfg = this.config,
204 for (prop in currCfg) {
205 if (Lang.hasOwnProperty(currCfg, prop)) {
206 property = currCfg[prop];
207 if (property && property.event) {
208 cfg[prop] = property.value;
217 * Returns the value of specified property.
218 * @method getProperty
219 * @param {String} key The name of the property
220 * @return {Object} The value of the specified property
222 getProperty: function (key) {
223 var property = this.config[key.toLowerCase()];
224 if (property && property.event) {
225 return property.value;
232 * Resets the specified property's value to its initial value.
233 * @method resetProperty
234 * @param {String} key The name of the property
235 * @return {Boolean} True is the property was reset, false if not
237 resetProperty: function (key) {
238 key = key.toLowerCase();
240 var property = this.config[key];
242 if (property && property.event) {
243 if (key in this.initialConfig) {
244 this.setProperty(key, this.initialConfig[key]);
253 * Sets the value of a property. If the silent property is passed as
254 * true, the property's event will not be fired.
255 * @method setProperty
256 * @param {String} key The name of the property
257 * @param {String} value The value to set the property to
258 * @param {Boolean} silent Whether the value should be set silently,
259 * without firing the property event.
260 * @return {Boolean} True, if the set was successful, false if it failed.
262 setProperty: function (key, value, silent) {
266 key = key.toLowerCase();
268 if (this.queueInProgress && ! silent) {
269 // Currently running through a queue...
270 this.queueProperty(key,value);
274 property = this.config[key];
275 if (property && property.event) {
276 if (property.validator && !property.validator(value)) {
279 property.value = value;
281 this.fireEvent(key, value);
282 this.configChangedEvent.fire([key, value]);
293 * Sets the value of a property and queues its event to execute. If the
294 * event is already scheduled to execute, it is
295 * moved from its current position to the end of the queue.
296 * @method queueProperty
297 * @param {String} key The name of the property
298 * @param {String} value The value to set the property to
299 * @return {Boolean} true, if the set was successful, false if
302 queueProperty: function (key, value) {
304 key = key.toLowerCase();
306 var property = this.config[key],
307 foundDuplicate = false,
322 if (property && property.event) {
324 if (!Lang.isUndefined(value) && property.validator &&
325 !property.validator(value)) { // validator
329 if (!Lang.isUndefined(value)) {
330 property.value = value;
332 value = property.value;
335 foundDuplicate = false;
336 iLen = this.eventQueue.length;
338 for (i = 0; i < iLen; i++) {
339 queueItem = this.eventQueue[i];
342 queueItemKey = queueItem[0];
343 queueItemValue = queueItem[1];
345 if (queueItemKey == key) {
348 found a dupe... push to end of queue, null
349 current item, and break
352 this.eventQueue[i] = null;
354 this.eventQueue.push(
355 [key, (!Lang.isUndefined(value) ?
356 value : queueItemValue)]);
358 foundDuplicate = true;
364 // this is a refire, or a new property in the queue
366 if (! foundDuplicate && !Lang.isUndefined(value)) {
367 this.eventQueue.push([key, value]);
371 if (property.supercedes) {
373 sLen = property.supercedes.length;
375 for (s = 0; s < sLen; s++) {
377 supercedesCheck = property.supercedes[s];
378 qLen = this.eventQueue.length;
380 for (q = 0; q < qLen; q++) {
381 queueItemCheck = this.eventQueue[q];
383 if (queueItemCheck) {
384 queueItemCheckKey = queueItemCheck[0];
385 queueItemCheckValue = queueItemCheck[1];
387 if (queueItemCheckKey ==
388 supercedesCheck.toLowerCase() ) {
390 this.eventQueue.push([queueItemCheckKey,
391 queueItemCheckValue]);
393 this.eventQueue[q] = null;
410 * Fires the event for a property using the property's current value.
411 * @method refireEvent
412 * @param {String} key The name of the property
414 refireEvent: function (key) {
416 key = key.toLowerCase();
418 var property = this.config[key];
420 if (property && property.event &&
422 !Lang.isUndefined(property.value)) {
424 if (this.queueInProgress) {
426 this.queueProperty(key);
430 this.fireEvent(key, property.value);
438 * Applies a key-value Object literal to the configuration, replacing
439 * any existing values, and queueing the property events.
440 * Although the values will be set, fireQueue() must be called for their
441 * associated events to execute.
442 * @method applyConfig
443 * @param {Object} userConfig The configuration Object literal
444 * @param {Boolean} init When set to true, the initialConfig will
445 * be set to the userConfig passed in, so that calling a reset will
446 * reset the properties to the passed values.
448 applyConfig: function (userConfig, init) {
455 for (sKey in userConfig) {
456 if (Lang.hasOwnProperty(userConfig, sKey)) {
457 oConfig[sKey.toLowerCase()] = userConfig[sKey];
460 this.initialConfig = oConfig;
463 for (sKey in userConfig) {
464 if (Lang.hasOwnProperty(userConfig, sKey)) {
465 this.queueProperty(sKey, userConfig[sKey]);
471 * Refires the events for all configuration properties using their
475 refresh: function () {
479 for (prop in this.config) {
480 if (Lang.hasOwnProperty(this.config, prop)) {
481 this.refireEvent(prop);
487 * Fires the normalized list of queued property change events
490 fireQueue: function () {
498 this.queueInProgress = true;
499 for (i = 0;i < this.eventQueue.length; i++) {
500 queueItem = this.eventQueue[i];
504 value = queueItem[1];
505 property = this.config[key];
507 property.value = value;
509 // Clear out queue entry, to avoid it being
510 // re-added to the queue by any queueProperty/supercedes
511 // calls which are invoked during fireEvent
512 this.eventQueue[i] = null;
514 this.fireEvent(key,value);
518 this.queueInProgress = false;
519 this.eventQueue = [];
523 * Subscribes an external handler to the change event for any
525 * @method subscribeToConfigEvent
526 * @param {String} key The property name
527 * @param {Function} handler The handler function to use subscribe to
528 * the property's event
529 * @param {Object} obj The Object to use for scoping the event handler
530 * (see CustomEvent documentation)
531 * @param {Boolean} overrideContext Optional. If true, will override
532 * "this" within the handler to map to the scope Object passed into the
534 * @return {Boolean} True, if the subscription was successful,
537 subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
539 var property = this.config[key.toLowerCase()];
541 if (property && property.event) {
542 if (!Config.alreadySubscribed(property.event, handler, obj)) {
543 property.event.subscribe(handler, obj, overrideContext);
553 * Unsubscribes an external handler from the change event for any
555 * @method unsubscribeFromConfigEvent
556 * @param {String} key The property name
557 * @param {Function} handler The handler function to use subscribe to
558 * the property's event
559 * @param {Object} obj The Object to use for scoping the event
560 * handler (see CustomEvent documentation)
561 * @return {Boolean} True, if the unsubscription was successful,
564 unsubscribeFromConfigEvent: function (key, handler, obj) {
565 var property = this.config[key.toLowerCase()];
566 if (property && property.event) {
567 return property.event.unsubscribe(handler, obj);
574 * Returns a string representation of the Config object
576 * @return {String} The Config object in string format.
578 toString: function () {
579 var output = "Config";
581 output += " [" + this.owner.toString() + "]";
587 * Returns a string representation of the Config object's current
589 * @method outputEventQueue
590 * @return {String} The string list of CustomEvents currently queued
593 outputEventQueue: function () {
598 nQueue = this.eventQueue.length;
600 for (q = 0; q < nQueue; q++) {
601 queueItem = this.eventQueue[q];
603 output += queueItem[0] + "=" + queueItem[1] + ", ";
610 * Sets all properties to null, unsubscribes all listeners from each
611 * property's change event and all listeners from the configChangedEvent.
614 destroy: function () {
616 var oConfig = this.config,
621 for (sProperty in oConfig) {
623 if (Lang.hasOwnProperty(oConfig, sProperty)) {
625 oProperty = oConfig[sProperty];
627 oProperty.event.unsubscribeAll();
628 oProperty.event = null;
634 this.configChangedEvent.unsubscribeAll();
636 this.configChangedEvent = null;
639 this.initialConfig = null;
640 this.eventQueue = null;
649 * Checks to determine if a particular function/Object pair are already
650 * subscribed to the specified CustomEvent
651 * @method YAHOO.util.Config.alreadySubscribed
653 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
655 * @param {Function} fn The function to look for in the subscribers list
656 * @param {Object} obj The execution scope Object for the subscription
657 * @return {Boolean} true, if the function/Object pair is already subscribed
658 * to the CustomEvent passed in
660 Config.alreadySubscribed = function (evt, fn, obj) {
662 var nSubscribers = evt.subscribers.length,
666 if (nSubscribers > 0) {
667 i = nSubscribers - 1;
669 subsc = evt.subscribers[i];
670 if (subsc && subsc.obj == obj && subsc.fn == fn) {
681 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
687 * The Container family of components is designed to enable developers to
688 * create different kinds of content-containing modules on the web. Module
689 * and Overlay are the most basic containers, and they can be used directly
690 * or extended to build custom containers. Also part of the Container family
691 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
692 * Dialog, and SimpleDialog.
695 * @requires yahoo, dom, event
696 * @optional dragdrop, animation, button
700 * Module is a JavaScript representation of the Standard Module Format.
701 * Standard Module Format is a simple standard for markup containers where
702 * child nodes representing the header, body, and footer of the content are
703 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
704 * Module is the base class for all other classes in the YUI
706 * @namespace YAHOO.widget
709 * @param {String} el The element ID representing the Module <em>OR</em>
710 * @param {HTMLElement} el The element representing the Module
711 * @param {Object} userConfig The configuration Object literal containing
712 * the configuration that should be set for this module. See configuration
713 * documentation for more details.
715 YAHOO.widget.Module = function (el, userConfig) {
717 this.init(el, userConfig);
722 var Dom = YAHOO.util.Dom,
723 Config = YAHOO.util.Config,
724 Event = YAHOO.util.Event,
725 CustomEvent = YAHOO.util.CustomEvent,
726 Module = YAHOO.widget.Module,
735 * Constant representing the name of the Module's events
736 * @property EVENT_TYPES
742 "BEFORE_INIT": "beforeInit",
745 "BEFORE_RENDER": "beforeRender",
747 "CHANGE_HEADER": "changeHeader",
748 "CHANGE_BODY": "changeBody",
749 "CHANGE_FOOTER": "changeFooter",
750 "CHANGE_CONTENT": "changeContent",
751 "DESTROY": "destroy",
752 "BEFORE_SHOW": "beforeShow",
754 "BEFORE_HIDE": "beforeHide",
759 * Constant representing the Module's configuration properties
760 * @property DEFAULT_CONFIG
770 validator: YAHOO.lang.isBoolean
776 supercedes: ["visible"]
780 key: "monitorresize",
784 "APPEND_TO_DOCUMENT_BODY": {
785 key: "appendtodocumentbody",
791 * Constant representing the prefix path to use for non-secure images
792 * @property YAHOO.widget.Module.IMG_ROOT
797 Module.IMG_ROOT = null;
800 * Constant representing the prefix path to use for securely served images
801 * @property YAHOO.widget.Module.IMG_ROOT_SSL
806 Module.IMG_ROOT_SSL = null;
809 * Constant for the default CSS class name that represents a Module
810 * @property YAHOO.widget.Module.CSS_MODULE
815 Module.CSS_MODULE = "yui-module";
818 * CSS classname representing the module header. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
819 * @property YAHOO.widget.Module.CSS_HEADER
824 Module.CSS_HEADER = "hd";
827 * CSS classname representing the module body. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
828 * @property YAHOO.widget.Module.CSS_BODY
833 Module.CSS_BODY = "bd";
836 * CSS classname representing the module footer. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
837 * @property YAHOO.widget.Module.CSS_FOOTER
842 Module.CSS_FOOTER = "ft";
845 * Constant representing the url for the "src" attribute of the iframe
846 * used to monitor changes to the browser's base font size
847 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
852 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
855 * Constant representing the buffer amount (in pixels) to use when positioning
856 * the text resize monitor offscreen. The resize monitor is positioned
857 * offscreen by an amount eqaul to its offsetHeight + the buffer value.
859 * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
863 // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
864 Module.RESIZE_MONITOR_BUFFER = 1;
867 * Singleton CustomEvent fired when the font size is changed in the browser.
868 * Opera's "zoom" functionality currently does not support text
870 * @event YAHOO.widget.Module.textResizeEvent
872 Module.textResizeEvent = new CustomEvent("textResize");
875 * Helper utility method, which forces a document level
876 * redraw for Opera, which can help remove repaint
877 * irregularities after applying DOM changes.
879 * @method YAHOO.widget.Module.forceDocumentRedraw
882 Module.forceDocumentRedraw = function() {
883 var docEl = document.documentElement;
885 docEl.className += " ";
886 docEl.className = YAHOO.lang.trim(docEl.className);
890 function createModuleTemplate() {
892 if (!m_oModuleTemplate) {
893 m_oModuleTemplate = document.createElement("div");
895 m_oModuleTemplate.innerHTML = ("<div class=\"" +
896 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
897 Module.CSS_BODY + "\"></div><div class=\"" +
898 Module.CSS_FOOTER + "\"></div>");
900 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
901 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
902 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
905 return m_oModuleTemplate;
908 function createHeader() {
909 if (!m_oHeaderTemplate) {
910 createModuleTemplate();
912 return (m_oHeaderTemplate.cloneNode(false));
915 function createBody() {
916 if (!m_oBodyTemplate) {
917 createModuleTemplate();
919 return (m_oBodyTemplate.cloneNode(false));
922 function createFooter() {
923 if (!m_oFooterTemplate) {
924 createModuleTemplate();
926 return (m_oFooterTemplate.cloneNode(false));
932 * The class's constructor function
933 * @property contructor
939 * The main module element that contains the header, body, and footer
946 * The header element, denoted with CSS class "hd"
953 * The body element, denoted with CSS class "bd"
960 * The footer element, denoted with CSS class "ft"
967 * The id of the element
974 * A string representing the root path for all images created by
976 * @deprecated It is recommend that any images for a Module be applied
977 * via CSS using the "background-image" property.
978 * @property imageRoot
981 imageRoot: Module.IMG_ROOT,
984 * Initializes the custom events for Module which are fired
985 * automatically at appropriate times by the Module class.
988 initEvents: function () {
990 var SIGNATURE = CustomEvent.LIST;
993 * CustomEvent fired prior to class initalization.
994 * @event beforeInitEvent
995 * @param {class} classRef class reference of the initializing
996 * class, such as this.beforeInitEvent.fire(Module)
998 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
999 this.beforeInitEvent.signature = SIGNATURE;
1002 * CustomEvent fired after class initalization.
1004 * @param {class} classRef class reference of the initializing
1005 * class, such as this.beforeInitEvent.fire(Module)
1007 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1008 this.initEvent.signature = SIGNATURE;
1011 * CustomEvent fired when the Module is appended to the DOM
1012 * @event appendEvent
1014 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1015 this.appendEvent.signature = SIGNATURE;
1018 * CustomEvent fired before the Module is rendered
1019 * @event beforeRenderEvent
1021 this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1022 this.beforeRenderEvent.signature = SIGNATURE;
1025 * CustomEvent fired after the Module is rendered
1026 * @event renderEvent
1028 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1029 this.renderEvent.signature = SIGNATURE;
1032 * CustomEvent fired when the header content of the Module
1034 * @event changeHeaderEvent
1035 * @param {String/HTMLElement} content String/element representing
1036 * the new header content
1038 this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1039 this.changeHeaderEvent.signature = SIGNATURE;
1042 * CustomEvent fired when the body content of the Module is modified
1043 * @event changeBodyEvent
1044 * @param {String/HTMLElement} content String/element representing
1045 * the new body content
1047 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1048 this.changeBodyEvent.signature = SIGNATURE;
1051 * CustomEvent fired when the footer content of the Module
1053 * @event changeFooterEvent
1054 * @param {String/HTMLElement} content String/element representing
1055 * the new footer content
1057 this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1058 this.changeFooterEvent.signature = SIGNATURE;
1061 * CustomEvent fired when the content of the Module is modified
1062 * @event changeContentEvent
1064 this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1065 this.changeContentEvent.signature = SIGNATURE;
1068 * CustomEvent fired when the Module is destroyed
1069 * @event destroyEvent
1071 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
1072 this.destroyEvent.signature = SIGNATURE;
1075 * CustomEvent fired before the Module is shown
1076 * @event beforeShowEvent
1078 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1079 this.beforeShowEvent.signature = SIGNATURE;
1082 * CustomEvent fired after the Module is shown
1085 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1086 this.showEvent.signature = SIGNATURE;
1089 * CustomEvent fired before the Module is hidden
1090 * @event beforeHideEvent
1092 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1093 this.beforeHideEvent.signature = SIGNATURE;
1096 * CustomEvent fired after the Module is hidden
1099 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1100 this.hideEvent.signature = SIGNATURE;
1104 * String identifying whether the current platform is windows or mac. This property
1105 * currently only identifies these 2 platforms, and returns false otherwise.
1106 * @property platform
1107 * @deprecated Use YAHOO.env.ua
1108 * @type {String|Boolean}
1110 platform: function () {
1111 var ua = navigator.userAgent.toLowerCase();
1113 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1115 } else if (ua.indexOf("macintosh") != -1) {
1123 * String representing the user-agent of the browser
1124 * @deprecated Use YAHOO.env.ua
1126 * @type {String|Boolean}
1128 browser: function () {
1129 var ua = navigator.userAgent.toLowerCase();
1131 Check Opera first in case of spoof and check Safari before
1132 Gecko since Safari's user agent string includes "like Gecko"
1134 if (ua.indexOf('opera') != -1) {
1136 } else if (ua.indexOf('msie 7') != -1) {
1138 } else if (ua.indexOf('msie') != -1) {
1140 } else if (ua.indexOf('safari') != -1) {
1142 } else if (ua.indexOf('gecko') != -1) {
1150 * Boolean representing whether or not the current browsing context is
1152 * @property isSecure
1155 isSecure: function () {
1156 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1164 * Initializes the custom events for Module which are fired
1165 * automatically at appropriate times by the Module class.
1167 initDefaultConfig: function () {
1168 // Add properties //
1170 * Specifies whether the Module is visible on the page.
1175 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1176 handler: this.configVisible,
1177 value: DEFAULT_CONFIG.VISIBLE.value,
1178 validator: DEFAULT_CONFIG.VISIBLE.validator
1183 * Object or array of objects representing the ContainerEffect
1184 * classes that are active for animating the container.
1187 * <strong>NOTE:</strong> Although this configuration
1188 * property is introduced at the Module level, an out of the box
1189 * implementation is not shipped for the Module class so setting
1190 * the proroperty on the Module class has no effect. The Overlay
1191 * class is the first class to provide out of the box ContainerEffect
1198 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1199 handler: this.configEffect,
1200 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1201 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1205 * Specifies whether to create a special proxy iframe to monitor
1206 * for user font resizing in the document
1207 * @config monitorresize
1211 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1212 handler: this.configMonitorResize,
1213 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1217 * Specifies if the module should be rendered as the first child
1218 * of document.body or appended as the last child when render is called
1219 * with document.body as the "appendToNode".
1221 * Appending to the body while the DOM is still being constructed can
1222 * lead to Operation Aborted errors in IE hence this flag is set to
1226 * @config appendtodocumentbody
1230 this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1231 value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1236 * The Module class's initialization method, which is executed for
1237 * Module and all of its subclasses. This method is automatically
1238 * called by the constructor, and sets up all DOM references for
1239 * pre-existing markup, and creates required markup if it is not
1242 * If the element passed in does not have an id, one will be generated
1246 * @param {String} el The element ID representing the Module <em>OR</em>
1247 * @param {HTMLElement} el The element representing the Module
1248 * @param {Object} userConfig The configuration Object literal
1249 * containing the configuration that should be set for this module.
1250 * See configuration documentation for more details.
1252 init: function (el, userConfig) {
1257 this.beforeInitEvent.fire(Module);
1260 * The Module's Config object used for monitoring
1261 * configuration properties.
1263 * @type YAHOO.util.Config
1265 this.cfg = new Config(this);
1267 if (this.isSecure) {
1268 this.imageRoot = Module.IMG_ROOT_SSL;
1271 if (typeof el == "string") {
1273 el = document.getElementById(el);
1275 el = (createModuleTemplate()).cloneNode(false);
1280 this.id = Dom.generateId(el);
1283 child = this.element.firstChild;
1286 var fndHd = false, fndBd = false, fndFt = false;
1288 // We're looking for elements
1289 if (1 == child.nodeType) {
1290 if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1291 this.header = child;
1293 } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1296 } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1297 this.footer = child;
1301 } while ((child = child.nextSibling));
1304 this.initDefaultConfig();
1306 Dom.addClass(this.element, Module.CSS_MODULE);
1309 this.cfg.applyConfig(userConfig, true);
1313 Subscribe to the fireQueue() method of Config so that any
1314 queued configuration changes are excecuted upon render of
1318 if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1319 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1322 this.initEvent.fire(Module);
1326 * Initialize an empty IFRAME that is placed out of the visible area
1327 * that can be used to detect text resize.
1328 * @method initResizeMonitor
1330 initResizeMonitor: function () {
1332 var isGeckoWin = (UA.gecko && this.platform == "windows");
1334 // Help prevent spinning loading icon which
1335 // started with FireFox 2.0.0.8/Win
1337 setTimeout(function(){self._initResizeMonitor();}, 0);
1339 this._initResizeMonitor();
1344 * Create and initialize the text resize monitoring iframe.
1347 * @method _initResizeMonitor
1349 _initResizeMonitor : function() {
1355 function fireTextResize() {
1356 Module.textResizeEvent.fire();
1360 oIFrame = Dom.get("_yuiResizeMonitor");
1362 var supportsCWResize = this._supportsCWResize();
1365 oIFrame = document.createElement("iframe");
1367 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1368 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1371 if (!supportsCWResize) {
1372 // Can't monitor on contentWindow, so fire from inside iframe
1373 sHTML = ["<html><head><script ",
1374 "type=\"text/javascript\">",
1375 "window.onresize=function(){window.parent.",
1376 "YAHOO.widget.Module.textResizeEvent.",
1379 "<body></body></html>"].join('');
1381 oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1384 oIFrame.id = "_yuiResizeMonitor";
1385 oIFrame.title = "Text Resize Monitor";
1386 oIFrame.tabIndex = -1;
1387 oIFrame.setAttribute("role", "presentation");
1390 Need to set "position" property before inserting the
1391 iframe into the document or Safari's status bar will
1392 forever indicate the iframe is loading
1393 (See YUILibrary bug #1723064)
1395 oIFrame.style.position = "absolute";
1396 oIFrame.style.visibility = "hidden";
1398 var db = document.body,
1401 db.insertBefore(oIFrame, fc);
1403 db.appendChild(oIFrame);
1406 // Setting the background color fixes an issue with IE6/IE7, where
1407 // elements in the DOM, with -ve margin-top which positioned them
1408 // offscreen (so they would be overlapped by the iframe and its -ve top
1409 // setting), would have their -ve margin-top ignored, when the iframe
1411 oIFrame.style.backgroundColor = "transparent";
1413 oIFrame.style.borderWidth = "0";
1414 oIFrame.style.width = "2em";
1415 oIFrame.style.height = "2em";
1416 oIFrame.style.left = "0";
1417 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1418 oIFrame.style.visibility = "visible";
1421 Don't open/close the document for Gecko like we used to, since it
1422 leads to duplicate cookies. (See YUILibrary bug #1721755)
1425 oDoc = oIFrame.contentWindow.document;
1431 if (oIFrame && oIFrame.contentWindow) {
1432 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1434 if (!Module.textResizeInitialized) {
1435 if (supportsCWResize) {
1436 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1438 This will fail in IE if document.domain has
1439 changed, so we must change the listener to
1440 use the oIFrame element instead
1442 Event.on(oIFrame, "resize", fireTextResize);
1445 Module.textResizeInitialized = true;
1447 this.resizeMonitor = oIFrame;
1453 * Text resize monitor helper method.
1454 * Determines if the browser supports resize events on iframe content windows.
1457 * @method _supportsCWResize
1459 _supportsCWResize : function() {
1461 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1462 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1464 We don't want to start sniffing for patch versions, so fire textResize the same
1465 way on all FF2 flavors
1467 var bSupported = true;
1468 if (UA.gecko && UA.gecko <= 1.8) {
1475 * Event handler fired when the resize monitor element is resized.
1476 * @method onDomResize
1477 * @param {DOMEvent} e The DOM resize event
1478 * @param {Object} obj The scope object passed to the handler
1480 onDomResize: function (e, obj) {
1482 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1484 this.resizeMonitor.style.top = nTop + "px";
1485 this.resizeMonitor.style.left = "0";
1489 * Sets the Module's header content to the markup specified, or appends
1490 * the passed element to the header.
1492 * If no header is present, one will
1493 * be automatically created. An empty string can be passed to the method
1494 * to clear the contents of the header.
1497 * @param {HTML} headerContent The markup used to set the header content.
1498 * As a convenience, non HTMLElement objects can also be passed into
1499 * the method, and will be treated as strings, with the header innerHTML
1500 * set to their default toString implementations.
1502 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1505 * @param {HTMLElement} headerContent The HTMLElement to append to
1507 * @param {DocumentFragment} headerContent The document fragment
1508 * containing elements which are to be added to the header
1510 setHeader: function (headerContent) {
1511 var oHeader = this.header || (this.header = createHeader());
1513 if (headerContent.nodeName) {
1514 oHeader.innerHTML = "";
1515 oHeader.appendChild(headerContent);
1517 oHeader.innerHTML = headerContent;
1520 if (this._rendered) {
1521 this._renderHeader();
1524 this.changeHeaderEvent.fire(headerContent);
1525 this.changeContentEvent.fire();
1530 * Appends the passed element to the header. If no header is present,
1531 * one will be automatically created.
1532 * @method appendToHeader
1533 * @param {HTMLElement | DocumentFragment} element The element to
1534 * append to the header. In the case of a document fragment, the
1535 * children of the fragment will be appended to the header.
1537 appendToHeader: function (element) {
1538 var oHeader = this.header || (this.header = createHeader());
1540 oHeader.appendChild(element);
1542 this.changeHeaderEvent.fire(element);
1543 this.changeContentEvent.fire();
1548 * Sets the Module's body content to the HTML specified.
1550 * If no body is present, one will be automatically created.
1552 * An empty string can be passed to the method to clear the contents of the body.
1554 * @param {HTML} bodyContent The HTML used to set the body content
1555 * As a convenience, non HTMLElement objects can also be passed into
1556 * the method, and will be treated as strings, with the body innerHTML
1557 * set to their default toString implementations.
1559 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1562 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1563 * child of the body element.
1565 * @param {DocumentFragment} bodyContent The document fragment
1566 * containing elements which are to be added to the body
1568 setBody: function (bodyContent) {
1569 var oBody = this.body || (this.body = createBody());
1571 if (bodyContent.nodeName) {
1572 oBody.innerHTML = "";
1573 oBody.appendChild(bodyContent);
1575 oBody.innerHTML = bodyContent;
1578 if (this._rendered) {
1582 this.changeBodyEvent.fire(bodyContent);
1583 this.changeContentEvent.fire();
1587 * Appends the passed element to the body. If no body is present, one
1588 * will be automatically created.
1589 * @method appendToBody
1590 * @param {HTMLElement | DocumentFragment} element The element to
1591 * append to the body. In the case of a document fragment, the
1592 * children of the fragment will be appended to the body.
1595 appendToBody: function (element) {
1596 var oBody = this.body || (this.body = createBody());
1598 oBody.appendChild(element);
1600 this.changeBodyEvent.fire(element);
1601 this.changeContentEvent.fire();
1606 * Sets the Module's footer content to the HTML specified, or appends
1607 * the passed element to the footer. If no footer is present, one will
1608 * be automatically created. An empty string can be passed to the method
1609 * to clear the contents of the footer.
1611 * @param {HTML} footerContent The HTML used to set the footer
1612 * As a convenience, non HTMLElement objects can also be passed into
1613 * the method, and will be treated as strings, with the footer innerHTML
1614 * set to their default toString implementations.
1616 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1619 * @param {HTMLElement} footerContent The HTMLElement to append to
1622 * @param {DocumentFragment} footerContent The document fragment containing
1623 * elements which are to be added to the footer
1625 setFooter: function (footerContent) {
1627 var oFooter = this.footer || (this.footer = createFooter());
1629 if (footerContent.nodeName) {
1630 oFooter.innerHTML = "";
1631 oFooter.appendChild(footerContent);
1633 oFooter.innerHTML = footerContent;
1636 if (this._rendered) {
1637 this._renderFooter();
1640 this.changeFooterEvent.fire(footerContent);
1641 this.changeContentEvent.fire();
1645 * Appends the passed element to the footer. If no footer is present,
1646 * one will be automatically created.
1647 * @method appendToFooter
1648 * @param {HTMLElement | DocumentFragment} element The element to
1649 * append to the footer. In the case of a document fragment, the
1650 * children of the fragment will be appended to the footer
1652 appendToFooter: function (element) {
1654 var oFooter = this.footer || (this.footer = createFooter());
1656 oFooter.appendChild(element);
1658 this.changeFooterEvent.fire(element);
1659 this.changeContentEvent.fire();
1664 * Renders the Module by inserting the elements that are not already
1665 * in the main Module into their correct places. Optionally appends
1666 * the Module to the specified node prior to the render's execution.
1668 * For Modules without existing markup, the appendToNode argument
1669 * is REQUIRED. If this argument is ommitted and the current element is
1670 * not present in the document, the function will return false,
1671 * indicating that the render was a failure.
1674 * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1675 * then the module is rendered as the first child of the body element,
1676 * and not appended to it, to avoid Operation Aborted errors in IE when
1677 * rendering the module before window's load event is fired. You can
1678 * use the appendtodocumentbody configuration property to change this
1679 * to append to document.body if required.
1682 * @param {String} appendToNode The element id to which the Module
1683 * should be appended to prior to rendering <em>OR</em>
1684 * @param {HTMLElement} appendToNode The element to which the Module
1685 * should be appended to prior to rendering
1686 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1687 * represents the actual Standard Module container.
1688 * @return {Boolean} Success or failure of the render
1690 render: function (appendToNode, moduleElement) {
1694 function appendTo(parentNode) {
1695 if (typeof parentNode == "string") {
1696 parentNode = document.getElementById(parentNode);
1700 me._addToParent(parentNode, me.element);
1701 me.appendEvent.fire();
1705 this.beforeRenderEvent.fire();
1707 if (! moduleElement) {
1708 moduleElement = this.element;
1712 appendTo(appendToNode);
1714 // No node was passed in. If the element is not already in the Dom, this fails
1715 if (! Dom.inDocument(this.element)) {
1720 this._renderHeader(moduleElement);
1721 this._renderBody(moduleElement);
1722 this._renderFooter(moduleElement);
1724 this._rendered = true;
1726 this.renderEvent.fire();
1731 * Renders the currently set header into it's proper position under the
1732 * module element. If the module element is not provided, "this.element"
1735 * @method _renderHeader
1737 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1739 _renderHeader: function(moduleElement){
1740 moduleElement = moduleElement || this.element;
1742 // Need to get everything into the DOM if it isn't already
1743 if (this.header && !Dom.inDocument(this.header)) {
1744 // There is a header, but it's not in the DOM yet. Need to add it.
1745 var firstChild = moduleElement.firstChild;
1747 moduleElement.insertBefore(this.header, firstChild);
1749 moduleElement.appendChild(this.header);
1755 * Renders the currently set body into it's proper position under the
1756 * module element. If the module element is not provided, "this.element"
1759 * @method _renderBody
1761 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1763 _renderBody: function(moduleElement){
1764 moduleElement = moduleElement || this.element;
1766 if (this.body && !Dom.inDocument(this.body)) {
1767 // There is a body, but it's not in the DOM yet. Need to add it.
1768 if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1769 moduleElement.insertBefore(this.body, this.footer);
1771 moduleElement.appendChild(this.body);
1777 * Renders the currently set footer into it's proper position under the
1778 * module element. If the module element is not provided, "this.element"
1781 * @method _renderFooter
1783 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1785 _renderFooter: function(moduleElement){
1786 moduleElement = moduleElement || this.element;
1788 if (this.footer && !Dom.inDocument(this.footer)) {
1789 // There is a footer, but it's not in the DOM yet. Need to add it.
1790 moduleElement.appendChild(this.footer);
1795 * Removes the Module element from the DOM, sets all child elements to null, and purges the bounding element of event listeners.
1797 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
1798 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
1800 destroy: function (shallowPurge) {
1803 purgeChildren = !(shallowPurge);
1806 Event.purgeElement(this.element, purgeChildren);
1807 parent = this.element.parentNode;
1811 parent.removeChild(this.element);
1814 this.element = null;
1819 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1824 this.destroyEvent.fire();
1828 * Shows the Module element by setting the visible configuration
1829 * property to true. Also fires two events: beforeShowEvent prior to
1830 * the visibility change, and showEvent after.
1834 this.cfg.setProperty("visible", true);
1838 * Hides the Module element by setting the visible configuration
1839 * property to false. Also fires two events: beforeHideEvent prior to
1840 * the visibility change, and hideEvent after.
1844 this.cfg.setProperty("visible", false);
1847 // BUILT-IN EVENT HANDLERS FOR MODULE //
1849 * Default event handler for changing the visibility property of a
1850 * Module. By default, this is achieved by switching the "display" style
1851 * between "block" and "none".
1852 * This method is responsible for firing showEvent and hideEvent.
1853 * @param {String} type The CustomEvent type (usually the property name)
1854 * @param {Object[]} args The CustomEvent arguments. For configuration
1855 * handlers, args[0] will equal the newly applied value for the property.
1856 * @param {Object} obj The scope object. For configuration handlers,
1857 * this will usually equal the owner.
1858 * @method configVisible
1860 configVisible: function (type, args, obj) {
1861 var visible = args[0];
1863 if(this.beforeShowEvent.fire()) {
1864 Dom.setStyle(this.element, "display", "block");
1865 this.showEvent.fire();
1868 if (this.beforeHideEvent.fire()) {
1869 Dom.setStyle(this.element, "display", "none");
1870 this.hideEvent.fire();
1876 * Default event handler for the "effect" configuration property
1877 * @param {String} type The CustomEvent type (usually the property name)
1878 * @param {Object[]} args The CustomEvent arguments. For configuration
1879 * handlers, args[0] will equal the newly applied value for the property.
1880 * @param {Object} obj The scope object. For configuration handlers,
1881 * this will usually equal the owner.
1882 * @method configEffect
1884 configEffect: function (type, args, obj) {
1885 this._cachedEffects = (this.cacheEffects) ? this._createEffects(args[0]) : null;
1889 * If true, ContainerEffects (and Anim instances) are cached when "effect" is set, and reused.
1890 * If false, new instances are created each time the container is hidden or shown, as was the
1891 * behavior prior to 2.9.0.
1893 * @property cacheEffects
1898 cacheEffects : true,
1901 * Creates an array of ContainerEffect instances from the provided configs
1903 * @method _createEffects
1904 * @param {Array|Object} effectCfg An effect configuration or array of effect configurations
1905 * @return {Array} An array of ContainerEffect instances.
1908 _createEffects: function(effectCfg) {
1909 var effectInstances = null,
1915 if (effectCfg instanceof Array) {
1916 effectInstances = [];
1917 n = effectCfg.length;
1918 for (i = 0; i < n; i++) {
1921 effectInstances[effectInstances.length] = eff.effect(this, eff.duration);
1924 } else if (effectCfg.effect) {
1925 effectInstances = [effectCfg.effect(this, effectCfg.duration)];
1929 return effectInstances;
1933 * Default event handler for the "monitorresize" configuration property
1934 * @param {String} type The CustomEvent type (usually the property name)
1935 * @param {Object[]} args The CustomEvent arguments. For configuration
1936 * handlers, args[0] will equal the newly applied value for the property.
1937 * @param {Object} obj The scope object. For configuration handlers,
1938 * this will usually equal the owner.
1939 * @method configMonitorResize
1941 configMonitorResize: function (type, args, obj) {
1942 var monitor = args[0];
1944 this.initResizeMonitor();
1946 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1947 this.resizeMonitor = null;
1952 * This method is a protected helper, used when constructing the DOM structure for the module
1953 * to account for situations which may cause Operation Aborted errors in IE. It should not
1954 * be used for general DOM construction.
1956 * If the parentNode is not document.body, the element is appended as the last element.
1959 * If the parentNode is document.body the element is added as the first child to help
1960 * prevent Operation Aborted errors in IE.
1963 * @param {parentNode} The HTML element to which the element will be added
1964 * @param {element} The HTML element to be added to parentNode's children
1965 * @method _addToParent
1968 _addToParent: function(parentNode, element) {
1969 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1970 parentNode.insertBefore(element, parentNode.firstChild);
1972 parentNode.appendChild(element);
1977 * Returns a String representation of the Object.
1979 * @return {String} The string representation of the Module
1981 toString: function () {
1982 return "Module " + this.id;
1986 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1992 * Overlay is a Module that is absolutely positioned above the page flow. It
1993 * has convenience methods for positioning and sizing, as well as options for
1994 * controlling zIndex and constraining the Overlay's position to the current
1995 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1996 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1997 * properly rendered above SELECT elements.
1998 * @namespace YAHOO.widget
2000 * @extends YAHOO.widget.Module
2001 * @param {String} el The element ID representing the Overlay <em>OR</em>
2002 * @param {HTMLElement} el The element representing the Overlay
2003 * @param {Object} userConfig The configuration object literal containing
2004 * the configuration that should be set for this Overlay. See configuration
2005 * documentation for more details.
2008 YAHOO.widget.Overlay = function (el, userConfig) {
2009 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
2012 var Lang = YAHOO.lang,
2013 CustomEvent = YAHOO.util.CustomEvent,
2014 Module = YAHOO.widget.Module,
2015 Event = YAHOO.util.Event,
2016 Dom = YAHOO.util.Dom,
2017 Config = YAHOO.util.Config,
2019 Overlay = YAHOO.widget.Overlay,
2021 _SUBSCRIBE = "subscribe",
2022 _UNSUBSCRIBE = "unsubscribe",
2023 _CONTAINED = "contained",
2028 * Constant representing the name of the Overlay's events
2029 * @property EVENT_TYPES
2035 "BEFORE_MOVE": "beforeMove",
2040 * Constant representing the Overlay's configuration properties
2041 * @property DEFAULT_CONFIG
2050 validator: Lang.isNumber,
2051 suppressEvent: true,
2052 supercedes: ["iframe"]
2057 validator: Lang.isNumber,
2058 suppressEvent: true,
2059 supercedes: ["iframe"]
2064 suppressEvent: true,
2065 supercedes: ["iframe"]
2070 suppressEvent: true,
2071 supercedes: ["iframe"]
2077 supercedes: ["iframe", "visible"]
2082 suppressEvent: true,
2083 supercedes: ["context", "fixedcenter", "iframe"]
2088 suppressEvent: true,
2089 supercedes: ["context", "fixedcenter", "iframe"]
2092 "AUTO_FILL_HEIGHT" : {
2093 key: "autofillheight",
2094 supercedes: ["height"],
2103 "CONSTRAIN_TO_VIEWPORT": {
2104 key: "constraintoviewport",
2106 validator: Lang.isBoolean,
2107 supercedes: ["iframe", "x", "y", "xy"]
2112 value: (UA.ie == 6 ? true : false),
2113 validator: Lang.isBoolean,
2114 supercedes: ["zindex"]
2117 "PREVENT_CONTEXT_OVERLAP": {
2118 key: "preventcontextoverlap",
2120 validator: Lang.isBoolean,
2121 supercedes: ["constraintoviewport"]
2127 * The URL that will be placed in the iframe
2128 * @property YAHOO.widget.Overlay.IFRAME_SRC
2133 Overlay.IFRAME_SRC = "javascript:false;";
2136 * Number representing how much the iframe shim should be offset from each
2137 * side of an Overlay instance, in pixels.
2138 * @property YAHOO.widget.Overlay.IFRAME_SRC
2144 Overlay.IFRAME_OFFSET = 3;
2147 * Number representing the minimum distance an Overlay instance should be
2148 * positioned relative to the boundaries of the browser's viewport, in pixels.
2149 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2155 Overlay.VIEWPORT_OFFSET = 10;
2158 * Constant representing the top left corner of an element, used for
2159 * configuring the context element alignment
2160 * @property YAHOO.widget.Overlay.TOP_LEFT
2165 Overlay.TOP_LEFT = "tl";
2168 * Constant representing the top right corner of an element, used for
2169 * configuring the context element alignment
2170 * @property YAHOO.widget.Overlay.TOP_RIGHT
2175 Overlay.TOP_RIGHT = "tr";
2178 * Constant representing the top bottom left corner of an element, used for
2179 * configuring the context element alignment
2180 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2185 Overlay.BOTTOM_LEFT = "bl";
2188 * Constant representing the bottom right corner of an element, used for
2189 * configuring the context element alignment
2190 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2195 Overlay.BOTTOM_RIGHT = "br";
2197 Overlay.PREVENT_OVERLAP_X = {
2204 Overlay.PREVENT_OVERLAP_Y = {
2212 * Constant representing the default CSS class used for an Overlay
2213 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2218 Overlay.CSS_OVERLAY = "yui-overlay";
2221 * Constant representing the default hidden CSS class used for an Overlay. This class is
2222 * applied to the overlay's outer DIV whenever it's hidden.
2224 * @property YAHOO.widget.Overlay.CSS_HIDDEN
2229 Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2232 * Constant representing the default CSS class used for an Overlay iframe shim.
2234 * @property YAHOO.widget.Overlay.CSS_IFRAME
2239 Overlay.CSS_IFRAME = "yui-overlay-iframe";
2242 * Constant representing the names of the standard module elements
2243 * used in the overlay.
2244 * @property YAHOO.widget.Overlay.STD_MOD_RE
2249 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2252 * A singleton CustomEvent used for reacting to the DOM event for
2254 * @event YAHOO.widget.Overlay.windowScrollEvent
2256 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2259 * A singleton CustomEvent used for reacting to the DOM event for
2261 * @event YAHOO.widget.Overlay.windowResizeEvent
2263 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2266 * The DOM event handler used to fire the CustomEvent for window scroll
2267 * @method YAHOO.widget.Overlay.windowScrollHandler
2269 * @param {DOMEvent} e The DOM scroll event
2271 Overlay.windowScrollHandler = function (e) {
2272 var t = Event.getTarget(e);
2274 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2275 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2276 // - IE doesn't recognize scroll registered on the document.
2278 // Also, when document view is scrolled, IE doesn't provide a target,
2279 // rest of the browsers set target to window.document, apart from opera
2280 // which sets target to window.
2281 if (!t || t === window || t === window.document) {
2284 if (! window.scrollEnd) {
2285 window.scrollEnd = -1;
2288 clearTimeout(window.scrollEnd);
2290 window.scrollEnd = setTimeout(function () {
2291 Overlay.windowScrollEvent.fire();
2295 Overlay.windowScrollEvent.fire();
2301 * The DOM event handler used to fire the CustomEvent for window resize
2302 * @method YAHOO.widget.Overlay.windowResizeHandler
2304 * @param {DOMEvent} e The DOM resize event
2306 Overlay.windowResizeHandler = function (e) {
2309 if (! window.resizeEnd) {
2310 window.resizeEnd = -1;
2313 clearTimeout(window.resizeEnd);
2315 window.resizeEnd = setTimeout(function () {
2316 Overlay.windowResizeEvent.fire();
2319 Overlay.windowResizeEvent.fire();
2324 * A boolean that indicated whether the window resize and scroll events have
2325 * already been subscribed to.
2326 * @property YAHOO.widget.Overlay._initialized
2330 Overlay._initialized = null;
2332 if (Overlay._initialized === null) {
2333 Event.on(window, "scroll", Overlay.windowScrollHandler);
2334 Event.on(window, "resize", Overlay.windowResizeHandler);
2335 Overlay._initialized = true;
2339 * Internal map of special event types, which are provided
2340 * by the instance. It maps the event type to the custom event
2341 * instance. Contains entries for the "windowScroll", "windowResize" and
2342 * "textResize" static container events.
2344 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2349 Overlay._TRIGGER_MAP = {
2350 "windowScroll" : Overlay.windowScrollEvent,
2351 "windowResize" : Overlay.windowResizeEvent,
2352 "textResize" : Module.textResizeEvent
2355 YAHOO.extend(Overlay, Module, {
2359 * Array of default event types which will trigger
2360 * context alignment for the Overlay class.
2362 * <p>The array is empty by default for Overlay,
2363 * but maybe populated in future releases, so classes extending
2364 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2365 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2366 * value with their own array of values.
2370 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2373 * @property CONTEXT_TRIGGERS
2377 CONTEXT_TRIGGERS : [],
2380 * The Overlay initialization method, which is executed for Overlay and
2381 * all of its subclasses. This method is automatically called by the
2382 * constructor, and sets up all DOM references for pre-existing markup,
2383 * and creates required markup if it is not already present.
2385 * @param {String} el The element ID representing the Overlay <em>OR</em>
2386 * @param {HTMLElement} el The element representing the Overlay
2387 * @param {Object} userConfig The configuration object literal
2388 * containing the configuration that should be set for this Overlay.
2389 * See configuration documentation for more details.
2391 init: function (el, userConfig) {
2394 Note that we don't pass the user config in here yet because we
2395 only want it executed once, at the lowest subclass level
2398 Overlay.superclass.init.call(this, el/*, userConfig*/);
2400 this.beforeInitEvent.fire(Overlay);
2402 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2405 this.cfg.applyConfig(userConfig, true);
2408 if (this.platform == "mac" && UA.gecko) {
2410 if (! Config.alreadySubscribed(this.showEvent,
2411 this.showMacGeckoScrollbars, this)) {
2413 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2418 if (! Config.alreadySubscribed(this.hideEvent,
2419 this.hideMacGeckoScrollbars, this)) {
2421 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2427 this.initEvent.fire(Overlay);
2431 * Initializes the custom events for Overlay which are fired
2432 * automatically at appropriate times by the Overlay class.
2433 * @method initEvents
2435 initEvents: function () {
2437 Overlay.superclass.initEvents.call(this);
2439 var SIGNATURE = CustomEvent.LIST;
2442 * CustomEvent fired before the Overlay is moved.
2443 * @event beforeMoveEvent
2444 * @param {Number} x x coordinate
2445 * @param {Number} y y coordinate
2447 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2448 this.beforeMoveEvent.signature = SIGNATURE;
2451 * CustomEvent fired after the Overlay is moved.
2453 * @param {Number} x x coordinate
2454 * @param {Number} y y coordinate
2456 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2457 this.moveEvent.signature = SIGNATURE;
2462 * Initializes the class's configurable properties which can be changed
2463 * using the Overlay's Config object (cfg).
2464 * @method initDefaultConfig
2466 initDefaultConfig: function () {
2468 Overlay.superclass.initDefaultConfig.call(this);
2472 // Add overlay config properties //
2475 * The absolute x-coordinate position of the Overlay
2480 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2482 handler: this.configX,
2483 validator: DEFAULT_CONFIG.X.validator,
2484 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2485 supercedes: DEFAULT_CONFIG.X.supercedes
2490 * The absolute y-coordinate position of the Overlay
2495 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2497 handler: this.configY,
2498 validator: DEFAULT_CONFIG.Y.validator,
2499 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2500 supercedes: DEFAULT_CONFIG.Y.supercedes
2505 * An array with the absolute x and y positions of the Overlay
2510 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2511 handler: this.configXY,
2512 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2513 supercedes: DEFAULT_CONFIG.XY.supercedes
2518 * The array of context arguments for context-sensitive positioning.
2522 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2523 * the 5 array elements described in detail below:
2527 * <dt>contextElementOrId <String|HTMLElement></dt>
2528 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2529 * <dt>overlayCorner <String></dt>
2530 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2531 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2532 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2533 * <dt>contextCorner <String></dt>
2534 * <dd>The corner of the context element which is to be used for alignment. Supported string values are the same ones listed for the "overlayCorner" entry above.</dd>
2535 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2538 * By default, context alignment is a one time operation, aligning the Overlay to the context element when context configuration property is set, or when the <a href="#method_align">align</a>
2539 * method is invoked. However, you can use the optional "arrayOfTriggerEvents" entry to define the list of events which should force the overlay to re-align itself with the context element.
2540 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2543 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2544 * 3 static container event types are also currently supported : <code>"windowResize", "windowScroll", "textResize"</code> (defined in <a href="#property__TRIGGER_MAP">_TRIGGER_MAP</a> private property).
2547 * <dt>xyOffset <Number[]></dt>
2549 * A 2 element Array specifying the X and Y pixel amounts by which the Overlay should be offset from the aligned corner. e.g. [5,0] offsets the Overlay 5 pixels to the left, <em>after</em> aligning the given context corners.
2550 * NOTE: If using this property and no triggers need to be defined, the arrayOfTriggerEvents property should be set to null to maintain correct array positions for the arguments.
2555 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2556 * align the Overlay's top left corner to the bottom left corner of the
2557 * context element with id "img1".
2560 * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
2561 * align the Overlay's top left corner to the bottom left corner of the
2562 * context element with id "img1", and then offset it by 5 pixels on the Y axis (providing a 5 pixel gap between the bottom of the context element and top of the overlay).
2565 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2566 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2573 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2574 handler: this.configContext,
2575 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2576 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2580 * Determines whether or not the Overlay should be anchored
2581 * to the center of the viewport.
2583 * <p>This property can be set to:</p>
2588 * To enable fixed center positioning
2590 * When enabled, the overlay will
2591 * be positioned in the center of viewport when initially displayed, and
2592 * will remain in the center of the viewport whenever the window is
2593 * scrolled or resized.
2596 * If the overlay is too big for the viewport,
2597 * it's top left corner will be aligned with the top left corner of the viewport.
2602 * To disable fixed center positioning.
2603 * <p>In this case the overlay can still be
2604 * centered as a one-off operation, by invoking the <code>center()</code> method,
2605 * however it will not remain centered when the window is scrolled/resized.
2607 * <dt>"contained"<dt>
2608 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2609 * <p>However, unlike setting the property to <code>true</code>,
2610 * when the property is set to <code>"contained"</code>, if the overlay is
2611 * too big for the viewport, it will not get automatically centered when the
2612 * user scrolls or resizes the window (until the window is large enough to contain the
2613 * overlay). This is useful in cases where the Overlay has both header and footer
2614 * UI controls which the user may need to access.
2619 * @config fixedcenter
2620 * @type Boolean | String
2623 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2624 handler: this.configFixedCenter,
2625 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2626 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2627 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2631 * CSS width of the Overlay.
2636 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2637 handler: this.configWidth,
2638 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2639 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2643 * CSS height of the Overlay.
2648 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2649 handler: this.configHeight,
2650 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2651 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2655 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2656 * Supported values are "header", "body", "footer".
2658 * @config autofillheight
2662 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2663 handler: this.configAutoFillHeight,
2664 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2665 validator : this._validateAutoFill,
2666 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2670 * CSS z-index of the Overlay.
2675 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2676 handler: this.configzIndex,
2677 value: DEFAULT_CONFIG.ZINDEX.value
2681 * True if the Overlay should be prevented from being positioned
2682 * out of the viewport.
2683 * @config constraintoviewport
2687 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2689 handler: this.configConstrainToViewport,
2690 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2691 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2692 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2698 * @description Boolean indicating whether or not the Overlay should
2699 * have an IFRAME shim; used to prevent SELECT elements from
2700 * poking through an Overlay instance in IE6. When set to "true",
2701 * the iframe shim is created when the Overlay instance is intially
2704 * @default true for IE6 and below, false for all other browsers.
2706 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2708 handler: this.configIframe,
2709 value: DEFAULT_CONFIG.IFRAME.value,
2710 validator: DEFAULT_CONFIG.IFRAME.validator,
2711 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2716 * @config preventcontextoverlap
2717 * @description Boolean indicating whether or not the Overlay should overlap its
2718 * context element (defined using the "context" configuration property) when the
2719 * "constraintoviewport" configuration property is set to "true".
2723 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2724 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2725 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2726 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2731 * Moves the Overlay to the specified position. This function is
2732 * identical to calling this.cfg.setProperty("xy", [x,y]);
2734 * @param {Number} x The Overlay's new x position
2735 * @param {Number} y The Overlay's new y position
2737 moveTo: function (x, y) {
2738 this.cfg.setProperty("xy", [x, y]);
2742 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2743 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2744 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2745 * @method hideMacGeckoScrollbars
2747 hideMacGeckoScrollbars: function () {
2748 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2752 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2753 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2754 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2755 * @method showMacGeckoScrollbars
2757 showMacGeckoScrollbars: function () {
2758 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2762 * Internal implementation to set the visibility of the overlay in the DOM.
2764 * @method _setDomVisibility
2765 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2768 _setDomVisibility : function(show) {
2769 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2770 var hiddenClass = Overlay.CSS_HIDDEN;
2773 Dom.removeClass(this.element, hiddenClass);
2775 Dom.addClass(this.element, hiddenClass);
2779 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2781 * The default event handler fired when the "visible" property is
2782 * changed. This method is responsible for firing showEvent
2784 * @method configVisible
2785 * @param {String} type The CustomEvent type (usually the property name)
2786 * @param {Object[]} args The CustomEvent arguments. For configuration
2787 * handlers, args[0] will equal the newly applied value for the property.
2788 * @param {Object} obj The scope object. For configuration handlers,
2789 * this will usually equal the owner.
2791 configVisible: function (type, args, obj) {
2793 var visible = args[0],
2794 currentVis = Dom.getStyle(this.element, "visibility"),
2795 effects = this._cachedEffects || this._createEffects(this.cfg.getProperty("effect")),
2796 isMacGecko = (this.platform == "mac" && UA.gecko),
2797 alreadySubscribed = Config.alreadySubscribed,
2801 if (currentVis == "inherit") {
2802 e = this.element.parentNode;
2804 while (e.nodeType != 9 && e.nodeType != 11) {
2805 currentVis = Dom.getStyle(e, "visibility");
2807 if (currentVis != "inherit") {
2814 if (currentVis == "inherit") {
2815 currentVis = "visible";
2819 if (visible) { // Show
2822 this.showMacGeckoScrollbars();
2825 if (effects) { // Animate in
2826 if (visible) { // Animate in if not showing
2828 // Fading out is a bit of a hack, but didn't want to risk doing
2829 // something broader (e.g a generic this._animatingOut) for 2.9.0
2831 if (currentVis != "visible" || currentVis === "" || this._fadingOut) {
2832 if (this.beforeShowEvent.fire()) {
2834 nEffectInstances = effects.length;
2836 for (j = 0; j < nEffectInstances; j++) {
2838 if (j === 0 && !alreadySubscribed(ei.animateInCompleteEvent, this.showEvent.fire, this.showEvent)) {
2839 ei.animateInCompleteEvent.subscribe(this.showEvent.fire, this.showEvent, true);
2847 if (currentVis != "visible" || currentVis === "") {
2848 if (this.beforeShowEvent.fire()) {
2849 this._setDomVisibility(true);
2850 this.cfg.refireEvent("iframe");
2851 this.showEvent.fire();
2854 this._setDomVisibility(true);
2860 this.hideMacGeckoScrollbars();
2863 if (effects) { // Animate out if showing
2864 if (currentVis == "visible" || this._fadingIn) {
2865 if (this.beforeHideEvent.fire()) {
2866 nEffectInstances = effects.length;
2867 for (k = 0; k < nEffectInstances; k++) {
2870 if (k === 0 && !alreadySubscribed(h.animateOutCompleteEvent, this.hideEvent.fire, this.hideEvent)) {
2871 h.animateOutCompleteEvent.subscribe(this.hideEvent.fire, this.hideEvent, true);
2877 } else if (currentVis === "") {
2878 this._setDomVisibility(false);
2881 } else { // Simple hide
2883 if (currentVis == "visible" || currentVis === "") {
2884 if (this.beforeHideEvent.fire()) {
2885 this._setDomVisibility(false);
2886 this.hideEvent.fire();
2889 this._setDomVisibility(false);
2896 * Fixed center event handler used for centering on scroll/resize, but only if
2897 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2898 * the overlay fits within the viewport.
2900 * @method doCenterOnDOMEvent
2902 doCenterOnDOMEvent: function () {
2904 fc = cfg.getProperty("fixedcenter");
2906 if (cfg.getProperty("visible")) {
2907 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2914 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2915 * will fit entirely inside the viewport, in both dimensions - width and height.
2917 * @method fitsInViewport
2918 * @return boolean true if the Overlay will fit, false if not
2920 fitsInViewport : function() {
2921 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2922 element = this.element,
2923 elementWidth = element.offsetWidth,
2924 elementHeight = element.offsetHeight,
2925 viewportWidth = Dom.getViewportWidth(),
2926 viewportHeight = Dom.getViewportHeight();
2928 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2932 * The default event handler fired when the "fixedcenter" property
2934 * @method configFixedCenter
2935 * @param {String} type The CustomEvent type (usually the property name)
2936 * @param {Object[]} args The CustomEvent arguments. For configuration
2937 * handlers, args[0] will equal the newly applied value for the property.
2938 * @param {Object} obj The scope object. For configuration handlers,
2939 * this will usually equal the owner.
2941 configFixedCenter: function (type, args, obj) {
2944 alreadySubscribed = Config.alreadySubscribed,
2945 windowResizeEvent = Overlay.windowResizeEvent,
2946 windowScrollEvent = Overlay.windowScrollEvent;
2951 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2952 this.beforeShowEvent.subscribe(this.center);
2955 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2956 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2959 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2960 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2964 this.beforeShowEvent.unsubscribe(this.center);
2966 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2967 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2972 * The default event handler fired when the "height" property is changed.
2973 * @method configHeight
2974 * @param {String} type The CustomEvent type (usually the property name)
2975 * @param {Object[]} args The CustomEvent arguments. For configuration
2976 * handlers, args[0] will equal the newly applied value for the property.
2977 * @param {Object} obj The scope object. For configuration handlers,
2978 * this will usually equal the owner.
2980 configHeight: function (type, args, obj) {
2982 var height = args[0],
2985 Dom.setStyle(el, "height", height);
2986 this.cfg.refireEvent("iframe");
2990 * The default event handler fired when the "autofillheight" property is changed.
2991 * @method configAutoFillHeight
2993 * @param {String} type The CustomEvent type (usually the property name)
2994 * @param {Object[]} args The CustomEvent arguments. For configuration
2995 * handlers, args[0] will equal the newly applied value for the property.
2996 * @param {Object} obj The scope object. For configuration handlers,
2997 * this will usually equal the owner.
2999 configAutoFillHeight: function (type, args, obj) {
3000 var fillEl = args[0],
3002 autoFillHeight = "autofillheight",
3004 currEl = cfg.getProperty(autoFillHeight),
3005 autoFill = this._autoFillOnHeightChange;
3007 cfg.unsubscribeFromConfigEvent(height, autoFill);
3008 Module.textResizeEvent.unsubscribe(autoFill);
3009 this.changeContentEvent.unsubscribe(autoFill);
3011 if (currEl && fillEl !== currEl && this[currEl]) {
3012 Dom.setStyle(this[currEl], height, "");
3016 fillEl = Lang.trim(fillEl.toLowerCase());
3018 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
3019 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
3020 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
3022 cfg.setProperty(autoFillHeight, fillEl, true);
3027 * The default event handler fired when the "width" property is changed.
3028 * @method configWidth
3029 * @param {String} type The CustomEvent type (usually the property name)
3030 * @param {Object[]} args The CustomEvent arguments. For configuration
3031 * handlers, args[0] will equal the newly applied value for the property.
3032 * @param {Object} obj The scope object. For configuration handlers,
3033 * this will usually equal the owner.
3035 configWidth: function (type, args, obj) {
3037 var width = args[0],
3040 Dom.setStyle(el, "width", width);
3041 this.cfg.refireEvent("iframe");
3045 * The default event handler fired when the "zIndex" property is changed.
3046 * @method configzIndex
3047 * @param {String} type The CustomEvent type (usually the property name)
3048 * @param {Object[]} args The CustomEvent arguments. For configuration
3049 * handlers, args[0] will equal the newly applied value for the property.
3050 * @param {Object} obj The scope object. For configuration handlers,
3051 * this will usually equal the owner.
3053 configzIndex: function (type, args, obj) {
3055 var zIndex = args[0],
3059 zIndex = Dom.getStyle(el, "zIndex");
3060 if (! zIndex || isNaN(zIndex)) {
3065 if (this.iframe || this.cfg.getProperty("iframe") === true) {
3071 Dom.setStyle(el, "zIndex", zIndex);
3072 this.cfg.setProperty("zIndex", zIndex, true);
3080 * The default event handler fired when the "xy" property is changed.
3082 * @param {String} type The CustomEvent type (usually the property name)
3083 * @param {Object[]} args The CustomEvent arguments. For configuration
3084 * handlers, args[0] will equal the newly applied value for the property.
3085 * @param {Object} obj The scope object. For configuration handlers,
3086 * this will usually equal the owner.
3088 configXY: function (type, args, obj) {
3094 this.cfg.setProperty("x", x);
3095 this.cfg.setProperty("y", y);
3097 this.beforeMoveEvent.fire([x, y]);
3099 x = this.cfg.getProperty("x");
3100 y = this.cfg.getProperty("y");
3103 this.cfg.refireEvent("iframe");
3104 this.moveEvent.fire([x, y]);
3108 * The default event handler fired when the "x" property is changed.
3110 * @param {String} type The CustomEvent type (usually the property name)
3111 * @param {Object[]} args The CustomEvent arguments. For configuration
3112 * handlers, args[0] will equal the newly applied value for the property.
3113 * @param {Object} obj The scope object. For configuration handlers,
3114 * this will usually equal the owner.
3116 configX: function (type, args, obj) {
3119 y = this.cfg.getProperty("y");
3121 this.cfg.setProperty("x", x, true);
3122 this.cfg.setProperty("y", y, true);
3124 this.beforeMoveEvent.fire([x, y]);
3126 x = this.cfg.getProperty("x");
3127 y = this.cfg.getProperty("y");
3129 Dom.setX(this.element, x, true);
3131 this.cfg.setProperty("xy", [x, y], true);
3133 this.cfg.refireEvent("iframe");
3134 this.moveEvent.fire([x, y]);
3138 * The default event handler fired when the "y" property is changed.
3140 * @param {String} type The CustomEvent type (usually the property name)
3141 * @param {Object[]} args The CustomEvent arguments. For configuration
3142 * handlers, args[0] will equal the newly applied value for the property.
3143 * @param {Object} obj The scope object. For configuration handlers,
3144 * this will usually equal the owner.
3146 configY: function (type, args, obj) {
3148 var x = this.cfg.getProperty("x"),
3151 this.cfg.setProperty("x", x, true);
3152 this.cfg.setProperty("y", y, true);
3154 this.beforeMoveEvent.fire([x, y]);
3156 x = this.cfg.getProperty("x");
3157 y = this.cfg.getProperty("y");
3159 Dom.setY(this.element, y, true);
3161 this.cfg.setProperty("xy", [x, y], true);
3163 this.cfg.refireEvent("iframe");
3164 this.moveEvent.fire([x, y]);
3168 * Shows the iframe shim, if it has been enabled.
3169 * @method showIframe
3171 showIframe: function () {
3173 var oIFrame = this.iframe,
3177 oParentNode = this.element.parentNode;
3179 if (oParentNode != oIFrame.parentNode) {
3180 this._addToParent(oParentNode, oIFrame);
3182 oIFrame.style.display = "block";
3187 * Hides the iframe shim, if it has been enabled.
3188 * @method hideIframe
3190 hideIframe: function () {
3192 this.iframe.style.display = "none";
3197 * Syncronizes the size and position of iframe shim to that of its
3198 * corresponding Overlay instance.
3199 * @method syncIframe
3201 syncIframe: function () {
3203 var oIFrame = this.iframe,
3204 oElement = this.element,
3205 nOffset = Overlay.IFRAME_OFFSET,
3206 nDimensionOffset = (nOffset * 2),
3211 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3212 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3214 // Position <iframe>
3215 aXY = this.cfg.getProperty("xy");
3217 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3218 this.syncPosition();
3219 aXY = this.cfg.getProperty("xy");
3221 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3226 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3227 * the Overlay element. The zindex of the iframe is set to be one less
3228 * than the Overlay element's zindex.
3230 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3231 * to ensure that the iframe shim has a non-negative zindex.
3232 * If you require the iframe zindex to be 0 or higher, the zindex of
3233 * the Overlay element should be set to a value greater than 0, before
3234 * this method is called.
3236 * @method stackIframe
3238 stackIframe: function () {
3240 var overlayZ = Dom.getStyle(this.element, "zIndex");
3241 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3242 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3248 * The default event handler fired when the "iframe" property is changed.
3249 * @method configIframe
3250 * @param {String} type The CustomEvent type (usually the property name)
3251 * @param {Object[]} args The CustomEvent arguments. For configuration
3252 * handlers, args[0] will equal the newly applied value for the property.
3253 * @param {Object} obj The scope object. For configuration handlers,
3254 * this will usually equal the owner.
3256 configIframe: function (type, args, obj) {
3258 var bIFrame = args[0];
3260 function createIFrame() {
3262 var oIFrame = this.iframe,
3263 oElement = this.element,
3267 if (!m_oIFrameTemplate) {
3268 m_oIFrameTemplate = document.createElement("iframe");
3270 if (this.isSecure) {
3271 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3275 Set the opacity of the <iframe> to 0 so that it
3276 doesn't modify the opacity of any transparent
3277 elements that may be on top of it (like a shadow).
3280 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3282 Need to set the "frameBorder" property to 0
3283 supress the default <iframe> border in IE.
3284 Setting the CSS "border" property alone
3287 m_oIFrameTemplate.frameBorder = 0;
3290 m_oIFrameTemplate.style.opacity = "0";
3293 m_oIFrameTemplate.style.position = "absolute";
3294 m_oIFrameTemplate.style.border = "none";
3295 m_oIFrameTemplate.style.margin = "0";
3296 m_oIFrameTemplate.style.padding = "0";
3297 m_oIFrameTemplate.style.display = "none";
3298 m_oIFrameTemplate.tabIndex = -1;
3299 m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3302 oIFrame = m_oIFrameTemplate.cloneNode(false);
3303 oIFrame.id = this.id + "_f";
3304 oParent = oElement.parentNode;
3306 var parentNode = oParent || document.body;
3308 this._addToParent(parentNode, oIFrame);
3309 this.iframe = oIFrame;
3313 Show the <iframe> before positioning it since the "setXY"
3314 method of DOM requires the element be in the document
3320 Syncronize the size and position of the <iframe> to that
3326 // Add event listeners to update the <iframe> when necessary
3327 if (!this._hasIframeEventListeners) {
3328 this.showEvent.subscribe(this.showIframe);
3329 this.hideEvent.subscribe(this.hideIframe);
3330 this.changeContentEvent.subscribe(this.syncIframe);
3332 this._hasIframeEventListeners = true;
3336 function onBeforeShow() {
3337 createIFrame.call(this);
3338 this.beforeShowEvent.unsubscribe(onBeforeShow);
3339 this._iframeDeferred = false;
3342 if (bIFrame) { // <iframe> shim is enabled
3344 if (this.cfg.getProperty("visible")) {
3345 createIFrame.call(this);
3347 if (!this._iframeDeferred) {
3348 this.beforeShowEvent.subscribe(onBeforeShow);
3349 this._iframeDeferred = true;
3353 } else { // <iframe> shim is disabled
3356 if (this._hasIframeEventListeners) {
3357 this.showEvent.unsubscribe(this.showIframe);
3358 this.hideEvent.unsubscribe(this.hideIframe);
3359 this.changeContentEvent.unsubscribe(this.syncIframe);
3361 this._hasIframeEventListeners = false;
3367 * Set's the container's XY value from DOM if not already set.
3369 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3370 * not already set. The method also refire's the XY config property event, so any
3371 * beforeMove, Move event listeners are invoked.
3373 * @method _primeXYFromDOM
3376 _primeXYFromDOM : function() {
3377 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3378 // Set CFG XY based on DOM XY
3379 this.syncPosition();
3380 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3381 this.cfg.refireEvent("xy");
3382 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3387 * The default event handler fired when the "constraintoviewport"
3388 * property is changed.
3389 * @method configConstrainToViewport
3390 * @param {String} type The CustomEvent type (usually the property name)
3391 * @param {Object[]} args The CustomEvent arguments. For configuration
3392 * handlers, args[0] will equal the newly applied value for
3394 * @param {Object} obj The scope object. For configuration handlers,
3395 * this will usually equal the owner.
3397 configConstrainToViewport: function (type, args, obj) {
3401 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3402 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3404 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3405 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3408 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3409 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3414 * The default event handler fired when the "context" property
3417 * @method configContext
3418 * @param {String} type The CustomEvent type (usually the property name)
3419 * @param {Object[]} args The CustomEvent arguments. For configuration
3420 * handlers, args[0] will equal the newly applied value for the property.
3421 * @param {Object} obj The scope object. For configuration handlers,
3422 * this will usually equal the owner.
3424 configContext: function (type, args, obj) {
3426 var contextArgs = args[0],
3428 elementMagnetCorner,
3429 contextMagnetCorner,
3432 defTriggers = this.CONTEXT_TRIGGERS;
3436 contextEl = contextArgs[0];
3437 elementMagnetCorner = contextArgs[1];
3438 contextMagnetCorner = contextArgs[2];
3439 triggers = contextArgs[3];
3440 offset = contextArgs[4];
3442 if (defTriggers && defTriggers.length > 0) {
3443 triggers = (triggers || []).concat(defTriggers);
3447 if (typeof contextEl == "string") {
3448 this.cfg.setProperty("context", [
3449 document.getElementById(contextEl),
3450 elementMagnetCorner,
3451 contextMagnetCorner,
3457 if (elementMagnetCorner && contextMagnetCorner) {
3458 this.align(elementMagnetCorner, contextMagnetCorner, offset);
3461 if (this._contextTriggers) {
3462 // Unsubscribe Old Set
3463 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3467 // Subscribe New Set
3468 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3469 this._contextTriggers = triggers;
3476 * Custom Event handler for context alignment triggers. Invokes the align method
3478 * @method _alignOnTrigger
3481 * @param {String} type The event type (not used by the default implementation)
3482 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3484 _alignOnTrigger: function(type, args) {
3489 * Helper method to locate the custom event instance for the event name string
3490 * passed in. As a convenience measure, any custom events passed in are returned.
3492 * @method _findTriggerCE
3495 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3496 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3498 _findTriggerCE : function(t) {
3500 if (t instanceof CustomEvent) {
3502 } else if (Overlay._TRIGGER_MAP[t]) {
3503 tce = Overlay._TRIGGER_MAP[t];
3509 * Utility method that subscribes or unsubscribes the given
3510 * function from the list of trigger events provided.
3512 * @method _processTriggers
3515 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3516 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3517 * subscribed/unsubscribed respectively.
3519 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3520 * we are subscribing or unsubscribing trigger listeners
3522 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3523 * Context is always set to the overlay instance, and no additional object argument
3524 * get passed to the subscribed function.
3526 _processTriggers : function(triggers, mode, fn) {
3529 for (var i = 0, l = triggers.length; i < l; ++i) {
3531 tce = this._findTriggerCE(t);
3533 tce[mode](fn, this, true);
3540 // END BUILT-IN PROPERTY EVENT HANDLERS //
3542 * Aligns the Overlay to its context element using the specified corner
3543 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3546 * @param {String} elementAlign The String representing the corner of
3547 * the Overlay that should be aligned to the context element
3548 * @param {String} contextAlign The corner of the context element
3549 * that the elementAlign corner should stick to.
3550 * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3551 * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
3552 * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3554 align: function (elementAlign, contextAlign, xyOffset) {
3556 var contextArgs = this.cfg.getProperty("context"),
3562 function doAlign(v, h) {
3564 var alignX = null, alignY = null;
3566 switch (elementAlign) {
3568 case Overlay.TOP_LEFT:
3573 case Overlay.TOP_RIGHT:
3574 alignX = h - element.offsetWidth;
3578 case Overlay.BOTTOM_LEFT:
3580 alignY = v - element.offsetHeight;
3583 case Overlay.BOTTOM_RIGHT:
3584 alignX = h - element.offsetWidth;
3585 alignY = v - element.offsetHeight;
3589 if (alignX !== null && alignY !== null) {
3591 alignX += xyOffset[0];
3592 alignY += xyOffset[1];
3594 me.moveTo(alignX, alignY);
3599 context = contextArgs[0];
3600 element = this.element;
3603 if (! elementAlign) {
3604 elementAlign = contextArgs[1];
3607 if (! contextAlign) {
3608 contextAlign = contextArgs[2];
3611 if (!xyOffset && contextArgs[4]) {
3612 xyOffset = contextArgs[4];
3615 if (element && context) {
3616 contextRegion = Dom.getRegion(context);
3618 switch (contextAlign) {
3620 case Overlay.TOP_LEFT:
3621 doAlign(contextRegion.top, contextRegion.left);
3624 case Overlay.TOP_RIGHT:
3625 doAlign(contextRegion.top, contextRegion.right);
3628 case Overlay.BOTTOM_LEFT:
3629 doAlign(contextRegion.bottom, contextRegion.left);
3632 case Overlay.BOTTOM_RIGHT:
3633 doAlign(contextRegion.bottom, contextRegion.right);
3641 * The default event handler executed when the moveEvent is fired, if the
3642 * "constraintoviewport" is set to true.
3643 * @method enforceConstraints
3644 * @param {String} type The CustomEvent type (usually the property name)
3645 * @param {Object[]} args The CustomEvent arguments. For configuration
3646 * handlers, args[0] will equal the newly applied value for the property.
3647 * @param {Object} obj The scope object. For configuration handlers,
3648 * this will usually equal the owner.
3650 enforceConstraints: function (type, args, obj) {
3653 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3654 this.cfg.setProperty("x", cXY[0], true);
3655 this.cfg.setProperty("y", cXY[1], true);
3656 this.cfg.setProperty("xy", cXY, true);
3660 * Shared implementation method for getConstrainedX and getConstrainedY.
3663 * Given a coordinate value, returns the calculated coordinate required to
3664 * position the Overlay if it is to be constrained to the viewport, based on the
3665 * current element size, viewport dimensions, scroll values and preventoverlap
3669 * @method _getConstrainedPos
3671 * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3672 * @param {Number} The coordinate value which needs to be constrained
3673 * @return {Number} The constrained coordinate value
3675 _getConstrainedPos: function(pos, val) {
3677 var overlayEl = this.element,
3679 buffer = Overlay.VIEWPORT_OFFSET,
3683 overlaySize = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3684 viewportSize = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3685 docScroll = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3686 overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3688 context = this.cfg.getProperty("context"),
3690 bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3691 bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3693 minConstraint = docScroll + buffer,
3694 maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3696 constrainedVal = val;
3698 if (val < minConstraint || val > maxConstraint) {
3699 if (bPreventContextOverlap) {
3700 constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3702 if (bOverlayFitsInViewport) {
3703 if (val < minConstraint) {
3704 constrainedVal = minConstraint;
3705 } else if (val > maxConstraint) {
3706 constrainedVal = maxConstraint;
3709 constrainedVal = minConstraint;
3714 return constrainedVal;
3718 * Helper method, used to position the Overlap to prevent overlap with the
3719 * context element (used when preventcontextoverlap is enabled)
3721 * @method _preventOverlap
3723 * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3724 * @param {HTMLElement} contextEl The context element
3725 * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3726 * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3727 * @param {Object} docScroll The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3729 * @return {Number} The new coordinate value which was set to prevent overlap
3731 _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3733 var x = (pos == "x"),
3735 buffer = Overlay.VIEWPORT_OFFSET,
3739 contextElPos = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3740 contextElSize = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3742 minRegionSize = contextElPos - buffer,
3743 maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3747 flip = function () {
3750 if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3751 flippedVal = (contextElPos - overlaySize);
3753 flippedVal = (contextElPos + contextElSize);
3756 overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3761 setPosition = function () {
3763 var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3766 if (overlaySize > displayRegionSize) {
3769 All possible positions and values have been
3770 tried, but none were successful, so fall back
3771 to the original size and position.
3777 position = setPosition();
3786 return this.cfg.getProperty(pos);
3790 * Given x coordinate value, returns the calculated x coordinate required to
3791 * position the Overlay if it is to be constrained to the viewport, based on the
3792 * current element size, viewport dimensions and scroll values.
3794 * @param {Number} x The X coordinate value to be constrained
3795 * @return {Number} The constrained x coordinate
3797 getConstrainedX: function (x) {
3798 return this._getConstrainedPos("x", x);
3802 * Given y coordinate value, returns the calculated y coordinate required to
3803 * position the Overlay if it is to be constrained to the viewport, based on the
3804 * current element size, viewport dimensions and scroll values.
3806 * @param {Number} y The Y coordinate value to be constrained
3807 * @return {Number} The constrained y coordinate
3809 getConstrainedY : function (y) {
3810 return this._getConstrainedPos("y", y);
3814 * Given x, y coordinate values, returns the calculated coordinates required to
3815 * position the Overlay if it is to be constrained to the viewport, based on the
3816 * current element size, viewport dimensions and scroll values.
3818 * @param {Number} x The X coordinate value to be constrained
3819 * @param {Number} y The Y coordinate value to be constrained
3820 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3822 getConstrainedXY: function(x, y) {
3823 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3827 * Centers the container in the viewport.
3830 center: function () {
3832 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3833 elementWidth = this.element.offsetWidth,
3834 elementHeight = this.element.offsetHeight,
3835 viewPortWidth = Dom.getViewportWidth(),
3836 viewPortHeight = Dom.getViewportHeight(),
3840 if (elementWidth < viewPortWidth) {
3841 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3843 x = nViewportOffset + Dom.getDocumentScrollLeft();
3846 if (elementHeight < viewPortHeight) {
3847 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3849 y = nViewportOffset + Dom.getDocumentScrollTop();
3852 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3853 this.cfg.refireEvent("iframe");
3856 this.forceContainerRedraw();
3861 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3862 * Panel's position in the DOM. This is primarily used to update
3863 * position information during drag & drop.
3864 * @method syncPosition
3866 syncPosition: function () {
3868 var pos = Dom.getXY(this.element);
3870 this.cfg.setProperty("x", pos[0], true);
3871 this.cfg.setProperty("y", pos[1], true);
3872 this.cfg.setProperty("xy", pos, true);
3877 * Event handler fired when the resize monitor element is resized.
3878 * @method onDomResize
3879 * @param {DOMEvent} e The resize DOM event
3880 * @param {Object} obj The scope object
3882 onDomResize: function (e, obj) {
3886 Overlay.superclass.onDomResize.call(this, e, obj);
3888 setTimeout(function () {
3890 me.cfg.refireEvent("iframe");
3891 me.cfg.refireEvent("context");
3896 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3898 * @method _getComputedHeight
3900 * @param {HTMLElement} el The element for which the content height needs to be determined
3901 * @return {Number} The content box height of the given element, or null if it could not be determined.
3903 _getComputedHeight : (function() {
3905 if (document.defaultView && document.defaultView.getComputedStyle) {
3906 return function(el) {
3908 if (el.ownerDocument && el.ownerDocument.defaultView) {
3909 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3911 height = parseInt(computed.height, 10);
3914 return (Lang.isNumber(height)) ? height : null;
3917 return function(el) {
3919 if (el.style.pixelHeight) {
3920 height = el.style.pixelHeight;
3922 return (Lang.isNumber(height)) ? height : null;
3928 * autofillheight validator. Verifies that the autofill value is either null
3929 * or one of the strings : "body", "header" or "footer".
3931 * @method _validateAutoFillHeight
3933 * @param {String} val
3934 * @return true, if valid, false otherwise
3936 _validateAutoFillHeight : function(val) {
3937 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3941 * The default custom event handler executed when the overlay's height is changed,
3942 * if the autofillheight property has been set.
3944 * @method _autoFillOnHeightChange
3946 * @param {String} type The event type
3947 * @param {Array} args The array of arguments passed to event subscribers
3948 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3949 * out the containers height
3951 _autoFillOnHeightChange : function(type, args, el) {
3952 var height = this.cfg.getProperty("height");
3953 if ((height && height !== "auto") || (height === 0)) {
3954 this.fillHeight(el);
3959 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3960 * otherwise returns the offsetHeight
3961 * @method _getPreciseHeight
3963 * @param {HTMLElement} el
3964 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3966 _getPreciseHeight : function(el) {
3967 var height = el.offsetHeight;
3969 if (el.getBoundingClientRect) {
3970 var rect = el.getBoundingClientRect();
3971 height = rect.bottom - rect.top;
3979 * Sets the height on the provided header, body or footer element to
3980 * fill out the height of the container. It determines the height of the
3981 * containers content box, based on it's configured height value, and
3982 * sets the height of the autofillheight element to fill out any
3983 * space remaining after the other standard module element heights
3984 * have been accounted for.
3986 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
3987 * height has not been set on the container, since for an "auto" height container,
3988 * the heights of the header/body/footer will drive the height of the container.</p>
3990 * @method fillHeight
3991 * @param {HTMLElement} el The element which should be resized to fill out the height
3992 * of the container element.
3994 fillHeight : function(el) {
3996 var container = this.innerElement || this.element,
3997 containerEls = [this.header, this.body, this.footer],
4004 for (var i = 0, l = containerEls.length; i < l; i++) {
4005 containerEl = containerEls[i];
4007 if (el !== containerEl) {
4008 filled += this._getPreciseHeight(containerEl);
4017 if (UA.ie || UA.opera) {
4018 // Need to set height to 0, to allow height to be reduced
4019 Dom.setStyle(el, 'height', 0 + 'px');
4022 total = this._getComputedHeight(container);
4024 // Fallback, if we can't get computed value for content height
4025 if (total === null) {
4026 Dom.addClass(container, "yui-override-padding");
4027 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4028 Dom.removeClass(container, "yui-override-padding");
4031 remaining = Math.max(total - filled, 0);
4033 Dom.setStyle(el, "height", remaining + "px");
4035 // Re-adjust height if required, to account for el padding and border
4036 if (el.offsetHeight != remaining) {
4037 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4039 Dom.setStyle(el, "height", remaining + "px");
4045 * Places the Overlay on top of all other instances of
4046 * YAHOO.widget.Overlay.
4047 * @method bringToTop
4049 bringToTop: function () {
4052 oElement = this.element;
4054 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4056 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4057 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4059 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4060 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4062 if (nZIndex1 > nZIndex2) {
4064 } else if (nZIndex1 < nZIndex2) {
4071 function isOverlayElement(p_oElement) {
4073 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4074 Panel = YAHOO.widget.Panel;
4076 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4077 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4078 aOverlays[aOverlays.length] = p_oElement.parentNode;
4080 aOverlays[aOverlays.length] = p_oElement;
4085 Dom.getElementsBy(isOverlayElement, "div", document.body);
4087 aOverlays.sort(compareZIndexDesc);
4089 var oTopOverlay = aOverlays[0],
4093 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4095 if (!isNaN(nTopZIndex)) {
4096 var bRequiresBump = false;
4098 if (oTopOverlay != oElement) {
4099 bRequiresBump = true;
4100 } else if (aOverlays.length > 1) {
4101 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4102 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4103 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4104 bRequiresBump = true;
4107 if (bRequiresBump) {
4108 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4115 * Removes the Overlay element from the DOM and sets all child
4118 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
4119 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
4121 destroy: function (shallowPurge) {
4124 this.iframe.parentNode.removeChild(this.iframe);
4129 Overlay.windowResizeEvent.unsubscribe(
4130 this.doCenterOnDOMEvent, this);
4132 Overlay.windowScrollEvent.unsubscribe(
4133 this.doCenterOnDOMEvent, this);
4135 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4137 if (this._contextTriggers) {
4138 // Unsubscribe context triggers - to cover context triggers which listen for global
4139 // events such as windowResize and windowScroll. Easier just to unsubscribe all
4140 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4143 Overlay.superclass.destroy.call(this, shallowPurge);
4147 * Can be used to force the container to repaint/redraw it's contents.
4149 * By default applies and then removes a 1px bottom margin through the
4150 * application/removal of a "yui-force-redraw" class.
4153 * It is currently used by Overlay to force a repaint for webkit
4154 * browsers, when centering.
4156 * @method forceContainerRedraw
4158 forceContainerRedraw : function() {
4160 Dom.addClass(c.element, "yui-force-redraw");
4161 setTimeout(function() {
4162 Dom.removeClass(c.element, "yui-force-redraw");
4167 * Returns a String representation of the object.
4169 * @return {String} The string representation of the Overlay.
4171 toString: function () {
4172 return "Overlay " + this.id;
4180 * OverlayManager is used for maintaining the focus status of
4181 * multiple Overlays.
4182 * @namespace YAHOO.widget
4183 * @namespace YAHOO.widget
4184 * @class OverlayManager
4186 * @param {Array} overlays Optional. A collection of Overlays to register
4188 * @param {Object} userConfig The object literal representing the user
4189 * configuration of the OverlayManager
4191 YAHOO.widget.OverlayManager = function (userConfig) {
4192 this.init(userConfig);
4195 var Overlay = YAHOO.widget.Overlay,
4196 Event = YAHOO.util.Event,
4197 Dom = YAHOO.util.Dom,
4198 Config = YAHOO.util.Config,
4199 CustomEvent = YAHOO.util.CustomEvent,
4200 OverlayManager = YAHOO.widget.OverlayManager;
4203 * The CSS class representing a focused Overlay
4204 * @property OverlayManager.CSS_FOCUSED
4209 OverlayManager.CSS_FOCUSED = "focused";
4211 OverlayManager.prototype = {
4214 * The class's constructor function
4215 * @property contructor
4218 constructor: OverlayManager,
4221 * The array of Overlays that are currently registered
4222 * @property overlays
4223 * @type YAHOO.widget.Overlay[]
4228 * Initializes the default configuration of the OverlayManager
4229 * @method initDefaultConfig
4231 initDefaultConfig: function () {
4233 * The collection of registered Overlays in use by
4234 * the OverlayManager
4236 * @type YAHOO.widget.Overlay[]
4239 this.cfg.addProperty("overlays", { suppressEvent: true } );
4242 * The default DOM event that should be used to focus an Overlay
4243 * @config focusevent
4245 * @default "mousedown"
4247 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4251 * Initializes the OverlayManager
4253 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4254 * register with the manager.
4255 * @param {Object} userConfig The object literal representing the user
4256 * configuration of the OverlayManager
4258 init: function (userConfig) {
4261 * The OverlayManager's Config object used for monitoring
4262 * configuration properties.
4266 this.cfg = new Config(this);
4268 this.initDefaultConfig();
4271 this.cfg.applyConfig(userConfig, true);
4273 this.cfg.fireQueue();
4276 * The currently activated Overlay
4277 * @property activeOverlay
4279 * @type YAHOO.widget.Overlay
4281 var activeOverlay = null;
4284 * Returns the currently focused Overlay
4286 * @return {Overlay} The currently focused Overlay
4288 this.getActive = function () {
4289 return activeOverlay;
4293 * Focuses the specified Overlay
4295 * @param {Overlay} overlay The Overlay to focus
4296 * @param {String} overlay The id of the Overlay to focus
4298 this.focus = function (overlay) {
4299 var o = this.find(overlay);
4306 * Removes the specified Overlay from the manager
4308 * @param {Overlay} overlay The Overlay to remove
4309 * @param {String} overlay The id of the Overlay to remove
4311 this.remove = function (overlay) {
4313 var o = this.find(overlay),
4317 if (activeOverlay == o) {
4318 activeOverlay = null;
4321 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4324 // Set it's zindex so that it's sorted to the end.
4325 originalZ = Dom.getStyle(o.element, "zIndex");
4326 o.cfg.setProperty("zIndex", -1000, true);
4329 this.overlays.sort(this.compareZIndexDesc);
4330 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4332 o.hideEvent.unsubscribe(o.blur);
4333 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4334 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4335 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4338 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4339 o.cfg.setProperty("zIndex", originalZ, true);
4340 o.cfg.setProperty("manager", null);
4343 /* _managed Flag for custom or existing. Don't want to remove existing */
4344 if (o.focusEvent._managed) { o.focusEvent = null; }
4345 if (o.blurEvent._managed) { o.blurEvent = null; }
4347 if (o.focus._managed) { o.focus = null; }
4348 if (o.blur._managed) { o.blur = null; }
4353 * Removes focus from all registered Overlays in the manager
4356 this.blurAll = function () {
4358 var nOverlays = this.overlays.length,
4361 if (nOverlays > 0) {
4364 this.overlays[i].blur();
4371 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4374 * @method _manageBlur
4375 * @param {Overlay} overlay The overlay instance which got blurred.
4378 this._manageBlur = function (overlay) {
4379 var changed = false;
4380 if (activeOverlay == overlay) {
4381 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4382 activeOverlay = null;
4389 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4392 * @method _manageFocus
4393 * @param {Overlay} overlay The overlay instance which got focus.
4396 this._manageFocus = function(overlay) {
4397 var changed = false;
4398 if (activeOverlay != overlay) {
4399 if (activeOverlay) {
4400 activeOverlay.blur();
4402 activeOverlay = overlay;
4403 this.bringToTop(activeOverlay);
4404 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4410 var overlays = this.cfg.getProperty("overlays");
4412 if (! this.overlays) {
4417 this.register(overlays);
4418 this.overlays.sort(this.compareZIndexDesc);
4423 * @method _onOverlayElementFocus
4424 * @description Event handler for the DOM event that is used to focus
4425 * the Overlay instance as specified by the "focusevent"
4426 * configuration property.
4428 * @param {Event} p_oEvent Object representing the DOM event
4429 * object passed back by the event utility (Event).
4431 _onOverlayElementFocus: function (p_oEvent) {
4433 var oTarget = Event.getTarget(p_oEvent),
4434 oClose = this.close;
4436 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4444 * @method _onOverlayDestroy
4445 * @description "destroy" event handler for the Overlay.
4447 * @param {String} p_sType String representing the name of the event
4449 * @param {Array} p_aArgs Array of arguments sent when the event
4451 * @param {Overlay} p_oOverlay Object representing the overlay that
4454 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4455 this.remove(p_oOverlay);
4459 * @method _onOverlayFocusHandler
4461 * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4464 * @param {String} p_sType String representing the name of the event
4466 * @param {Array} p_aArgs Array of arguments sent when the event
4468 * @param {Overlay} p_oOverlay Object representing the overlay that
4471 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4472 this._manageFocus(p_oOverlay);
4476 * @method _onOverlayBlurHandler
4477 * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4480 * @param {String} p_sType String representing the name of the event
4482 * @param {Array} p_aArgs Array of arguments sent when the event
4484 * @param {Overlay} p_oOverlay Object representing the overlay that
4487 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4488 this._manageBlur(p_oOverlay);
4492 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4493 * monitor focus state.
4495 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4496 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4497 * on the instance, the _bindFocus method will add them, and the focus method will
4498 * update the OverlayManager's state directly.
4500 * @method _bindFocus
4501 * @param {Overlay} overlay The overlay for which focus needs to be managed
4504 _bindFocus : function(overlay) {
4507 if (!overlay.focusEvent) {
4508 overlay.focusEvent = overlay.createEvent("focus");
4509 overlay.focusEvent.signature = CustomEvent.LIST;
4510 overlay.focusEvent._managed = true;
4512 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4515 if (!overlay.focus) {
4516 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4517 overlay.focus = function () {
4518 if (mgr._manageFocus(this)) {
4520 if (this.cfg.getProperty("visible") && this.focusFirst) {
4523 this.focusEvent.fire();
4526 overlay.focus._managed = true;
4531 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4532 * monitor blur state.
4534 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4535 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4536 * on the instance, the _bindBlur method will add them, and the blur method
4537 * update the OverlayManager's state directly.
4540 * @param {Overlay} overlay The overlay for which blur needs to be managed
4543 _bindBlur : function(overlay) {
4546 if (!overlay.blurEvent) {
4547 overlay.blurEvent = overlay.createEvent("blur");
4548 overlay.blurEvent.signature = CustomEvent.LIST;
4549 overlay.focusEvent._managed = true;
4551 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4554 if (!overlay.blur) {
4555 overlay.blur = function () {
4556 if (mgr._manageBlur(this)) {
4557 this.blurEvent.fire();
4560 overlay.blur._managed = true;
4563 overlay.hideEvent.subscribe(overlay.blur);
4567 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4568 * to be removed for the OverlayManager when destroyed.
4570 * @method _bindDestroy
4571 * @param {Overlay} overlay The overlay instance being managed
4574 _bindDestroy : function(overlay) {
4576 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4580 * Ensures the zIndex configuration property on the managed overlay based instance
4581 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4583 * @method _syncZIndex
4584 * @param {Overlay} overlay The overlay instance being managed
4587 _syncZIndex : function(overlay) {
4588 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4589 if (!isNaN(zIndex)) {
4590 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4592 overlay.cfg.setProperty("zIndex", 0);
4597 * Registers an Overlay or an array of Overlays with the manager. Upon
4598 * registration, the Overlay receives functions for focus and blur,
4599 * along with CustomEvents for each.
4602 * @param {Overlay} overlay An Overlay to register with the manager.
4603 * @param {Overlay[]} overlay An array of Overlays to register with
4605 * @return {boolean} true if any Overlays are registered.
4607 register: function (overlay) {
4609 var registered = false,
4613 if (overlay instanceof Overlay) {
4615 overlay.cfg.addProperty("manager", { value: this } );
4617 this._bindFocus(overlay);
4618 this._bindBlur(overlay);
4619 this._bindDestroy(overlay);
4620 this._syncZIndex(overlay);
4622 this.overlays.push(overlay);
4623 this.bringToTop(overlay);
4627 } else if (overlay instanceof Array) {
4629 for (i = 0, n = overlay.length; i < n; i++) {
4630 registered = this.register(overlay[i]) || registered;
4639 * Places the specified Overlay instance on top of all other
4640 * Overlay instances.
4641 * @method bringToTop
4642 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4644 * @param {String} p_oOverlay String representing the id of an
4647 bringToTop: function (p_oOverlay) {
4649 var oOverlay = this.find(p_oOverlay),
4656 aOverlays = this.overlays;
4657 aOverlays.sort(this.compareZIndexDesc);
4659 oTopOverlay = aOverlays[0];
4662 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4664 if (!isNaN(nTopZIndex)) {
4666 var bRequiresBump = false;
4668 if (oTopOverlay !== oOverlay) {
4669 bRequiresBump = true;
4670 } else if (aOverlays.length > 1) {
4671 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4672 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4673 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4674 bRequiresBump = true;
4678 if (bRequiresBump) {
4679 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4682 aOverlays.sort(this.compareZIndexDesc);
4688 * Attempts to locate an Overlay by instance or ID.
4690 * @param {Overlay} overlay An Overlay to locate within the manager
4691 * @param {String} overlay An Overlay id to locate within the manager
4692 * @return {Overlay} The requested Overlay, if found, or null if it
4693 * cannot be located.
4695 find: function (overlay) {
4697 var isInstance = overlay instanceof Overlay,
4698 overlays = this.overlays,
4699 n = overlays.length,
4704 if (isInstance || typeof overlay == "string") {
4705 for (i = n-1; i >= 0; i--) {
4707 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4718 * Used for sorting the manager's Overlays by z-index.
4719 * @method compareZIndexDesc
4721 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4722 * fall in the stacking order.
4724 compareZIndexDesc: function (o1, o2) {
4726 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4727 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4729 if (zIndex1 === null && zIndex2 === null) {
4731 } else if (zIndex1 === null){
4733 } else if (zIndex2 === null) {
4735 } else if (zIndex1 > zIndex2) {
4737 } else if (zIndex1 < zIndex2) {
4745 * Shows all Overlays in the manager.
4748 showAll: function () {
4749 var overlays = this.overlays,
4750 n = overlays.length,
4753 for (i = n - 1; i >= 0; i--) {
4759 * Hides all Overlays in the manager.
4762 hideAll: function () {
4763 var overlays = this.overlays,
4764 n = overlays.length,
4767 for (i = n - 1; i >= 0; i--) {
4773 * Returns a string representation of the object.
4775 * @return {String} The string representation of the OverlayManager
4777 toString: function () {
4778 return "OverlayManager";
4785 * Tooltip is an implementation of Overlay that behaves like an OS tooltip,
4786 * displaying when the user mouses over a particular element, and
4787 * disappearing on mouse out.
4788 * @namespace YAHOO.widget
4790 * @extends YAHOO.widget.Overlay
4792 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4793 * @param {HTMLElement} el The element representing the Tooltip
4794 * @param {Object} userConfig The configuration object literal containing
4795 * the configuration that should be set for this Overlay. See configuration
4796 * documentation for more details.
4798 YAHOO.widget.Tooltip = function (el, userConfig) {
4799 YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4802 var Lang = YAHOO.lang,
4803 Event = YAHOO.util.Event,
4804 CustomEvent = YAHOO.util.CustomEvent,
4805 Dom = YAHOO.util.Dom,
4806 Tooltip = YAHOO.widget.Tooltip,
4808 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
4813 * Constant representing the Tooltip's configuration properties
4814 * @property DEFAULT_CONFIG
4821 "PREVENT_OVERLAP": {
4822 key: "preventoverlap",
4824 validator: Lang.isBoolean,
4825 supercedes: ["x", "y", "xy"]
4831 validator: Lang.isNumber
4834 "AUTO_DISMISS_DELAY": {
4835 key: "autodismissdelay",
4837 validator: Lang.isNumber
4843 validator: Lang.isNumber
4869 * Constant representing the name of the Tooltip's events
4870 * @property EVENT_TYPES
4876 "CONTEXT_MOUSE_OVER": "contextMouseOver",
4877 "CONTEXT_MOUSE_OUT": "contextMouseOut",
4878 "CONTEXT_TRIGGER": "contextTrigger"
4882 * Constant representing the Tooltip CSS class
4883 * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4888 Tooltip.CSS_TOOLTIP = "yui-tt";
4890 function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
4892 var oConfig = this.cfg,
4893 sCurrentWidth = oConfig.getProperty("width");
4895 if (sCurrentWidth == sForcedWidth) {
4896 oConfig.setProperty("width", sOriginalWidth);
4901 changeContent event handler that sets a Tooltip instance's "width"
4902 configuration property to the value of its root HTML
4903 elements's offsetWidth if a specific width has not been set.
4906 function setWidthToOffsetWidth(p_sType, p_aArgs) {
4908 if ("_originalWidth" in this) {
4909 restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
4912 var oBody = document.body,
4914 sOriginalWidth = oConfig.getProperty("width"),
4918 if ((!sOriginalWidth || sOriginalWidth == "auto") &&
4919 (oConfig.getProperty("container") != oBody ||
4920 oConfig.getProperty("x") >= Dom.getViewportWidth() ||
4921 oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4923 oClone = this.element.cloneNode(true);
4924 oClone.style.visibility = "hidden";
4925 oClone.style.top = "0px";
4926 oClone.style.left = "0px";
4928 oBody.appendChild(oClone);
4930 sNewWidth = (oClone.offsetWidth + "px");
4932 oBody.removeChild(oClone);
4935 oConfig.setProperty("width", sNewWidth);
4936 oConfig.refireEvent("xy");
4938 this._originalWidth = sOriginalWidth || "";
4939 this._forcedWidth = sNewWidth;
4943 // "onDOMReady" that renders the ToolTip
4945 function onDOMReady(p_sType, p_aArgs, p_oObject) {
4946 this.render(p_oObject);
4949 // "init" event handler that automatically renders the Tooltip
4952 Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4955 YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
4958 * The Tooltip initialization method. This method is automatically
4959 * called by the constructor. A Tooltip is automatically rendered by
4960 * the init method, and it also is set to be invisible by default,
4961 * and constrained to viewport by default as well.
4963 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4964 * @param {HTMLElement} el The element representing the Tooltip
4965 * @param {Object} userConfig The configuration object literal
4966 * containing the configuration that should be set for this Tooltip.
4967 * See configuration documentation for more details.
4969 init: function (el, userConfig) {
4972 Tooltip.superclass.init.call(this, el);
4974 this.beforeInitEvent.fire(Tooltip);
4976 Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
4979 this.cfg.applyConfig(userConfig, true);
4982 this.cfg.queueProperty("visible", false);
4983 this.cfg.queueProperty("constraintoviewport", true);
4987 this.subscribe("changeContent", setWidthToOffsetWidth);
4988 this.subscribe("init", onInit);
4989 this.subscribe("render", this.onRender);
4991 this.initEvent.fire(Tooltip);
4995 * Initializes the custom events for Tooltip
4996 * @method initEvents
4998 initEvents: function () {
5000 Tooltip.superclass.initEvents.call(this);
5001 var SIGNATURE = CustomEvent.LIST;
5004 * CustomEvent fired when user mouses over a context element. Returning false from
5005 * a subscriber to this event will prevent the tooltip from being displayed for
5006 * the current context element.
5008 * @event contextMouseOverEvent
5009 * @param {HTMLElement} context The context element which the user just moused over
5010 * @param {DOMEvent} e The DOM event object, associated with the mouse over
5012 this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
5013 this.contextMouseOverEvent.signature = SIGNATURE;
5016 * CustomEvent fired when the user mouses out of a context element.
5018 * @event contextMouseOutEvent
5019 * @param {HTMLElement} context The context element which the user just moused out of
5020 * @param {DOMEvent} e The DOM event object, associated with the mouse out
5022 this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
5023 this.contextMouseOutEvent.signature = SIGNATURE;
5026 * CustomEvent fired just before the tooltip is displayed for the current context.
5028 * You can subscribe to this event if you need to set up the text for the
5029 * tooltip based on the context element for which it is about to be displayed.
5031 * <p>This event differs from the beforeShow event in following respects:</p>
5034 * When moving from one context element to another, if the tooltip is not
5035 * hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
5036 * be fired when the tooltip is displayed for the new context since it is already visible.
5037 * However the contextTrigger event is always fired before displaying the tooltip for
5041 * The trigger event provides access to the context element, allowing you to
5042 * set the text of the tooltip based on context element for which the tooltip is
5047 * It is not possible to prevent the tooltip from being displayed
5048 * using this event. You can use the contextMouseOverEvent if you need to prevent
5049 * the tooltip from being displayed.
5051 * @event contextTriggerEvent
5052 * @param {HTMLElement} context The context element for which the tooltip is triggered
5054 this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
5055 this.contextTriggerEvent.signature = SIGNATURE;
5059 * Initializes the class's configurable properties which can be
5060 * changed using the Overlay's Config object (cfg).
5061 * @method initDefaultConfig
5063 initDefaultConfig: function () {
5065 Tooltip.superclass.initDefaultConfig.call(this);
5068 * Specifies whether the Tooltip should be kept from overlapping
5069 * its context element.
5070 * @config preventoverlap
5074 this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
5075 value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
5076 validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
5077 supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
5081 * The number of milliseconds to wait before showing a Tooltip
5087 this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
5088 handler: this.configShowDelay,
5090 validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5094 * The number of milliseconds to wait before automatically
5095 * dismissing a Tooltip after the mouse has been resting on the
5097 * @config autodismissdelay
5101 this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
5102 handler: this.configAutoDismissDelay,
5103 value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
5104 validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
5108 * The number of milliseconds to wait before hiding a Tooltip
5114 this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
5115 handler: this.configHideDelay,
5116 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5117 validator: DEFAULT_CONFIG.HIDE_DELAY.validator
5121 * Specifies the Tooltip's text. The text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
5126 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
5127 handler: this.configText,
5128 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
5132 * Specifies the container element that the Tooltip's markup
5133 * should be rendered into.
5135 * @type HTMLElement/String
5136 * @default document.body
5138 this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
5139 handler: this.configContainer,
5140 value: document.body
5144 * Specifies whether or not the tooltip is disabled. Disabled tooltips
5145 * will not be displayed. If the tooltip is driven by the title attribute
5146 * of the context element, the title attribute will still be removed for
5147 * disabled tooltips, to prevent default tooltip behavior.
5153 this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
5154 handler: this.configContainer,
5155 value: DEFAULT_CONFIG.DISABLED.value,
5156 supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5160 * Specifies the XY offset from the mouse position, where the tooltip should be displayed, specified
5161 * as a 2 element array (e.g. [10, 20]);
5167 this.cfg.addProperty(DEFAULT_CONFIG.XY_OFFSET.key, {
5168 value: DEFAULT_CONFIG.XY_OFFSET.value.concat(),
5169 supressEvent: DEFAULT_CONFIG.XY_OFFSET.suppressEvent
5173 * Specifies the element or elements that the Tooltip should be
5174 * anchored to on mouseover.
5176 * @type HTMLElement[]/String[]
5181 * String representing the width of the Tooltip. <em>Please note:
5182 * </em> As of version 2.3 if either no value or a value of "auto"
5183 * is specified, and the Toolip's "container" configuration property
5184 * is set to something other than <code>document.body</code> or
5185 * its "context" element resides outside the immediately visible
5186 * portion of the document, the width of the Tooltip will be
5187 * calculated based on the offsetWidth of its root HTML and set just
5188 * before it is made visible. The original value will be
5189 * restored when the Tooltip is hidden. This ensures the Tooltip is
5190 * rendered at a usable width. For more information see
5191 * YUILibrary bug #1685496 and YUILibrary
5200 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5203 * The default event handler fired when the "text" property is changed.
5204 * @method configText
5205 * @param {String} type The CustomEvent type (usually the property name)
5206 * @param {Object[]} args The CustomEvent arguments. For configuration
5207 * handlers, args[0] will equal the newly applied value for the property.
5208 * @param {Object} obj The scope object. For configuration handlers,
5209 * this will usually equal the owner.
5211 configText: function (type, args, obj) {
5219 * The default event handler fired when the "container" property
5221 * @method configContainer
5222 * @param {String} type The CustomEvent type (usually the property name)
5223 * @param {Object[]} args The CustomEvent arguments. For
5224 * configuration handlers, args[0] will equal the newly applied value
5226 * @param {Object} obj The scope object. For configuration handlers,
5227 * this will usually equal the owner.
5229 configContainer: function (type, args, obj) {
5230 var container = args[0];
5232 if (typeof container == 'string') {
5233 this.cfg.setProperty("container", document.getElementById(container), true);
5238 * @method _removeEventListeners
5239 * @description Removes all of the DOM event handlers from the HTML
5240 * element(s) that trigger the display of the tooltip.
5243 _removeEventListeners: function () {
5245 var aElements = this._context,
5251 nElements = aElements.length;
5252 if (nElements > 0) {
5255 oElement = aElements[i];
5256 Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
5257 Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
5258 Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
5266 * The default event handler fired when the "context" property
5268 * @method configContext
5269 * @param {String} type The CustomEvent type (usually the property name)
5270 * @param {Object[]} args The CustomEvent arguments. For configuration
5271 * handlers, args[0] will equal the newly applied value for the property.
5272 * @param {Object} obj The scope object. For configuration handlers,
5273 * this will usually equal the owner.
5275 configContext: function (type, args, obj) {
5277 var context = args[0],
5285 // Normalize parameter into an array
5286 if (! (context instanceof Array)) {
5287 if (typeof context == "string") {
5288 this.cfg.setProperty("context", [document.getElementById(context)], true);
5289 } else { // Assuming this is an element
5290 this.cfg.setProperty("context", [context], true);
5292 context = this.cfg.getProperty("context");
5295 // Remove any existing mouseover/mouseout listeners
5296 this._removeEventListeners();
5298 // Add mouseover/mouseout listeners to context elements
5299 this._context = context;
5301 aElements = this._context;
5304 nElements = aElements.length;
5305 if (nElements > 0) {
5308 oElement = aElements[i];
5309 Event.on(oElement, "mouseover", this.onContextMouseOver, this);
5310 Event.on(oElement, "mousemove", this.onContextMouseMove, this);
5311 Event.on(oElement, "mouseout", this.onContextMouseOut, this);
5319 // END BUILT-IN PROPERTY EVENT HANDLERS //
5321 // BEGIN BUILT-IN DOM EVENT HANDLERS //
5324 * The default event handler fired when the user moves the mouse while
5325 * over the context element.
5326 * @method onContextMouseMove
5327 * @param {DOMEvent} e The current DOM event
5328 * @param {Object} obj The object argument
5330 onContextMouseMove: function (e, obj) {
5331 obj.pageX = Event.getPageX(e);
5332 obj.pageY = Event.getPageY(e);
5336 * The default event handler fired when the user mouses over the
5338 * @method onContextMouseOver
5339 * @param {DOMEvent} e The current DOM event
5340 * @param {Object} obj The object argument
5342 onContextMouseOver: function (e, obj) {
5345 if (context.title) {
5346 obj._tempTitle = context.title;
5350 // Fire first, to honor disabled set in the listner
5351 if (obj.fireEvent("contextMouseOver", context, e) !== false && !obj.cfg.getProperty("disabled")) {
5353 // Stop the tooltip from being hidden (set on last mouseout)
5354 if (obj.hideProcId) {
5355 clearTimeout(obj.hideProcId);
5356 obj.hideProcId = null;
5359 Event.on(context, "mousemove", obj.onContextMouseMove, obj);
5362 * The unique process ID associated with the thread responsible
5363 * for showing the Tooltip.
5366 obj.showProcId = obj.doShow(e, context);
5371 * The default event handler fired when the user mouses out of
5372 * the context element.
5373 * @method onContextMouseOut
5374 * @param {DOMEvent} e The current DOM event
5375 * @param {Object} obj The object argument
5377 onContextMouseOut: function (e, obj) {
5380 if (obj._tempTitle) {
5381 el.title = obj._tempTitle;
5382 obj._tempTitle = null;
5385 if (obj.showProcId) {
5386 clearTimeout(obj.showProcId);
5387 obj.showProcId = null;
5390 if (obj.hideProcId) {
5391 clearTimeout(obj.hideProcId);
5392 obj.hideProcId = null;
5395 obj.fireEvent("contextMouseOut", el, e);
5397 obj.hideProcId = setTimeout(function () {
5399 }, obj.cfg.getProperty("hidedelay"));
5402 // END BUILT-IN DOM EVENT HANDLERS //
5405 * Processes the showing of the Tooltip by setting the timeout delay
5406 * and offset of the Tooltip.
5408 * @param {DOMEvent} e The current DOM event
5409 * @param {HTMLElement} context The current context element
5410 * @return {Number} The process ID of the timeout function associated
5413 doShow: function (e, context) {
5415 var offset = this.cfg.getProperty("xyoffset"),
5416 xOffset = offset[0],
5417 yOffset = offset[1],
5420 if (UA.opera && context.tagName &&
5421 context.tagName.toUpperCase() == "A") {
5425 return setTimeout(function () {
5427 var txt = me.cfg.getProperty("text");
5429 // title does not over-ride text
5430 if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
5431 me.setBody(me._tempTitle);
5433 me.cfg.refireEvent("text");
5436 me.moveTo(me.pageX + xOffset, me.pageY + yOffset);
5438 if (me.cfg.getProperty("preventoverlap")) {
5439 me.preventOverlap(me.pageX, me.pageY);
5442 Event.removeListener(context, "mousemove", me.onContextMouseMove);
5444 me.contextTriggerEvent.fire(context);
5448 me.hideProcId = me.doHide();
5450 }, this.cfg.getProperty("showdelay"));
5454 * Sets the timeout for the auto-dismiss delay, which by default is 5
5455 * seconds, meaning that a tooltip will automatically dismiss itself
5456 * after 5 seconds of being displayed.
5459 doHide: function () {
5464 return setTimeout(function () {
5468 }, this.cfg.getProperty("autodismissdelay"));
5473 * Fired when the Tooltip is moved, this event handler is used to
5474 * prevent the Tooltip from overlapping with its context element.
5475 * @method preventOverlay
5476 * @param {Number} pageX The x coordinate position of the mouse pointer
5477 * @param {Number} pageY The y coordinate position of the mouse pointer
5479 preventOverlap: function (pageX, pageY) {
5481 var height = this.element.offsetHeight,
5482 mousePoint = new YAHOO.util.Point(pageX, pageY),
5483 elementRegion = Dom.getRegion(this.element);
5485 elementRegion.top -= 5;
5486 elementRegion.left -= 5;
5487 elementRegion.right += 5;
5488 elementRegion.bottom += 5;
5491 if (elementRegion.contains(mousePoint)) {
5492 this.cfg.setProperty("y", (pageY - height - 5));
5499 * @description "render" event handler for the Tooltip.
5500 * @param {String} p_sType String representing the name of the event
5502 * @param {Array} p_aArgs Array of arguments sent when the event
5505 onRender: function (p_sType, p_aArgs) {
5507 function sizeShadow() {
5509 var oElement = this.element,
5510 oShadow = this.underlay;
5513 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
5514 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
5519 function addShadowVisibleClass() {
5520 Dom.addClass(this.underlay, "yui-tt-shadow-visible");
5523 this.forceUnderlayRedraw();
5527 function removeShadowVisibleClass() {
5528 Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
5531 function createShadow() {
5533 var oShadow = this.underlay,
5541 oElement = this.element;
5542 Module = YAHOO.widget.Module;
5546 if (!m_oShadowTemplate) {
5547 m_oShadowTemplate = document.createElement("div");
5548 m_oShadowTemplate.className = "yui-tt-shadow";
5551 oShadow = m_oShadowTemplate.cloneNode(false);
5553 oElement.appendChild(oShadow);
5555 this.underlay = oShadow;
5557 // Backward compatibility, even though it's probably
5558 // intended to be "private", it isn't marked as such in the api docs
5559 this._shadow = this.underlay;
5561 addShadowVisibleClass.call(this);
5563 this.subscribe("beforeShow", addShadowVisibleClass);
5564 this.subscribe("hide", removeShadowVisibleClass);
5567 window.setTimeout(function () {
5568 sizeShadow.call(me);
5571 this.cfg.subscribeToConfigEvent("width", sizeShadow);
5572 this.cfg.subscribeToConfigEvent("height", sizeShadow);
5573 this.subscribe("changeContent", sizeShadow);
5575 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5576 this.subscribe("destroy", function () {
5577 Module.textResizeEvent.unsubscribe(sizeShadow, this);
5583 function onBeforeShow() {
5584 createShadow.call(this);
5585 this.unsubscribe("beforeShow", onBeforeShow);
5588 if (this.cfg.getProperty("visible")) {
5589 createShadow.call(this);
5591 this.subscribe("beforeShow", onBeforeShow);
5597 * Forces the underlay element to be repainted, through the application/removal
5598 * of a yui-force-redraw class to the underlay element.
5600 * @method forceUnderlayRedraw
5602 forceUnderlayRedraw : function() {
5604 Dom.addClass(tt.underlay, "yui-force-redraw");
5605 setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
5609 * Removes the Tooltip element from the DOM and sets all child
5613 destroy: function () {
5615 // Remove any existing mouseover/mouseout listeners
5616 this._removeEventListeners();
5618 Tooltip.superclass.destroy.call(this);
5623 * Returns a string representation of the object.
5625 * @return {String} The string representation of the Tooltip
5627 toString: function () {
5628 return "Tooltip " + this.id;
5637 * Panel is an implementation of Overlay that behaves like an OS window,
5638 * with a draggable header and an optional close icon at the top right.
5639 * @namespace YAHOO.widget
5641 * @extends YAHOO.widget.Overlay
5643 * @param {String} el The element ID representing the Panel <em>OR</em>
5644 * @param {HTMLElement} el The element representing the Panel
5645 * @param {Object} userConfig The configuration object literal containing
5646 * the configuration that should be set for this Panel. See configuration
5647 * documentation for more details.
5649 YAHOO.widget.Panel = function (el, userConfig) {
5650 YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5653 var _currentModal = null;
5655 var Lang = YAHOO.lang,
5659 CustomEvent = Util.CustomEvent,
5660 KeyListener = YAHOO.util.KeyListener,
5661 Config = Util.Config,
5662 Overlay = YAHOO.widget.Overlay,
5663 Panel = YAHOO.widget.Panel,
5666 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
5669 m_oUnderlayTemplate,
5670 m_oCloseIconTemplate,
5673 * Constant representing the name of the Panel's events
5674 * @property EVENT_TYPES
5680 "BEFORE_SHOW_MASK" : "beforeShowMask",
5681 "BEFORE_HIDE_MASK" : "beforeHideMask",
5682 "SHOW_MASK": "showMask",
5683 "HIDE_MASK": "hideMask",
5688 * Constant representing the Panel's configuration properties
5689 * @property DEFAULT_CONFIG
5699 validator: Lang.isBoolean,
5700 supercedes: ["visible"]
5705 value: (Util.DD ? true : false),
5706 validator: Lang.isBoolean,
5707 supercedes: ["visible"]
5713 validator: Lang.isBoolean,
5714 supercedes: ["draggable"]
5720 supercedes: ["visible"]
5726 validator: Lang.isBoolean,
5727 supercedes: ["visible", "zindex"]
5731 key: "keylisteners",
5732 suppressEvent: true,
5733 supercedes: ["visible"]
5738 supercedes: ["close"],
5739 validator: Lang.isObject,
5747 * Constant representing the default CSS class used for a Panel
5748 * @property YAHOO.widget.Panel.CSS_PANEL
5753 Panel.CSS_PANEL = "yui-panel";
5756 * Constant representing the default CSS class used for a Panel's
5757 * wrapping container
5758 * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5763 Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5766 * Constant representing the default set of focusable elements
5767 * on the pagewhich Modal Panels will prevent access to, when
5768 * the modal mask is displayed
5770 * @property YAHOO.widget.Panel.FOCUSABLE
5783 // Private CustomEvent listeners
5786 "beforeRender" event handler that creates an empty header for a Panel
5787 instance if its "draggable" configuration property is set to "true"
5788 and no header has been created.
5791 function createHeader(p_sType, p_aArgs) {
5792 if (!this.header && this.cfg.getProperty("draggable")) {
5793 this.setHeader(" ");
5798 "hide" event handler that sets a Panel instance's "width"
5799 configuration property back to its original value before
5800 "setWidthToOffsetWidth" was called.
5803 function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5805 var sOriginalWidth = p_oObject[0],
5806 sNewWidth = p_oObject[1],
5808 sCurrentWidth = oConfig.getProperty("width");
5810 if (sCurrentWidth == sNewWidth) {
5811 oConfig.setProperty("width", sOriginalWidth);
5814 this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5818 "beforeShow" event handler that sets a Panel instance's "width"
5819 configuration property to the value of its root HTML
5820 elements's offsetWidth
5823 function setWidthToOffsetWidth(p_sType, p_aArgs) {
5832 sOriginalWidth = oConfig.getProperty("width");
5834 if (!sOriginalWidth || sOriginalWidth == "auto") {
5836 sNewWidth = (this.element.offsetWidth + "px");
5838 oConfig.setProperty("width", sNewWidth);
5840 this.subscribe("hide", restoreOriginalWidth,
5841 [(sOriginalWidth || ""), sNewWidth]);
5847 YAHOO.extend(Panel, Overlay, {
5850 * The Overlay initialization method, which is executed for Overlay and
5851 * all of its subclasses. This method is automatically called by the
5852 * constructor, and sets up all DOM references for pre-existing markup,
5853 * and creates required markup if it is not already present.
5855 * @param {String} el The element ID representing the Overlay <em>OR</em>
5856 * @param {HTMLElement} el The element representing the Overlay
5857 * @param {Object} userConfig The configuration object literal
5858 * containing the configuration that should be set for this Overlay.
5859 * See configuration documentation for more details.
5861 init: function (el, userConfig) {
5863 Note that we don't pass the user config in here yet because
5864 we only want it executed once, at the lowest subclass level
5867 Panel.superclass.init.call(this, el/*, userConfig*/);
5869 this.beforeInitEvent.fire(Panel);
5871 Dom.addClass(this.element, Panel.CSS_PANEL);
5873 this.buildWrapper();
5876 this.cfg.applyConfig(userConfig, true);
5879 this.subscribe("showMask", this._addFocusHandlers);
5880 this.subscribe("hideMask", this._removeFocusHandlers);
5881 this.subscribe("beforeRender", createHeader);
5883 this.subscribe("render", function() {
5884 this.setFirstLastFocusable();
5885 this.subscribe("changeContent", this.setFirstLastFocusable);
5888 this.subscribe("show", this._focusOnShow);
5890 this.initEvent.fire(Panel);
5894 * @method _onElementFocus
5897 * "focus" event handler for a focuable element. Used to automatically
5898 * blur the element when it receives focus to ensure that a Panel
5899 * instance's modality is not compromised.
5901 * @param {Event} e The DOM event object
5903 _onElementFocus : function(e){
5905 if(_currentModal === this) {
5907 var target = Event.getTarget(e),
5908 doc = document.documentElement,
5909 insideDoc = (target !== doc && target !== window);
5911 // mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on
5912 // the documentElement, when the document scrollbars are clicked on
5913 if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
5915 this._focusFirstModal();
5917 // Just in case we fail to focus
5919 if (insideDoc && target !== document.body) {
5929 * Focuses on the first element if present, otherwise falls back to the focus mechanisms used for
5930 * modality. This method does not try/catch focus failures. The caller is responsible for catching exceptions,
5931 * and taking remedial measures.
5933 * @method _focusFirstModal
5935 _focusFirstModal : function() {
5936 var el = this.firstElement;
5940 if (this._modalFocus) {
5941 this._modalFocus.focus();
5943 this.innerElement.focus();
5949 * @method _addFocusHandlers
5952 * "showMask" event handler that adds a "focus" event handler to all
5953 * focusable elements in the document to enforce a Panel instance's
5954 * modality from being compromised.
5956 * @param p_sType {String} Custom event type
5957 * @param p_aArgs {Array} Custom event arguments
5959 _addFocusHandlers: function(p_sType, p_aArgs) {
5960 if (!this.firstElement) {
5961 if (UA.webkit || UA.opera) {
5962 if (!this._modalFocus) {
5963 this._createHiddenFocusElement();
5966 this.innerElement.tabIndex = 0;
5969 this._setTabLoop(this.firstElement, this.lastElement);
5970 Event.onFocus(document.documentElement, this._onElementFocus, this, true);
5971 _currentModal = this;
5975 * Creates a hidden focusable element, used to focus on,
5976 * to enforce modality for browsers in which focus cannot
5977 * be applied to the container box.
5979 * @method _createHiddenFocusElement
5982 _createHiddenFocusElement : function() {
5983 var e = document.createElement("button");
5984 e.style.height = "1px";
5985 e.style.width = "1px";
5986 e.style.position = "absolute";
5987 e.style.left = "-10000em";
5988 e.style.opacity = 0;
5990 this.innerElement.appendChild(e);
5991 this._modalFocus = e;
5995 * @method _removeFocusHandlers
5998 * "hideMask" event handler that removes all "focus" event handlers added
5999 * by the "addFocusEventHandlers" method.
6001 * @param p_sType {String} Event type
6002 * @param p_aArgs {Array} Event Arguments
6004 _removeFocusHandlers: function(p_sType, p_aArgs) {
6005 Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
6007 if (_currentModal == this) {
6008 _currentModal = null;
6013 * Focus handler for the show event
6015 * @method _focusOnShow
6016 * @param {String} type Event Type
6017 * @param {Array} args Event arguments
6018 * @param {Object} obj Additional data
6020 _focusOnShow : function(type, args, obj) {
6022 if (args && args[1]) {
6023 Event.stopEvent(args[1]);
6026 if (!this.focusFirst(type, args, obj)) {
6027 if (this.cfg.getProperty("modal")) {
6028 this._focusFirstModal();
6034 * Sets focus to the first element in the Panel.
6036 * @method focusFirst
6037 * @return {Boolean} true, if successfully focused, false otherwise
6039 focusFirst: function (type, args, obj) {
6040 var el = this.firstElement, focused = false;
6042 if (args && args[1]) {
6043 Event.stopEvent(args[1]);
6059 * Sets focus to the last element in the Panel.
6062 * @return {Boolean} true, if successfully focused, false otherwise
6064 focusLast: function (type, args, obj) {
6065 var el = this.lastElement, focused = false;
6067 if (args && args[1]) {
6068 Event.stopEvent(args[1]);
6084 * Protected internal method for setTabLoop, which can be used by
6085 * subclasses to jump in and modify the arguments passed in if required.
6087 * @method _setTabLoop
6088 * @param {HTMLElement} firstElement
6089 * @param {HTMLElement} lastElement
6093 _setTabLoop : function(firstElement, lastElement) {
6094 this.setTabLoop(firstElement, lastElement);
6098 * Sets up a tab, shift-tab loop between the first and last elements
6099 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
6100 * instance properties, which are reset everytime this method is invoked.
6102 * @method setTabLoop
6103 * @param {HTMLElement} firstElement
6104 * @param {HTMLElement} lastElement
6107 setTabLoop : function(firstElement, lastElement) {
6109 var backTab = this.preventBackTab, tab = this.preventTabOut,
6110 showEvent = this.showEvent, hideEvent = this.hideEvent;
6114 showEvent.unsubscribe(backTab.enable, backTab);
6115 hideEvent.unsubscribe(backTab.disable, backTab);
6116 backTab = this.preventBackTab = null;
6121 showEvent.unsubscribe(tab.enable, tab);
6122 hideEvent.unsubscribe(tab.disable,tab);
6123 tab = this.preventTabOut = null;
6127 this.preventBackTab = new KeyListener(firstElement,
6128 {shift:true, keys:9},
6129 {fn:this.focusLast, scope:this, correctScope:true}
6131 backTab = this.preventBackTab;
6133 showEvent.subscribe(backTab.enable, backTab, true);
6134 hideEvent.subscribe(backTab.disable,backTab, true);
6138 this.preventTabOut = new KeyListener(lastElement,
6139 {shift:false, keys:9},
6140 {fn:this.focusFirst, scope:this, correctScope:true}
6142 tab = this.preventTabOut;
6144 showEvent.subscribe(tab.enable, tab, true);
6145 hideEvent.subscribe(tab.disable,tab, true);
6150 * Returns an array of the currently focusable items which reside within
6151 * Panel. The set of focusable elements the method looks for are defined
6152 * in the Panel.FOCUSABLE static property
6154 * @method getFocusableElements
6155 * @param {HTMLElement} root element to start from.
6157 getFocusableElements : function(root) {
6159 root = root || this.innerElement;
6161 var focusable = {}, panel = this;
6162 for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
6163 focusable[Panel.FOCUSABLE[i]] = true;
6166 // Not looking by Tag, since we want elements in DOM order
6168 return Dom.getElementsBy(function(el) { return panel._testIfFocusable(el, focusable); }, null, root);
6172 * This is the test method used by getFocusableElements, to determine which elements to
6173 * include in the focusable elements list. Users may override this to customize behavior.
6175 * @method _testIfFocusable
6176 * @param {Object} el The element being tested
6177 * @param {Object} focusable The hash of known focusable elements, created by an array-to-map operation on Panel.FOCUSABLE
6180 _testIfFocusable: function(el, focusable) {
6181 if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
6188 * Sets the firstElement and lastElement instance properties
6189 * to the first and last focusable elements in the Panel.
6191 * @method setFirstLastFocusable
6193 setFirstLastFocusable : function() {
6195 this.firstElement = null;
6196 this.lastElement = null;
6198 var elements = this.getFocusableElements();
6199 this.focusableElements = elements;
6201 if (elements.length > 0) {
6202 this.firstElement = elements[0];
6203 this.lastElement = elements[elements.length - 1];
6206 if (this.cfg.getProperty("modal")) {
6207 this._setTabLoop(this.firstElement, this.lastElement);
6212 * Initializes the custom events for Module which are fired
6213 * automatically at appropriate times by the Module class.
6215 initEvents: function () {
6216 Panel.superclass.initEvents.call(this);
6218 var SIGNATURE = CustomEvent.LIST;
6221 * CustomEvent fired after the modality mask is shown
6222 * @event showMaskEvent
6224 this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
6225 this.showMaskEvent.signature = SIGNATURE;
6228 * CustomEvent fired before the modality mask is shown. Subscribers can return false to prevent the
6229 * mask from being shown
6230 * @event beforeShowMaskEvent
6232 this.beforeShowMaskEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW_MASK);
6233 this.beforeShowMaskEvent.signature = SIGNATURE;
6236 * CustomEvent fired after the modality mask is hidden
6237 * @event hideMaskEvent
6239 this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
6240 this.hideMaskEvent.signature = SIGNATURE;
6243 * CustomEvent fired before the modality mask is hidden. Subscribers can return false to prevent the
6244 * mask from being hidden
6245 * @event beforeHideMaskEvent
6247 this.beforeHideMaskEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE_MASK);
6248 this.beforeHideMaskEvent.signature = SIGNATURE;
6251 * CustomEvent when the Panel is dragged
6254 this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
6255 this.dragEvent.signature = SIGNATURE;
6259 * Initializes the class's configurable properties which can be changed
6260 * using the Panel's Config object (cfg).
6261 * @method initDefaultConfig
6263 initDefaultConfig: function () {
6264 Panel.superclass.initDefaultConfig.call(this);
6266 // Add panel config properties //
6269 * True if the Panel should display a "close" button
6274 this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
6275 handler: this.configClose,
6276 value: DEFAULT_CONFIG.CLOSE.value,
6277 validator: DEFAULT_CONFIG.CLOSE.validator,
6278 supercedes: DEFAULT_CONFIG.CLOSE.supercedes
6282 * Boolean specifying if the Panel should be draggable. The default
6283 * value is "true" if the Drag and Drop utility is included,
6284 * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
6285 * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
6286 * (Quirks Mode) where Panels that either don't have a value set for
6287 * their "width" configuration property, or their "width"
6288 * configuration property is set to "auto" will only be draggable by
6289 * placing the mouse on the text of the Panel's header element.
6290 * To fix this bug, draggable Panels missing a value for their
6291 * "width" configuration property, or whose "width" configuration
6292 * property is set to "auto" will have it set to the value of
6293 * their root HTML element's offsetWidth before they are made
6294 * visible. The calculated width is then removed when the Panel is
6295 * hidden. <em>This fix is only applied to draggable Panels in IE 6
6296 * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
6297 * more information on this issue see:
6298 * YUILibrary bugs #1726972 and #1589210.
6303 this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
6304 handler: this.configDraggable,
6305 value: (Util.DD) ? true : false,
6306 validator: DEFAULT_CONFIG.DRAGGABLE.validator,
6307 supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
6311 * Boolean specifying if the draggable Panel should be drag only, not interacting with drop
6312 * targets on the page.
6314 * When set to true, draggable Panels will not check to see if they are over drop targets,
6315 * or fire the DragDrop events required to support drop target interaction (onDragEnter,
6316 * onDragOver, onDragOut, onDragDrop etc.).
6317 * If the Panel is not designed to be dropped on any target elements on the page, then this
6318 * flag can be set to true to improve performance.
6321 * When set to false, all drop target related events will be fired.
6324 * The property is set to false by default to maintain backwards compatibility but should be
6325 * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
6331 this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, {
6332 value: DEFAULT_CONFIG.DRAG_ONLY.value,
6333 validator: DEFAULT_CONFIG.DRAG_ONLY.validator,
6334 supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes
6338 * Sets the type of underlay to display for the Panel. Valid values
6339 * are "shadow," "matte," and "none". <strong>PLEASE NOTE:</strong>
6340 * The creation of the underlay element is deferred until the Panel
6341 * is initially made visible. For Gecko-based browsers on Mac
6342 * OS X the underlay elment is always created as it is used as a
6343 * shim to prevent Aqua scrollbars below a Panel instance from poking
6344 * through it (See YUILibrary bug #1723530).
6349 this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
6350 handler: this.configUnderlay,
6351 value: DEFAULT_CONFIG.UNDERLAY.value,
6352 supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
6356 * True if the Panel should be displayed in a modal fashion,
6357 * automatically creating a transparent mask over the document that
6358 * will not be removed until the Panel is dismissed.
6363 this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
6364 handler: this.configModal,
6365 value: DEFAULT_CONFIG.MODAL.value,
6366 validator: DEFAULT_CONFIG.MODAL.validator,
6367 supercedes: DEFAULT_CONFIG.MODAL.supercedes
6371 * A KeyListener (or array of KeyListeners) that will be enabled
6372 * when the Panel is shown, and disabled when the Panel is hidden.
6373 * @config keylisteners
6374 * @type YAHOO.util.KeyListener[]
6377 this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
6378 handler: this.configKeyListeners,
6379 suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
6380 supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
6384 * UI Strings used by the Panel. The strings are inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
6388 * @default An object literal with the properties shown below:
6390 * <dt>close</dt><dd><em>HTML</em> : The markup to use as the label for the close icon. Defaults to "Close".</dd>
6393 this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, {
6394 value:DEFAULT_CONFIG.STRINGS.value,
6395 handler:this.configStrings,
6396 validator:DEFAULT_CONFIG.STRINGS.validator,
6397 supercedes:DEFAULT_CONFIG.STRINGS.supercedes
6401 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6404 * The default event handler fired when the "close" property is changed.
6405 * The method controls the appending or hiding of the close icon at the
6406 * top right of the Panel.
6407 * @method configClose
6408 * @param {String} type The CustomEvent type (usually the property name)
6409 * @param {Object[]} args The CustomEvent arguments. For configuration
6410 * handlers, args[0] will equal the newly applied value for the property.
6411 * @param {Object} obj The scope object. For configuration handlers,
6412 * this will usually equal the owner.
6414 configClose: function (type, args, obj) {
6417 oClose = this.close,
6418 strings = this.cfg.getProperty("strings"),
6424 if (!m_oCloseIconTemplate) {
6425 m_oCloseIconTemplate = document.createElement("a");
6426 m_oCloseIconTemplate.className = "container-close";
6427 m_oCloseIconTemplate.href = "#";
6430 oClose = m_oCloseIconTemplate.cloneNode(true);
6432 fc = this.innerElement.firstChild;
6435 this.innerElement.insertBefore(oClose, fc);
6437 this.innerElement.appendChild(oClose);
6440 oClose.innerHTML = (strings && strings.close) ? strings.close : " ";
6442 Event.on(oClose, "click", this._doClose, this, true);
6444 this.close = oClose;
6447 oClose.style.display = "block";
6452 oClose.style.display = "none";
6459 * Event handler for the close icon
6464 * @param {DOMEvent} e
6466 _doClose : function (e) {
6467 Event.preventDefault(e);
6472 * The default event handler fired when the "draggable" property
6474 * @method configDraggable
6475 * @param {String} type The CustomEvent type (usually the property name)
6476 * @param {Object[]} args The CustomEvent arguments. For configuration
6477 * handlers, args[0] will equal the newly applied value for the property.
6478 * @param {Object} obj The scope object. For configuration handlers,
6479 * this will usually equal the owner.
6481 configDraggable: function (type, args, obj) {
6486 this.cfg.setProperty("draggable", false);
6491 Dom.setStyle(this.header, "cursor", "move");
6492 this.registerDragDrop();
6495 this.subscribe("beforeShow", setWidthToOffsetWidth);
6504 Dom.setStyle(this.header,"cursor","auto");
6507 this.unsubscribe("beforeShow", setWidthToOffsetWidth);
6512 * The default event handler fired when the "underlay" property
6514 * @method configUnderlay
6515 * @param {String} type The CustomEvent type (usually the property name)
6516 * @param {Object[]} args The CustomEvent arguments. For configuration
6517 * handlers, args[0] will equal the newly applied value for the property.
6518 * @param {Object} obj The scope object. For configuration handlers,
6519 * this will usually equal the owner.
6521 configUnderlay: function (type, args, obj) {
6523 var bMacGecko = (this.platform == "mac" && UA.gecko),
6524 sUnderlay = args[0].toLowerCase(),
6525 oUnderlay = this.underlay,
6526 oElement = this.element;
6528 function createUnderlay() {
6530 if (!oUnderlay) { // create if not already in DOM
6532 if (!m_oUnderlayTemplate) {
6533 m_oUnderlayTemplate = document.createElement("div");
6534 m_oUnderlayTemplate.className = "underlay";
6537 oUnderlay = m_oUnderlayTemplate.cloneNode(false);
6538 this.element.appendChild(oUnderlay);
6540 this.underlay = oUnderlay;
6543 this.sizeUnderlay();
6544 this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
6545 this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
6547 this.changeContentEvent.subscribe(this.sizeUnderlay);
6548 YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
6551 if (UA.webkit && UA.webkit < 420) {
6552 this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
6559 function onBeforeShow() {
6560 var bNew = createUnderlay.call(this);
6561 if (!bNew && bIEQuirks) {
6562 this.sizeUnderlay();
6564 this._underlayDeferred = false;
6565 this.beforeShowEvent.unsubscribe(onBeforeShow);
6568 function destroyUnderlay() {
6569 if (this._underlayDeferred) {
6570 this.beforeShowEvent.unsubscribe(onBeforeShow);
6571 this._underlayDeferred = false;
6575 this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
6576 this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
6577 this.changeContentEvent.unsubscribe(this.sizeUnderlay);
6578 this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
6579 YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
6581 this.element.removeChild(oUnderlay);
6583 this.underlay = null;
6587 switch (sUnderlay) {
6589 Dom.removeClass(oElement, "matte");
6590 Dom.addClass(oElement, "shadow");
6594 destroyUnderlay.call(this);
6596 Dom.removeClass(oElement, "shadow");
6597 Dom.addClass(oElement, "matte");
6601 destroyUnderlay.call(this);
6603 Dom.removeClass(oElement, "shadow");
6604 Dom.removeClass(oElement, "matte");
6608 if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
6609 if (this.cfg.getProperty("visible")) {
6610 var bNew = createUnderlay.call(this);
6611 if (!bNew && bIEQuirks) {
6612 this.sizeUnderlay();
6615 if (!this._underlayDeferred) {
6616 this.beforeShowEvent.subscribe(onBeforeShow);
6617 this._underlayDeferred = true;
6624 * The default event handler fired when the "modal" property is
6625 * changed. This handler subscribes or unsubscribes to the show and hide
6626 * events to handle the display or hide of the modality mask.
6627 * @method configModal
6628 * @param {String} type The CustomEvent type (usually the property name)
6629 * @param {Object[]} args The CustomEvent arguments. For configuration
6630 * handlers, args[0] will equal the newly applied value for the property.
6631 * @param {Object} obj The scope object. For configuration handlers,
6632 * this will usually equal the owner.
6634 configModal: function (type, args, obj) {
6636 var modal = args[0];
6638 if (!this._hasModalityEventListeners) {
6640 this.subscribe("beforeShow", this.buildMask);
6641 this.subscribe("beforeShow", this.bringToTop);
6642 this.subscribe("beforeShow", this.showMask);
6643 this.subscribe("hide", this.hideMask);
6645 Overlay.windowResizeEvent.subscribe(this.sizeMask,
6648 this._hasModalityEventListeners = true;
6651 if (this._hasModalityEventListeners) {
6653 if (this.cfg.getProperty("visible")) {
6658 this.unsubscribe("beforeShow", this.buildMask);
6659 this.unsubscribe("beforeShow", this.bringToTop);
6660 this.unsubscribe("beforeShow", this.showMask);
6661 this.unsubscribe("hide", this.hideMask);
6663 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6665 this._hasModalityEventListeners = false;
6671 * Removes the modality mask.
6672 * @method removeMask
6674 removeMask: function () {
6676 var oMask = this.mask,
6681 Hide the mask before destroying it to ensure that DOM
6682 event handlers on focusable elements get removed.
6686 oParentNode = oMask.parentNode;
6688 oParentNode.removeChild(oMask);
6696 * The default event handler fired when the "keylisteners" property
6698 * @method configKeyListeners
6699 * @param {String} type The CustomEvent type (usually the property name)
6700 * @param {Object[]} args The CustomEvent arguments. For configuration
6701 * handlers, args[0] will equal the newly applied value for the property.
6702 * @param {Object} obj The scope object. For configuration handlers,
6703 * this will usually equal the owner.
6705 configKeyListeners: function (type, args, obj) {
6707 var listeners = args[0],
6714 if (listeners instanceof Array) {
6716 nListeners = listeners.length;
6718 for (i = 0; i < nListeners; i++) {
6720 listener = listeners[i];
6722 if (!Config.alreadySubscribed(this.showEvent,
6723 listener.enable, listener)) {
6725 this.showEvent.subscribe(listener.enable,
6730 if (!Config.alreadySubscribed(this.hideEvent,
6731 listener.disable, listener)) {
6733 this.hideEvent.subscribe(listener.disable,
6736 this.destroyEvent.subscribe(listener.disable,
6743 if (!Config.alreadySubscribed(this.showEvent,
6744 listeners.enable, listeners)) {
6746 this.showEvent.subscribe(listeners.enable,
6750 if (!Config.alreadySubscribed(this.hideEvent,
6751 listeners.disable, listeners)) {
6753 this.hideEvent.subscribe(listeners.disable,
6756 this.destroyEvent.subscribe(listeners.disable,
6768 * The default handler for the "strings" property
6769 * @method configStrings
6771 configStrings : function(type, args, obj) {
6772 var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
6773 this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
6777 * The default event handler fired when the "height" property is changed.
6778 * @method configHeight
6779 * @param {String} type The CustomEvent type (usually the property name)
6780 * @param {Object[]} args The CustomEvent arguments. For configuration
6781 * handlers, args[0] will equal the newly applied value for the property.
6782 * @param {Object} obj The scope object. For configuration handlers,
6783 * this will usually equal the owner.
6785 configHeight: function (type, args, obj) {
6786 var height = args[0],
6787 el = this.innerElement;
6789 Dom.setStyle(el, "height", height);
6790 this.cfg.refireEvent("iframe");
6794 * The default custom event handler executed when the Panel's height is changed,
6795 * if the autofillheight property has been set.
6797 * @method _autoFillOnHeightChange
6799 * @param {String} type The event type
6800 * @param {Array} args The array of arguments passed to event subscribers
6801 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
6802 * out the containers height
6804 _autoFillOnHeightChange : function(type, args, el) {
6805 Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
6808 setTimeout(function() {
6809 panel.sizeUnderlay();
6815 * The default event handler fired when the "width" property is changed.
6816 * @method configWidth
6817 * @param {String} type The CustomEvent type (usually the property name)
6818 * @param {Object[]} args The CustomEvent arguments. For configuration
6819 * handlers, args[0] will equal the newly applied value for the property.
6820 * @param {Object} obj The scope object. For configuration handlers,
6821 * this will usually equal the owner.
6823 configWidth: function (type, args, obj) {
6825 var width = args[0],
6826 el = this.innerElement;
6828 Dom.setStyle(el, "width", width);
6829 this.cfg.refireEvent("iframe");
6834 * The default event handler fired when the "zIndex" property is changed.
6835 * @method configzIndex
6836 * @param {String} type The CustomEvent type (usually the property name)
6837 * @param {Object[]} args The CustomEvent arguments. For configuration
6838 * handlers, args[0] will equal the newly applied value for the property.
6839 * @param {Object} obj The scope object. For configuration handlers,
6840 * this will usually equal the owner.
6842 configzIndex: function (type, args, obj) {
6843 Panel.superclass.configzIndex.call(this, type, args, obj);
6845 if (this.mask || this.cfg.getProperty("modal") === true) {
6846 var panelZ = Dom.getStyle(this.element, "zIndex");
6847 if (!panelZ || isNaN(panelZ)) {
6852 // Recursive call to configzindex (which should be stopped
6853 // from going further because panelZ should no longer === 0)
6854 this.cfg.setProperty("zIndex", 1);
6861 // END BUILT-IN PROPERTY EVENT HANDLERS //
6863 * Builds the wrapping container around the Panel that is used for
6864 * positioning the shadow and matte underlays. The container element is
6865 * assigned to a local instance variable called container, and the
6866 * element is reinserted inside of it.
6867 * @method buildWrapper
6869 buildWrapper: function () {
6871 var elementParent = this.element.parentNode,
6872 originalElement = this.element,
6873 wrapper = document.createElement("div");
6875 wrapper.className = Panel.CSS_PANEL_CONTAINER;
6876 wrapper.id = originalElement.id + "_c";
6878 if (elementParent) {
6879 elementParent.insertBefore(wrapper, originalElement);
6882 wrapper.appendChild(originalElement);
6884 this.element = wrapper;
6885 this.innerElement = originalElement;
6887 Dom.setStyle(this.innerElement, "visibility", "inherit");
6891 * Adjusts the size of the shadow based on the size of the element.
6892 * @method sizeUnderlay
6894 sizeUnderlay: function () {
6895 var oUnderlay = this.underlay,
6899 oElement = this.element;
6900 oUnderlay.style.width = oElement.offsetWidth + "px";
6901 oUnderlay.style.height = oElement.offsetHeight + "px";
6906 * Registers the Panel's header for drag & drop capability.
6907 * @method registerDragDrop
6909 registerDragDrop: function () {
6919 var bDragOnly = (this.cfg.getProperty("dragonly") === true);
6922 * The YAHOO.util.DD instance, used to implement the draggable header for the panel if draggable is enabled
6925 * @type YAHOO.util.DD
6927 this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
6929 if (!this.header.id) {
6930 this.header.id = this.id + "_h";
6933 this.dd.startDrag = function () {
6942 if (YAHOO.env.ua.ie == 6) {
6943 Dom.addClass(me.element,"drag");
6946 if (me.cfg.getProperty("constraintoviewport")) {
6948 var nViewportOffset = Overlay.VIEWPORT_OFFSET;
6950 offsetHeight = me.element.offsetHeight;
6951 offsetWidth = me.element.offsetWidth;
6953 viewPortWidth = Dom.getViewportWidth();
6954 viewPortHeight = Dom.getViewportHeight();
6956 scrollX = Dom.getDocumentScrollLeft();
6957 scrollY = Dom.getDocumentScrollTop();
6959 if (offsetHeight + nViewportOffset < viewPortHeight) {
6960 this.minY = scrollY + nViewportOffset;
6961 this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
6963 this.minY = scrollY + nViewportOffset;
6964 this.maxY = scrollY + nViewportOffset;
6967 if (offsetWidth + nViewportOffset < viewPortWidth) {
6968 this.minX = scrollX + nViewportOffset;
6969 this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
6971 this.minX = scrollX + nViewportOffset;
6972 this.maxX = scrollX + nViewportOffset;
6975 this.constrainX = true;
6976 this.constrainY = true;
6978 this.constrainX = false;
6979 this.constrainY = false;
6982 me.dragEvent.fire("startDrag", arguments);
6985 this.dd.onDrag = function () {
6987 me.cfg.refireEvent("iframe");
6988 if (this.platform == "mac" && YAHOO.env.ua.gecko) {
6989 this.showMacGeckoScrollbars();
6992 me.dragEvent.fire("onDrag", arguments);
6995 this.dd.endDrag = function () {
6997 if (YAHOO.env.ua.ie == 6) {
6998 Dom.removeClass(me.element,"drag");
7001 me.dragEvent.fire("endDrag", arguments);
7002 me.moveEvent.fire(me.cfg.getProperty("xy"));
7006 this.dd.setHandleElId(this.header.id);
7007 this.dd.addInvalidHandleType("INPUT");
7008 this.dd.addInvalidHandleType("SELECT");
7009 this.dd.addInvalidHandleType("TEXTAREA");
7014 * Builds the mask that is laid over the document when the Panel is
7015 * configured to be modal.
7018 buildMask: function () {
7019 var oMask = this.mask;
7021 if (!m_oMaskTemplate) {
7022 m_oMaskTemplate = document.createElement("div");
7023 m_oMaskTemplate.className = "mask";
7024 m_oMaskTemplate.innerHTML = " ";
7026 oMask = m_oMaskTemplate.cloneNode(true);
7027 oMask.id = this.id + "_mask";
7029 document.body.insertBefore(oMask, document.body.firstChild);
7033 if (YAHOO.env.ua.gecko && this.platform == "mac") {
7034 Dom.addClass(this.mask, "block-scrollbars");
7037 // Stack mask based on the element zindex
7043 * Hides the modality mask.
7046 hideMask: function () {
7047 if (this.cfg.getProperty("modal") && this.mask && this.beforeHideMaskEvent.fire()) {
7048 this.mask.style.display = "none";
7049 Dom.removeClass(document.body, "masked");
7050 this.hideMaskEvent.fire();
7055 * Shows the modality mask.
7058 showMask: function () {
7059 if (this.cfg.getProperty("modal") && this.mask && this.beforeShowMaskEvent.fire()) {
7060 Dom.addClass(document.body, "masked");
7062 this.mask.style.display = "block";
7063 this.showMaskEvent.fire();
7068 * Sets the size of the modality mask to cover the entire scrollable
7069 * area of the document
7072 sizeMask: function () {
7075 // Shrink mask first, so it doesn't affect the document size.
7076 var mask = this.mask,
7077 viewWidth = Dom.getViewportWidth(),
7078 viewHeight = Dom.getViewportHeight();
7080 if (mask.offsetHeight > viewHeight) {
7081 mask.style.height = viewHeight + "px";
7084 if (mask.offsetWidth > viewWidth) {
7085 mask.style.width = viewWidth + "px";
7088 // Then size it to the document
7089 mask.style.height = Dom.getDocumentHeight() + "px";
7090 mask.style.width = Dom.getDocumentWidth() + "px";
7095 * Sets the zindex of the mask, if it exists, based on the zindex of
7096 * the Panel element. The zindex of the mask is set to be one less
7097 * than the Panel element's zindex.
7099 * <p>NOTE: This method will not bump up the zindex of the Panel
7100 * to ensure that the mask has a non-negative zindex. If you require the
7101 * mask zindex to be 0 or higher, the zindex of the Panel
7102 * should be set to a value higher than 0, before this method is called.
7106 stackMask: function() {
7108 var panelZ = Dom.getStyle(this.element, "zIndex");
7109 if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
7110 Dom.setStyle(this.mask, "zIndex", panelZ - 1);
7116 * Renders the Panel by inserting the elements that are not already in
7117 * the main Panel into their correct places. Optionally appends the
7118 * Panel to the specified node prior to the render's execution. NOTE:
7119 * For Panels without existing markup, the appendToNode argument is
7120 * REQUIRED. If this argument is ommitted and the current element is
7121 * not present in the document, the function will return false,
7122 * indicating that the render was a failure.
7124 * @param {String} appendToNode The element id to which the Module
7125 * should be appended to prior to rendering <em>OR</em>
7126 * @param {HTMLElement} appendToNode The element to which the Module
7127 * should be appended to prior to rendering
7128 * @return {boolean} Success or failure of the render
7130 render: function (appendToNode) {
7131 return Panel.superclass.render.call(this, appendToNode, this.innerElement);
7135 * Renders the currently set header into it's proper position under the
7136 * module element. If the module element is not provided, "this.innerElement"
7139 * @method _renderHeader
7141 * @param {HTMLElement} moduleElement Optional. A reference to the module element
7143 _renderHeader: function(moduleElement){
7144 moduleElement = moduleElement || this.innerElement;
7145 Panel.superclass._renderHeader.call(this, moduleElement);
7149 * Renders the currently set body into it's proper position under the
7150 * module element. If the module element is not provided, "this.innerElement"
7153 * @method _renderBody
7155 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
7157 _renderBody: function(moduleElement){
7158 moduleElement = moduleElement || this.innerElement;
7159 Panel.superclass._renderBody.call(this, moduleElement);
7163 * Renders the currently set footer into it's proper position under the
7164 * module element. If the module element is not provided, "this.innerElement"
7167 * @method _renderFooter
7169 * @param {HTMLElement} moduleElement Optional. A reference to the module element
7171 _renderFooter: function(moduleElement){
7172 moduleElement = moduleElement || this.innerElement;
7173 Panel.superclass._renderFooter.call(this, moduleElement);
7177 * Removes the Panel element from the DOM and sets all child elements
7180 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
7181 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
7183 destroy: function (shallowPurge) {
7184 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
7187 Event.purgeElement(this.close);
7189 Panel.superclass.destroy.call(this, shallowPurge);
7193 * Forces the underlay element to be repainted through the application/removal
7194 * of a yui-force-redraw class to the underlay element.
7196 * @method forceUnderlayRedraw
7198 forceUnderlayRedraw : function () {
7199 var u = this.underlay;
7200 Dom.addClass(u, "yui-force-redraw");
7201 setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
7205 * Returns a String representation of the object.
7207 * @return {String} The string representation of the Panel.
7209 toString: function () {
7210 return "Panel " + this.id;
7220 * Dialog is an implementation of Panel that can be used to submit form
7224 * Built-in functionality for buttons with event handlers is included.
7225 * If the optional YUI Button dependancy is included on the page, the buttons
7226 * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
7230 * Forms can be processed in 3 ways -- via an asynchronous Connection utility call,
7231 * a simple form POST or GET, or manually. The YUI Connection utility should be
7232 * included if you're using the default "async" postmethod, but is not required if
7233 * you're using any of the other postmethod values.
7235 * @namespace YAHOO.widget
7237 * @extends YAHOO.widget.Panel
7239 * @param {String} el The element ID representing the Dialog <em>OR</em>
7240 * @param {HTMLElement} el The element representing the Dialog
7241 * @param {Object} userConfig The configuration object literal containing
7242 * the configuration that should be set for this Dialog. See configuration
7243 * documentation for more details.
7245 YAHOO.widget.Dialog = function (el, userConfig) {
7246 YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
7249 var Event = YAHOO.util.Event,
7250 CustomEvent = YAHOO.util.CustomEvent,
7251 Dom = YAHOO.util.Dom,
7252 Dialog = YAHOO.widget.Dialog,
7256 * Constant representing the name of the Dialog's events
7257 * @property EVENT_TYPES
7263 "BEFORE_SUBMIT": "beforeSubmit",
7265 "MANUAL_SUBMIT": "manualSubmit",
7266 "ASYNC_SUBMIT": "asyncSubmit",
7267 "FORM_SUBMIT": "formSubmit",
7272 * Constant representing the Dialog's configuration properties
7273 * @property DEFAULT_CONFIG
7293 supercedes: ["visible"]
7296 "HIDEAFTERSUBMIT" : {
7297 key: "hideaftersubmit",
7304 * Constant representing the default CSS class used for a Dialog
7305 * @property YAHOO.widget.Dialog.CSS_DIALOG
7310 Dialog.CSS_DIALOG = "yui-dialog";
7312 function removeButtonEventHandlers() {
7314 var aButtons = this._aButtons,
7319 if (Lang.isArray(aButtons)) {
7320 nButtons = aButtons.length;
7325 oButton = aButtons[i];
7327 if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
7330 else if (oButton.tagName.toUpperCase() == "BUTTON") {
7331 Event.purgeElement(oButton);
7332 Event.purgeElement(oButton, false);
7340 YAHOO.extend(Dialog, YAHOO.widget.Panel, {
7344 * @description Object reference to the Dialog's
7345 * <code><form></code> element.
7347 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7348 * level-one-html.html#ID-40002357">HTMLFormElement</a>
7353 * Initializes the class's configurable properties which can be changed
7354 * using the Dialog's Config object (cfg).
7355 * @method initDefaultConfig
7357 initDefaultConfig: function () {
7358 Dialog.superclass.initDefaultConfig.call(this);
7361 * The internally maintained callback object for use with the
7362 * Connection utility. The format of the callback object is
7363 * similar to Connection Manager's callback object and is
7364 * simply passed through to Connection Manager when the async
7366 * @property callback
7372 * The function to execute upon success of the
7373 * Connection submission (when the form does not
7374 * contain a file input element).
7376 * @property callback.success
7382 * The function to execute upon failure of the
7383 * Connection submission
7384 * @property callback.failure
7391 * The function to execute upon success of the
7392 * Connection submission, when the form contains
7393 * a file input element.
7396 * <em>NOTE:</em> Connection manager will not
7397 * invoke the success or failure handlers for the file
7398 * upload use case. This will be the only callback
7402 * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
7403 * Connection Manager documenation on file uploads</a>.
7405 * @property callback.upload
7410 * The arbitrary argument or arguments to pass to the Connection
7411 * callback functions
7412 * @property callback.argument
7419 // Add form dialog config properties //
7421 * The method to use for posting the Dialog's form. Possible values
7422 * are "async", "form", and "manual".
7423 * @config postmethod
7427 this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
7428 handler: this.configPostMethod,
7429 value: DEFAULT_CONFIG.POST_METHOD.value,
7430 validator: function (val) {
7431 if (val != "form" && val != "async" && val != "none" &&
7441 * Any additional post data which needs to be sent when using the
7442 * <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
7443 * The format for the post data string is defined by Connection Manager's
7444 * <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a>
7450 this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
7451 value: DEFAULT_CONFIG.POST_DATA.value
7455 * This property is used to configure whether or not the
7456 * dialog should be automatically hidden after submit.
7458 * @config hideaftersubmit
7462 this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
7463 value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
7467 * Array of object literals, each containing a set of properties
7468 * defining a button to be appended into the Dialog's footer.
7470 * <p>Each button object in the buttons array can have three properties:</p>
7474 * The text that will display on the face of the button. The text can
7475 * include HTML, as long as it is compliant with HTML Button specifications. The text is added to the DOM as HTML,
7476 * and should be escaped by the implementor if coming from an external source.
7479 * <dd>Can be either:
7481 * <li>A reference to a function that should fire when the
7482 * button is clicked. (In this case scope of this function is
7483 * always its Dialog instance.)</li>
7485 * <li>An object literal representing the code to be
7486 * executed when the button is clicked.
7493 * <strong>fn:</strong> Function, //
7494 * The handler to call when the event fires.
7496 * <strong>obj:</strong> Object, //
7497 * An object to pass back to the handler.
7499 * <strong>scope:</strong> Object //
7500 * The object to use for the scope of the handler.
7507 * <dt>isDefault:</dt>
7509 * An optional boolean value that specifies that a button
7510 * should be highlighted and focused by default.
7514 * <em>NOTE:</em>If the YUI Button Widget is included on the page,
7515 * the buttons created will be instances of YAHOO.widget.Button.
7516 * Otherwise, HTML Buttons (<code><BUTTON></code>) will be
7520 * @type {Array|String}
7523 this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
7524 handler: this.configButtons,
7525 value: DEFAULT_CONFIG.BUTTONS.value,
7526 supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
7532 * Initializes the custom events for Dialog which are fired
7533 * automatically at appropriate times by the Dialog class.
7534 * @method initEvents
7536 initEvents: function () {
7537 Dialog.superclass.initEvents.call(this);
7539 var SIGNATURE = CustomEvent.LIST;
7542 * CustomEvent fired prior to submission
7543 * @event beforeSubmitEvent
7545 this.beforeSubmitEvent =
7546 this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
7547 this.beforeSubmitEvent.signature = SIGNATURE;
7550 * CustomEvent fired after submission
7551 * @event submitEvent
7553 this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
7554 this.submitEvent.signature = SIGNATURE;
7557 * CustomEvent fired for manual submission, before the generic submit event is fired
7558 * @event manualSubmitEvent
7560 this.manualSubmitEvent =
7561 this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
7562 this.manualSubmitEvent.signature = SIGNATURE;
7565 * CustomEvent fired after asynchronous submission, before the generic submit event is fired
7567 * @event asyncSubmitEvent
7568 * @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
7570 this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
7571 this.asyncSubmitEvent.signature = SIGNATURE;
7574 * CustomEvent fired after form-based submission, before the generic submit event is fired
7575 * @event formSubmitEvent
7577 this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
7578 this.formSubmitEvent.signature = SIGNATURE;
7581 * CustomEvent fired after cancel
7582 * @event cancelEvent
7584 this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
7585 this.cancelEvent.signature = SIGNATURE;
7590 * The Dialog initialization method, which is executed for Dialog and
7591 * all of its subclasses. This method is automatically called by the
7592 * constructor, and sets up all DOM references for pre-existing markup,
7593 * and creates required markup if it is not already present.
7596 * @param {String} el The element ID representing the Dialog <em>OR</em>
7597 * @param {HTMLElement} el The element representing the Dialog
7598 * @param {Object} userConfig The configuration object literal
7599 * containing the configuration that should be set for this Dialog.
7600 * See configuration documentation for more details.
7602 init: function (el, userConfig) {
7605 Note that we don't pass the user config in here yet because
7606 we only want it executed once, at the lowest subclass level
7609 Dialog.superclass.init.call(this, el/*, userConfig*/);
7611 this.beforeInitEvent.fire(Dialog);
7613 Dom.addClass(this.element, Dialog.CSS_DIALOG);
7615 this.cfg.setProperty("visible", false);
7618 this.cfg.applyConfig(userConfig, true);
7621 //this.showEvent.subscribe(this.focusFirst, this, true);
7622 this.beforeHideEvent.subscribe(this.blurButtons, this, true);
7624 this.subscribe("changeBody", this.registerForm);
7626 this.initEvent.fire(Dialog);
7630 * Submits the Dialog's form depending on the value of the
7631 * "postmethod" configuration property. <strong>Please note:
7632 * </strong> As of version 2.3 this method will automatically handle
7633 * asyncronous file uploads should the Dialog instance's form contain
7634 * <code><input type="file"></code> elements. If a Dialog
7635 * instance will be handling asyncronous file uploads, its
7636 * <code>callback</code> property will need to be setup with a
7637 * <code>upload</code> handler rather than the standard
7638 * <code>success</code> and, or <code>failure</code> handlers. For more
7639 * information, see the <a href="http://developer.yahoo.com/yui/
7640 * connection/#file">Connection Manager documenation on file uploads</a>.
7643 doSubmit: function () {
7645 var Connect = YAHOO.util.Connect,
7647 bUseFileUpload = false,
7648 bUseSecureFileUpload = false,
7654 switch (this.cfg.getProperty("postmethod")) {
7657 aElements = oForm.elements;
7658 nElements = aElements.length;
7660 if (nElements > 0) {
7663 if (aElements[i].type == "file") {
7664 bUseFileUpload = true;
7671 if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
7672 bUseSecureFileUpload = true;
7675 formAttrs = this._getFormAttributes(oForm);
7677 Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
7679 var postData = this.cfg.getProperty("postdata");
7680 var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
7682 this.asyncSubmitEvent.fire(c);
7688 this.formSubmitEvent.fire();
7693 this.manualSubmitEvent.fire();
7699 * Retrieves important attributes (currently method and action) from
7700 * the form element, accounting for any elements which may have the same name
7701 * as the attributes. Defaults to "POST" and "" for method and action respectively
7702 * if the attribute cannot be retrieved.
7704 * @method _getFormAttributes
7706 * @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
7707 * @return {Object} Object literal, with method and action String properties.
7709 _getFormAttributes : function(oForm){
7716 if (oForm.getAttributeNode) {
7717 var action = oForm.getAttributeNode("action");
7718 var method = oForm.getAttributeNode("method");
7721 attrs.action = action.value;
7725 attrs.method = method.value;
7729 attrs.action = oForm.getAttribute("action");
7730 attrs.method = oForm.getAttribute("method");
7734 attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
7735 attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
7741 * Prepares the Dialog's internal FORM object, creating one if one is
7742 * not currently present.
7743 * @method registerForm
7745 registerForm: function() {
7747 var form = this.element.getElementsByTagName("form")[0];
7750 if (this.form == form && Dom.isAncestor(this.element, this.form)) {
7753 Event.purgeElement(this.form);
7759 form = document.createElement("form");
7760 form.name = "frm_" + this.id;
7761 this.body.appendChild(form);
7766 Event.on(form, "submit", this._submitHandler, this, true);
7771 * Internal handler for the form submit event
7773 * @method _submitHandler
7775 * @param {DOMEvent} e The DOM Event object
7777 _submitHandler : function(e) {
7784 * Sets up a tab, shift-tab loop between the first and last elements
7785 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
7786 * instance properties, which are reset everytime this method is invoked.
7788 * @method setTabLoop
7789 * @param {HTMLElement} firstElement
7790 * @param {HTMLElement} lastElement
7793 setTabLoop : function(firstElement, lastElement) {
7795 firstElement = firstElement || this.firstButton;
7796 lastElement = lastElement || this.lastButton;
7798 Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
7802 * Protected internal method for setTabLoop, which can be used by
7803 * subclasses to jump in and modify the arguments passed in if required.
7805 * @method _setTabLoop
7806 * @param {HTMLElement} firstElement
7807 * @param {HTMLElement} lastElement
7810 _setTabLoop : function(firstElement, lastElement) {
7811 firstElement = firstElement || this.firstButton;
7812 lastElement = this.lastButton || lastElement;
7814 this.setTabLoop(firstElement, lastElement);
7818 * Configures instance properties, pointing to the
7819 * first and last focusable elements in the Dialog's form.
7821 * @method setFirstLastFocusable
7823 setFirstLastFocusable : function() {
7825 Dialog.superclass.setFirstLastFocusable.call(this);
7827 var i, l, el, elements = this.focusableElements;
7829 this.firstFormElement = null;
7830 this.lastFormElement = null;
7832 if (this.form && elements && elements.length > 0) {
7833 l = elements.length;
7835 for (i = 0; i < l; ++i) {
7837 if (this.form === el.form) {
7838 this.firstFormElement = el;
7843 for (i = l-1; i >= 0; --i) {
7845 if (this.form === el.form) {
7846 this.lastFormElement = el;
7853 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7855 * The default event handler fired when the "close" property is
7856 * changed. The method controls the appending or hiding of the close
7857 * icon at the top right of the Dialog.
7858 * @method configClose
7859 * @param {String} type The CustomEvent type (usually the property name)
7860 * @param {Object[]} args The CustomEvent arguments. For
7861 * configuration handlers, args[0] will equal the newly applied value
7863 * @param {Object} obj The scope object. For configuration handlers,
7864 * this will usually equal the owner.
7866 configClose: function (type, args, obj) {
7867 Dialog.superclass.configClose.apply(this, arguments);
7871 * Event handler for the close icon
7876 * @param {DOMEvent} e
7878 _doClose : function(e) {
7879 Event.preventDefault(e);
7884 * The default event handler for the "buttons" configuration property
7885 * @method configButtons
7886 * @param {String} type The CustomEvent type (usually the property name)
7887 * @param {Object[]} args The CustomEvent arguments. For configuration
7888 * handlers, args[0] will equal the newly applied value for the property.
7889 * @param {Object} obj The scope object. For configuration handlers,
7890 * this will usually equal the owner.
7892 configButtons: function (type, args, obj) {
7894 var Button = YAHOO.widget.Button,
7896 oInnerElement = this.innerElement,
7905 removeButtonEventHandlers.call(this);
7907 this._aButtons = null;
7909 if (Lang.isArray(aButtons)) {
7911 oSpan = document.createElement("span");
7912 oSpan.className = "button-group";
7913 nButtons = aButtons.length;
7915 this._aButtons = [];
7916 this.defaultHtmlButton = null;
7918 for (i = 0; i < nButtons; i++) {
7919 oButton = aButtons[i];
7922 oYUIButton = new Button({ label: oButton.text, type:oButton.type });
7923 oYUIButton.appendTo(oSpan);
7925 oButtonEl = oYUIButton.get("element");
7927 if (oButton.isDefault) {
7928 oYUIButton.addClass("default");
7929 this.defaultHtmlButton = oButtonEl;
7932 if (Lang.isFunction(oButton.handler)) {
7934 oYUIButton.set("onclick", {
7935 fn: oButton.handler,
7940 } else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
7942 oYUIButton.set("onclick", {
7943 fn: oButton.handler.fn,
7944 obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7945 scope: (oButton.handler.scope || this)
7950 this._aButtons[this._aButtons.length] = oYUIButton;
7954 oButtonEl = document.createElement("button");
7955 oButtonEl.setAttribute("type", "button");
7957 if (oButton.isDefault) {
7958 oButtonEl.className = "default";
7959 this.defaultHtmlButton = oButtonEl;
7962 oButtonEl.innerHTML = oButton.text;
7964 if (Lang.isFunction(oButton.handler)) {
7965 Event.on(oButtonEl, "click", oButton.handler, this, true);
7966 } else if (Lang.isObject(oButton.handler) &&
7967 Lang.isFunction(oButton.handler.fn)) {
7969 Event.on(oButtonEl, "click",
7971 ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7972 (oButton.handler.scope || this));
7975 oSpan.appendChild(oButtonEl);
7976 this._aButtons[this._aButtons.length] = oButtonEl;
7979 oButton.htmlButton = oButtonEl;
7982 this.firstButton = oButtonEl;
7985 if (i == (nButtons - 1)) {
7986 this.lastButton = oButtonEl;
7990 this.setFooter(oSpan);
7992 oFooter = this.footer;
7994 if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
7995 oInnerElement.appendChild(oFooter);
7998 this.buttonSpan = oSpan;
8000 } else { // Do cleanup
8001 oSpan = this.buttonSpan;
8002 oFooter = this.footer;
8003 if (oSpan && oFooter) {
8004 oFooter.removeChild(oSpan);
8005 this.buttonSpan = null;
8006 this.firstButton = null;
8007 this.lastButton = null;
8008 this.defaultHtmlButton = null;
8012 this.changeContentEvent.fire();
8016 * @method getButtons
8017 * @description Returns an array containing each of the Dialog's
8018 * buttons, by default an array of HTML <code><BUTTON></code>
8019 * elements. If the Dialog's buttons were created using the
8020 * YAHOO.widget.Button class (via the inclusion of the optional Button
8021 * dependency on the page), an array of YAHOO.widget.Button instances
8025 getButtons: function () {
8026 return this._aButtons || null;
8031 * Sets focus to the first focusable element in the Dialog's form if found,
8032 * else, the default button if found, else the first button defined via the
8033 * "buttons" configuration property.
8036 * This method is invoked when the Dialog is made visible.
8038 * @method focusFirst
8039 * @return {Boolean} true, if focused. false if not
8041 focusFirst: function (type, args, obj) {
8043 var el = this.firstFormElement,
8046 if (args && args[1]) {
8047 Event.stopEvent(args[1]);
8049 // When tabbing here, use firstElement instead of firstFormElement
8050 if (args[0] === 9 && this.firstElement) {
8051 el = this.firstElement;
8059 } catch(oException) {
8063 if (this.defaultHtmlButton) {
8064 focused = this.focusDefaultButton();
8066 focused = this.focusFirstButton();
8073 * Sets focus to the last element in the Dialog's form or the last
8074 * button defined via the "buttons" configuration property.
8076 * @return {Boolean} true, if focused. false if not
8078 focusLast: function (type, args, obj) {
8080 var aButtons = this.cfg.getProperty("buttons"),
8081 el = this.lastFormElement,
8084 if (args && args[1]) {
8085 Event.stopEvent(args[1]);
8087 // When tabbing here, use lastElement instead of lastFormElement
8088 if (args[0] === 9 && this.lastElement) {
8089 el = this.lastElement;
8093 if (aButtons && Lang.isArray(aButtons)) {
8094 focused = this.focusLastButton();
8100 } catch(oException) {
8110 * Helper method to normalize button references. It either returns the
8111 * YUI Button instance for the given element if found,
8112 * or the passes back the HTMLElement reference if a corresponding YUI Button
8113 * reference is not found or YAHOO.widget.Button does not exist on the page.
8115 * @method _getButton
8117 * @param {HTMLElement} button
8118 * @return {YAHOO.widget.Button|HTMLElement}
8120 _getButton : function(button) {
8121 var Button = YAHOO.widget.Button;
8123 // If we have an HTML button and YUI Button is on the page,
8124 // get the YUI Button reference if available.
8125 if (Button && button && button.nodeName && button.id) {
8126 button = Button.getButton(button.id) || button;
8133 * Sets the focus to the button that is designated as the default via
8134 * the "buttons" configuration property. By default, this method is
8135 * called when the Dialog is made visible.
8136 * @method focusDefaultButton
8137 * @return {Boolean} true if focused, false if not
8139 focusDefaultButton: function () {
8140 var button = this._getButton(this.defaultHtmlButton),
8145 Place the call to the "focus" method inside a try/catch
8146 block to prevent IE from throwing JavaScript errors if
8147 the element is disabled or hidden.
8152 } catch(oException) {
8159 * Blurs all the buttons defined via the "buttons"
8160 * configuration property.
8161 * @method blurButtons
8163 blurButtons: function () {
8165 var aButtons = this.cfg.getProperty("buttons"),
8171 if (aButtons && Lang.isArray(aButtons)) {
8172 nButtons = aButtons.length;
8176 oButton = aButtons[i];
8178 oElement = this._getButton(oButton.htmlButton);
8181 Place the call to the "blur" method inside
8182 a try/catch block to prevent IE from
8183 throwing JavaScript errors if the element
8184 is disabled or hidden.
8188 } catch(oException) {
8199 * Sets the focus to the first button created via the "buttons"
8200 * configuration property.
8201 * @method focusFirstButton
8202 * @return {Boolean} true, if focused. false if not
8204 focusFirstButton: function () {
8206 var aButtons = this.cfg.getProperty("buttons"),
8211 if (aButtons && Lang.isArray(aButtons)) {
8212 oButton = aButtons[0];
8214 oElement = this._getButton(oButton.htmlButton);
8217 Place the call to the "focus" method inside a
8218 try/catch block to prevent IE from throwing
8219 JavaScript errors if the element is disabled
8225 } catch(oException) {
8236 * Sets the focus to the last button created via the "buttons"
8237 * configuration property.
8238 * @method focusLastButton
8239 * @return {Boolean} true, if focused. false if not
8241 focusLastButton: function () {
8243 var aButtons = this.cfg.getProperty("buttons"),
8249 if (aButtons && Lang.isArray(aButtons)) {
8250 nButtons = aButtons.length;
8252 oButton = aButtons[(nButtons - 1)];
8255 oElement = this._getButton(oButton.htmlButton);
8258 Place the call to the "focus" method inside a
8259 try/catch block to prevent IE from throwing
8260 JavaScript errors if the element is disabled
8267 } catch(oException) {
8279 * The default event handler for the "postmethod" configuration property
8280 * @method configPostMethod
8281 * @param {String} type The CustomEvent type (usually the property name)
8282 * @param {Object[]} args The CustomEvent arguments. For
8283 * configuration handlers, args[0] will equal the newly applied value
8285 * @param {Object} obj The scope object. For configuration handlers,
8286 * this will usually equal the owner.
8288 configPostMethod: function (type, args, obj) {
8289 this.registerForm();
8292 // END BUILT-IN PROPERTY EVENT HANDLERS //
8295 * Built-in function hook for writing a validation function that will
8296 * be checked for a "true" value prior to a submit. This function, as
8297 * implemented by default, always returns true, so it should be
8298 * overridden if validation is necessary.
8301 validate: function () {
8306 * Executes a submit of the Dialog if validation
8307 * is successful. By default the Dialog is hidden
8308 * after submission, but you can set the "hideaftersubmit"
8309 * configuration property to false, to prevent the Dialog
8310 * from being hidden.
8314 submit: function () {
8315 if (this.validate()) {
8316 if (this.beforeSubmitEvent.fire()) {
8318 this.submitEvent.fire();
8320 if (this.cfg.getProperty("hideaftersubmit")) {
8334 * Executes the cancel of the Dialog followed by a hide.
8337 cancel: function () {
8338 this.cancelEvent.fire();
8343 * Returns a JSON-compatible data structure representing the data
8344 * currently contained in the form.
8346 * @return {Object} A JSON object reprsenting the data of the
8349 getData: function () {
8351 var oForm = this.form,
8370 function isFormElement(p_oElement) {
8371 var sTag = p_oElement.tagName.toUpperCase();
8372 return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
8373 sTag == "SELECT") && p_oElement.name == sName);
8378 aElements = oForm.elements;
8379 nTotalElements = aElements.length;
8382 for (i = 0; i < nTotalElements; i++) {
8383 sName = aElements[i].name;
8386 Using "Dom.getElementsBy" to safeguard user from JS
8387 errors that result from giving a form field (or set of
8388 fields) the same name as a native method of a form
8389 (like "submit") or a DOM collection (such as the "item"
8390 method). Originally tried accessing fields via the
8391 "namedItem" method of the "element" collection, but
8392 discovered that it won't return a collection of fields
8396 oElement = Dom.getElementsBy(isFormElement, "*", oForm);
8397 nElements = oElement.length;
8399 if (nElements > 0) {
8400 if (nElements == 1) {
8401 oElement = oElement[0];
8403 sType = oElement.type;
8404 sTagName = oElement.tagName.toUpperCase();
8408 if (sType == "checkbox") {
8409 oData[sName] = oElement.checked;
8410 } else if (sType != "radio") {
8411 oData[sName] = oElement.value;
8416 oData[sName] = oElement.value;
8420 aOptions = oElement.options;
8421 nOptions = aOptions.length;
8424 for (n = 0; n < nOptions; n++) {
8425 oOption = aOptions[n];
8426 if (oOption.selected) {
8427 valueAttr = oOption.attributes.value;
8428 aValues[aValues.length] = (valueAttr && valueAttr.specified) ? oOption.value : oOption.text;
8431 oData[sName] = aValues;
8436 sType = oElement[0].type;
8439 for (n = 0; n < nElements; n++) {
8440 oRadio = oElement[n];
8441 if (oRadio.checked) {
8442 oData[sName] = oRadio.value;
8450 for (n = 0; n < nElements; n++) {
8451 oCheckbox = oElement[n];
8452 if (oCheckbox.checked) {
8453 aValues[aValues.length] = oCheckbox.value;
8456 oData[sName] = aValues;
8468 * Removes the Panel element from the DOM and sets all child elements
8471 * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
8472 * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
8474 destroy: function (shallowPurge) {
8475 removeButtonEventHandlers.call(this);
8477 this._aButtons = null;
8479 var aForms = this.element.getElementsByTagName("form"),
8482 if (aForms.length > 0) {
8486 Event.purgeElement(oForm);
8487 if (oForm.parentNode) {
8488 oForm.parentNode.removeChild(oForm);
8493 Dialog.superclass.destroy.call(this, shallowPurge);
8497 * Returns a string representation of the object.
8499 * @return {String} The string representation of the Dialog
8501 toString: function () {
8502 return "Dialog " + this.id;
8511 * SimpleDialog is a simple implementation of Dialog that can be used to
8512 * submit a single value. Forms can be processed in 3 ways -- via an
8513 * asynchronous Connection utility call, a simple form POST or GET,
8515 * @namespace YAHOO.widget
8516 * @class SimpleDialog
8517 * @extends YAHOO.widget.Dialog
8519 * @param {String} el The element ID representing the SimpleDialog
8521 * @param {HTMLElement} el The element representing the SimpleDialog
8522 * @param {Object} userConfig The configuration object literal containing
8523 * the configuration that should be set for this SimpleDialog. See
8524 * configuration documentation for more details.
8526 YAHOO.widget.SimpleDialog = function (el, userConfig) {
8528 YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
8533 var Dom = YAHOO.util.Dom,
8534 SimpleDialog = YAHOO.widget.SimpleDialog,
8537 * Constant representing the SimpleDialog's configuration properties
8538 * @property DEFAULT_CONFIG
8554 suppressEvent: true,
8555 supercedes: ["icon"]
8561 * Constant for the standard network icon for a blocking action
8562 * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
8567 SimpleDialog.ICON_BLOCK = "blckicon";
8570 * Constant for the standard network icon for alarm
8571 * @property YAHOO.widget.SimpleDialog.ICON_ALARM
8576 SimpleDialog.ICON_ALARM = "alrticon";
8579 * Constant for the standard network icon for help
8580 * @property YAHOO.widget.SimpleDialog.ICON_HELP
8585 SimpleDialog.ICON_HELP = "hlpicon";
8588 * Constant for the standard network icon for info
8589 * @property YAHOO.widget.SimpleDialog.ICON_INFO
8594 SimpleDialog.ICON_INFO = "infoicon";
8597 * Constant for the standard network icon for warn
8598 * @property YAHOO.widget.SimpleDialog.ICON_WARN
8603 SimpleDialog.ICON_WARN = "warnicon";
8606 * Constant for the standard network icon for a tip
8607 * @property YAHOO.widget.SimpleDialog.ICON_TIP
8612 SimpleDialog.ICON_TIP = "tipicon";
8615 * Constant representing the name of the CSS class applied to the element
8616 * created by the "icon" configuration property.
8617 * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
8622 SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
8625 * Constant representing the default CSS class used for a SimpleDialog
8626 * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
8631 SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
8634 YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
8637 * Initializes the class's configurable properties which can be changed
8638 * using the SimpleDialog's Config object (cfg).
8639 * @method initDefaultConfig
8641 initDefaultConfig: function () {
8643 SimpleDialog.superclass.initDefaultConfig.call(this);
8645 // Add dialog config properties //
8648 * Sets the informational icon for the SimpleDialog
8653 this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
8654 handler: this.configIcon,
8655 value: DEFAULT_CONFIG.ICON.value,
8656 suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
8660 * Sets the text for the SimpleDialog. The text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
8665 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
8666 handler: this.configText,
8667 value: DEFAULT_CONFIG.TEXT.value,
8668 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
8669 supercedes: DEFAULT_CONFIG.TEXT.supercedes
8676 * The SimpleDialog initialization method, which is executed for
8677 * SimpleDialog and all of its subclasses. This method is automatically
8678 * called by the constructor, and sets up all DOM references for
8679 * pre-existing markup, and creates required markup if it is not
8682 * @param {String} el The element ID representing the SimpleDialog
8684 * @param {HTMLElement} el The element representing the SimpleDialog
8685 * @param {Object} userConfig The configuration object literal
8686 * containing the configuration that should be set for this
8687 * SimpleDialog. See configuration documentation for more details.
8689 init: function (el, userConfig) {
8692 Note that we don't pass the user config in here yet because we
8693 only want it executed once, at the lowest subclass level
8696 SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
8698 this.beforeInitEvent.fire(SimpleDialog);
8700 Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
8702 this.cfg.queueProperty("postmethod", "manual");
8705 this.cfg.applyConfig(userConfig, true);
8708 this.beforeRenderEvent.subscribe(function () {
8714 this.initEvent.fire(SimpleDialog);
8719 * Prepares the SimpleDialog's internal FORM object, creating one if one
8720 * is not currently present, and adding the value hidden field.
8721 * @method registerForm
8723 registerForm: function () {
8724 SimpleDialog.superclass.registerForm.call(this);
8726 var doc = this.form.ownerDocument,
8727 input = doc.createElement("input");
8729 input.type = "hidden";
8730 input.name = this.id;
8733 this.form.appendChild(input);
8736 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
8739 * Fired when the "icon" property is set.
8740 * @method configIcon
8741 * @param {String} type The CustomEvent type (usually the property name)
8742 * @param {Object[]} args The CustomEvent arguments. For configuration
8743 * handlers, args[0] will equal the newly applied value for the property.
8744 * @param {Object} obj The scope object. For configuration handlers,
8745 * this will usually equal the owner.
8747 configIcon: function (type,args,obj) {
8749 var sIcon = args[0],
8751 sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
8756 if (sIcon && sIcon != "none") {
8758 aElements = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
8760 if (aElements.length === 1) {
8762 oIcon = aElements[0];
8763 oIconParent = oIcon.parentNode;
8767 oIconParent.removeChild(oIcon);
8776 if (sIcon.indexOf(".") == -1) {
8778 oIcon = document.createElement("span");
8779 oIcon.className = (sCSSClass + " " + sIcon);
8780 oIcon.innerHTML = " ";
8784 oIcon = document.createElement("img");
8785 oIcon.src = (this.imageRoot + sIcon);
8786 oIcon.className = sCSSClass;
8793 oBody.insertBefore(oIcon, oBody.firstChild);
8802 * Fired when the "text" property is set.
8803 * @method configText
8804 * @param {String} type The CustomEvent type (usually the property name)
8805 * @param {Object[]} args The CustomEvent arguments. For configuration
8806 * handlers, args[0] will equal the newly applied value for the property.
8807 * @param {Object} obj The scope object. For configuration handlers,
8808 * this will usually equal the owner.
8810 configText: function (type,args,obj) {
8814 this.cfg.refireEvent("icon");
8818 // END BUILT-IN PROPERTY EVENT HANDLERS //
8821 * Returns a string representation of the object.
8823 * @return {String} The string representation of the SimpleDialog
8825 toString: function () {
8826 return "SimpleDialog " + this.id;
8831 * Sets the SimpleDialog's body content to the HTML specified.
8832 * If no body is present, one will be automatically created.
8833 * An empty string can be passed to the method to clear the contents of the body.
8835 * <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
8836 * and <a href="#config_icon">icon</a> configuration properties to set the contents
8837 * of it's body element in accordance with the UI design for a SimpleDialog (an
8838 * icon and message text). Calling setBody on the SimpleDialog will not enforce this
8839 * UI design constraint and will replace the entire contents of the SimpleDialog body.
8840 * It should only be used if you wish the replace the default icon/text body structure
8841 * of a SimpleDialog with your own custom markup.</p>
8844 * @param {HTML} bodyContent The HTML used to set the body.
8845 * As a convenience, non HTMLElement objects can also be passed into
8846 * the method, and will be treated as strings, with the body innerHTML
8847 * set to their default toString implementations.
8849 * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
8852 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
8854 * @param {DocumentFragment} bodyContent The document fragment
8855 * containing elements which are to be added to the body
8863 * ContainerEffect encapsulates animation transitions that are executed when
8864 * an Overlay is shown or hidden.
8865 * @namespace YAHOO.widget
8866 * @class ContainerEffect
8868 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
8869 * should be associated with
8870 * @param {Object} attrIn The object literal representing the animation
8871 * arguments to be used for the animate-in transition. The arguments for
8872 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8873 * duration(Number), and method(i.e. Easing.easeIn).
8874 * @param {Object} attrOut The object literal representing the animation
8875 * arguments to be used for the animate-out transition. The arguments for
8876 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8877 * duration(Number), and method(i.e. Easing.easeIn).
8878 * @param {HTMLElement} targetElement Optional. The target element that
8879 * should be animated during the transition. Defaults to overlay.element.
8880 * @param {class} Optional. The animation class to instantiate. Defaults to
8881 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
8883 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
8886 animClass = YAHOO.util.Anim;
8890 * The overlay to animate
8892 * @type YAHOO.widget.Overlay
8894 this.overlay = overlay;
8897 * The animation attributes to use when transitioning into view
8901 this.attrIn = attrIn;
8904 * The animation attributes to use when transitioning out of view
8908 this.attrOut = attrOut;
8911 * The target element to be animated
8912 * @property targetElement
8915 this.targetElement = targetElement || overlay.element;
8918 * The animation class to use for animating the overlay
8919 * @property animClass
8922 this.animClass = animClass;
8925 var Dom = YAHOO.util.Dom,
8926 CustomEvent = YAHOO.util.CustomEvent,
8927 ContainerEffect = YAHOO.widget.ContainerEffect;
8930 * A pre-configured ContainerEffect instance that can be used for fading
8931 * an overlay in and out.
8934 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8935 * @param {Number} dur The duration of the animation
8936 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8938 ContainerEffect.FADE = function (overlay, dur) {
8940 var Easing = YAHOO.util.Easing,
8942 attributes: {opacity:{from:0, to:1}},
8944 method: Easing.easeIn
8947 attributes: {opacity:{to:0}},
8949 method: Easing.easeOut
8951 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
8953 fade.handleUnderlayStart = function() {
8954 var underlay = this.overlay.underlay;
8955 if (underlay && YAHOO.env.ua.ie) {
8956 var hasFilters = (underlay.filters && underlay.filters.length > 0);
8958 Dom.addClass(overlay.element, "yui-effect-fade");
8963 fade.handleUnderlayComplete = function() {
8964 var underlay = this.overlay.underlay;
8965 if (underlay && YAHOO.env.ua.ie) {
8966 Dom.removeClass(overlay.element, "yui-effect-fade");
8970 fade.handleStartAnimateIn = function (type, args, obj) {
8971 obj.overlay._fadingIn = true;
8973 Dom.addClass(obj.overlay.element, "hide-select");
8975 if (!obj.overlay.underlay) {
8976 obj.overlay.cfg.refireEvent("underlay");
8979 obj.handleUnderlayStart();
8981 obj.overlay._setDomVisibility(true);
8982 Dom.setStyle(obj.overlay.element, "opacity", 0);
8985 fade.handleCompleteAnimateIn = function (type,args,obj) {
8986 obj.overlay._fadingIn = false;
8988 Dom.removeClass(obj.overlay.element, "hide-select");
8990 if (obj.overlay.element.style.filter) {
8991 obj.overlay.element.style.filter = null;
8994 obj.handleUnderlayComplete();
8996 obj.overlay.cfg.refireEvent("iframe");
8997 obj.animateInCompleteEvent.fire();
9000 fade.handleStartAnimateOut = function (type, args, obj) {
9001 obj.overlay._fadingOut = true;
9002 Dom.addClass(obj.overlay.element, "hide-select");
9003 obj.handleUnderlayStart();
9006 fade.handleCompleteAnimateOut = function (type, args, obj) {
9007 obj.overlay._fadingOut = false;
9008 Dom.removeClass(obj.overlay.element, "hide-select");
9010 if (obj.overlay.element.style.filter) {
9011 obj.overlay.element.style.filter = null;
9013 obj.overlay._setDomVisibility(false);
9014 Dom.setStyle(obj.overlay.element, "opacity", 1);
9016 obj.handleUnderlayComplete();
9018 obj.overlay.cfg.refireEvent("iframe");
9019 obj.animateOutCompleteEvent.fire();
9028 * A pre-configured ContainerEffect instance that can be used for sliding an
9029 * overlay in and out.
9032 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
9033 * @param {Number} dur The duration of the animation
9034 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
9036 ContainerEffect.SLIDE = function (overlay, dur) {
9037 var Easing = YAHOO.util.Easing,
9039 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
9040 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
9041 clientWidth = Dom.getClientWidth(),
9042 offsetWidth = overlay.element.offsetWidth,
9045 attributes: { points: { to: [x, y] } },
9047 method: Easing.easeIn
9051 attributes: { points: { to: [(clientWidth + 25), y] } },
9053 method: Easing.easeOut
9056 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
9058 slide.handleStartAnimateIn = function (type,args,obj) {
9059 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
9060 obj.overlay.element.style.top = y + "px";
9063 slide.handleTweenAnimateIn = function (type, args, obj) {
9065 var pos = Dom.getXY(obj.overlay.element),
9069 if (Dom.getStyle(obj.overlay.element, "visibility") ==
9070 "hidden" && currentX < x) {
9072 obj.overlay._setDomVisibility(true);
9076 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
9077 obj.overlay.cfg.refireEvent("iframe");
9080 slide.handleCompleteAnimateIn = function (type, args, obj) {
9081 obj.overlay.cfg.setProperty("xy", [x, y], true);
9084 obj.overlay.cfg.refireEvent("iframe");
9085 obj.animateInCompleteEvent.fire();
9088 slide.handleStartAnimateOut = function (type, args, obj) {
9090 var vw = Dom.getViewportWidth(),
9091 pos = Dom.getXY(obj.overlay.element),
9094 obj.animOut.attributes.points.to = [(vw + 25), yso];
9097 slide.handleTweenAnimateOut = function (type, args, obj) {
9099 var pos = Dom.getXY(obj.overlay.element),
9103 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
9104 obj.overlay.cfg.refireEvent("iframe");
9107 slide.handleCompleteAnimateOut = function (type, args, obj) {
9108 obj.overlay._setDomVisibility(false);
9110 obj.overlay.cfg.setProperty("xy", [x, y]);
9111 obj.animateOutCompleteEvent.fire();
9118 ContainerEffect.prototype = {
9121 * Initializes the animation classes and events.
9126 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
9127 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
9129 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
9130 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
9132 this.animateInCompleteEvent = this.createEvent("animateInComplete");
9133 this.animateInCompleteEvent.signature = CustomEvent.LIST;
9135 this.animateOutCompleteEvent = this.createEvent("animateOutComplete");
9136 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
9138 this.animIn = new this.animClass(
9140 this.attrIn.attributes,
9141 this.attrIn.duration,
9142 this.attrIn.method);
9144 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
9145 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
9146 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);
9148 this.animOut = new this.animClass(
9150 this.attrOut.attributes,
9151 this.attrOut.duration,
9152 this.attrOut.method);
9154 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
9155 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
9156 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, this);
9161 * Triggers the in-animation.
9164 animateIn: function () {
9165 this._stopAnims(this.lastFrameOnStop);
9166 this.beforeAnimateInEvent.fire();
9167 this.animIn.animate();
9171 * Triggers the out-animation.
9172 * @method animateOut
9174 animateOut: function () {
9175 this._stopAnims(this.lastFrameOnStop);
9176 this.beforeAnimateOutEvent.fire();
9177 this.animOut.animate();
9181 * Flag to define whether Anim should jump to the last frame,
9182 * when animateIn or animateOut is stopped.
9184 * @property lastFrameOnStop
9188 lastFrameOnStop : true,
9191 * Stops both animIn and animOut instances, if in progress.
9193 * @method _stopAnims
9194 * @param {boolean} finish If true, animation will jump to final frame.
9197 _stopAnims : function(finish) {
9198 if (this.animOut && this.animOut.isAnimated()) {
9199 this.animOut.stop(finish);
9202 if (this.animIn && this.animIn.isAnimated()) {
9203 this.animIn.stop(finish);
9208 * The default onStart handler for the in-animation.
9209 * @method handleStartAnimateIn
9210 * @param {String} type The CustomEvent type
9211 * @param {Object[]} args The CustomEvent arguments
9212 * @param {Object} obj The scope object
9214 handleStartAnimateIn: function (type, args, obj) { },
9217 * The default onTween handler for the in-animation.
9218 * @method handleTweenAnimateIn
9219 * @param {String} type The CustomEvent type
9220 * @param {Object[]} args The CustomEvent arguments
9221 * @param {Object} obj The scope object
9223 handleTweenAnimateIn: function (type, args, obj) { },
9226 * The default onComplete handler for the in-animation.
9227 * @method handleCompleteAnimateIn
9228 * @param {String} type The CustomEvent type
9229 * @param {Object[]} args The CustomEvent arguments
9230 * @param {Object} obj The scope object
9232 handleCompleteAnimateIn: function (type, args, obj) { },
9235 * The default onStart handler for the out-animation.
9236 * @method handleStartAnimateOut
9237 * @param {String} type The CustomEvent type
9238 * @param {Object[]} args The CustomEvent arguments
9239 * @param {Object} obj The scope object
9241 handleStartAnimateOut: function (type, args, obj) { },
9244 * The default onTween handler for the out-animation.
9245 * @method handleTweenAnimateOut
9246 * @param {String} type The CustomEvent type
9247 * @param {Object[]} args The CustomEvent arguments
9248 * @param {Object} obj The scope object
9250 handleTweenAnimateOut: function (type, args, obj) { },
9253 * The default onComplete handler for the out-animation.
9254 * @method handleCompleteAnimateOut
9255 * @param {String} type The CustomEvent type
9256 * @param {Object[]} args The CustomEvent arguments
9257 * @param {Object} obj The scope object
9259 handleCompleteAnimateOut: function (type, args, obj) { },
9262 * Returns a string representation of the object.
9264 * @return {String} The string representation of the ContainerEffect
9266 toString: function () {
9267 var output = "ContainerEffect";
9269 output += " [" + this.overlay.toString() + "]";
9275 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
9278 YAHOO.register("container", YAHOO.widget.Module, {version: "2.9.0", build: "2800"});