2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
10 * Config is a utility used within an Object to allow the implementer to
11 * maintain a list of local configuration properties and listen for changes
12 * to those properties dynamically using CustomEvent. The initial values are
13 * also maintained so that the configuration can be reset at any given point
14 * to its initial state.
15 * @namespace YAHOO.util
18 * @param {Object} owner The owner Object to which this Config Object belongs
20 YAHOO.util.Config = function (owner) {
30 var Lang = YAHOO.lang,
31 CustomEvent = YAHOO.util.CustomEvent,
32 Config = YAHOO.util.Config;
36 * Constant representing the CustomEvent type for the config changed event.
37 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
42 Config.CONFIG_CHANGED_EVENT = "configChanged";
45 * Constant representing the boolean type string
46 * @property YAHOO.util.Config.BOOLEAN_TYPE
51 Config.BOOLEAN_TYPE = "boolean";
56 * Object reference to the owner of this Config Object
63 * Boolean flag that specifies whether a queue is currently
65 * @property queueInProgress
68 queueInProgress: false,
71 * Maintains the local collection of configuration property objects and
72 * their specified values
80 * Maintains the local collection of configuration property objects as
81 * they were initially applied.
82 * This object is used when resetting a property.
83 * @property initialConfig
90 * Maintains the local, normalized CustomEvent queue
91 * @property eventQueue
98 * Custom Event, notifying subscribers when Config properties are set
99 * (setProperty is called without the silent flag
100 * @event configChangedEvent
102 configChangedEvent: null,
105 * Initializes the configuration Object and all of its local members.
107 * @param {Object} owner The owner Object to which this Config
110 init: function (owner) {
114 this.configChangedEvent =
115 this.createEvent(Config.CONFIG_CHANGED_EVENT);
117 this.configChangedEvent.signature = CustomEvent.LIST;
118 this.queueInProgress = false;
120 this.initialConfig = {};
121 this.eventQueue = [];
126 * Validates that the value passed in is a Boolean.
127 * @method checkBoolean
128 * @param {Object} val The value to validate
129 * @return {Boolean} true, if the value is valid
131 checkBoolean: function (val) {
132 return (typeof val == Config.BOOLEAN_TYPE);
136 * Validates that the value passed in is a number.
137 * @method checkNumber
138 * @param {Object} val The value to validate
139 * @return {Boolean} true, if the value is valid
141 checkNumber: function (val) {
142 return (!isNaN(val));
146 * Fires a configuration property event using the specified value.
149 * @param {String} key The configuration property's name
150 * @param {value} Object The value of the correct type for the property
152 fireEvent: function ( key, value ) {
153 var property = this.config[key];
155 if (property && property.event) {
156 property.event.fire(value);
161 * Adds a property to the Config Object's private config hash.
162 * @method addProperty
163 * @param {String} key The configuration property's name
164 * @param {Object} propertyObject The Object containing all of this
165 * property's arguments
167 addProperty: function ( key, propertyObject ) {
168 key = key.toLowerCase();
170 this.config[key] = propertyObject;
172 propertyObject.event = this.createEvent(key, { scope: this.owner });
173 propertyObject.event.signature = CustomEvent.LIST;
176 propertyObject.key = key;
178 if (propertyObject.handler) {
179 propertyObject.event.subscribe(propertyObject.handler,
183 this.setProperty(key, propertyObject.value, true);
185 if (! propertyObject.suppressEvent) {
186 this.queueProperty(key, propertyObject.value);
192 * Returns a key-value configuration map of the values currently set in
195 * @return {Object} The current config, represented in a key-value map
197 getConfig: function () {
200 currCfg = this.config,
204 for (prop in currCfg) {
205 if (Lang.hasOwnProperty(currCfg, prop)) {
206 property = currCfg[prop];
207 if (property && property.event) {
208 cfg[prop] = property.value;
217 * Returns the value of specified property.
218 * @method getProperty
219 * @param {String} key The name of the property
220 * @return {Object} The value of the specified property
222 getProperty: function (key) {
223 var property = this.config[key.toLowerCase()];
224 if (property && property.event) {
225 return property.value;
232 * Resets the specified property's value to its initial value.
233 * @method resetProperty
234 * @param {String} key The name of the property
235 * @return {Boolean} True is the property was reset, false if not
237 resetProperty: function (key) {
239 key = key.toLowerCase();
241 var property = this.config[key];
243 if (property && property.event) {
245 if (this.initialConfig[key] &&
246 !Lang.isUndefined(this.initialConfig[key])) {
248 this.setProperty(key, this.initialConfig[key]);
262 * Sets the value of a property. If the silent property is passed as
263 * true, the property's event will not be fired.
264 * @method setProperty
265 * @param {String} key The name of the property
266 * @param {String} value The value to set the property to
267 * @param {Boolean} silent Whether the value should be set silently,
268 * without firing the property event.
269 * @return {Boolean} True, if the set was successful, false if it failed.
271 setProperty: function (key, value, silent) {
275 key = key.toLowerCase();
277 if (this.queueInProgress && ! silent) {
278 // Currently running through a queue...
279 this.queueProperty(key,value);
283 property = this.config[key];
284 if (property && property.event) {
285 if (property.validator && !property.validator(value)) {
288 property.value = value;
290 this.fireEvent(key, value);
291 this.configChangedEvent.fire([key, value]);
302 * Sets the value of a property and queues its event to execute. If the
303 * event is already scheduled to execute, it is
304 * moved from its current position to the end of the queue.
305 * @method queueProperty
306 * @param {String} key The name of the property
307 * @param {String} value The value to set the property to
308 * @return {Boolean} true, if the set was successful, false if
311 queueProperty: function (key, value) {
313 key = key.toLowerCase();
315 var property = this.config[key],
316 foundDuplicate = false,
331 if (property && property.event) {
333 if (!Lang.isUndefined(value) && property.validator &&
334 !property.validator(value)) { // validator
338 if (!Lang.isUndefined(value)) {
339 property.value = value;
341 value = property.value;
344 foundDuplicate = false;
345 iLen = this.eventQueue.length;
347 for (i = 0; i < iLen; i++) {
348 queueItem = this.eventQueue[i];
351 queueItemKey = queueItem[0];
352 queueItemValue = queueItem[1];
354 if (queueItemKey == key) {
357 found a dupe... push to end of queue, null
358 current item, and break
361 this.eventQueue[i] = null;
363 this.eventQueue.push(
364 [key, (!Lang.isUndefined(value) ?
365 value : queueItemValue)]);
367 foundDuplicate = true;
373 // this is a refire, or a new property in the queue
375 if (! foundDuplicate && !Lang.isUndefined(value)) {
376 this.eventQueue.push([key, value]);
380 if (property.supercedes) {
382 sLen = property.supercedes.length;
384 for (s = 0; s < sLen; s++) {
386 supercedesCheck = property.supercedes[s];
387 qLen = this.eventQueue.length;
389 for (q = 0; q < qLen; q++) {
390 queueItemCheck = this.eventQueue[q];
392 if (queueItemCheck) {
393 queueItemCheckKey = queueItemCheck[0];
394 queueItemCheckValue = queueItemCheck[1];
396 if (queueItemCheckKey ==
397 supercedesCheck.toLowerCase() ) {
399 this.eventQueue.push([queueItemCheckKey,
400 queueItemCheckValue]);
402 this.eventQueue[q] = null;
419 * Fires the event for a property using the property's current value.
420 * @method refireEvent
421 * @param {String} key The name of the property
423 refireEvent: function (key) {
425 key = key.toLowerCase();
427 var property = this.config[key];
429 if (property && property.event &&
431 !Lang.isUndefined(property.value)) {
433 if (this.queueInProgress) {
435 this.queueProperty(key);
439 this.fireEvent(key, property.value);
447 * Applies a key-value Object literal to the configuration, replacing
448 * any existing values, and queueing the property events.
449 * Although the values will be set, fireQueue() must be called for their
450 * associated events to execute.
451 * @method applyConfig
452 * @param {Object} userConfig The configuration Object literal
453 * @param {Boolean} init When set to true, the initialConfig will
454 * be set to the userConfig passed in, so that calling a reset will
455 * reset the properties to the passed values.
457 applyConfig: function (userConfig, init) {
464 for (sKey in userConfig) {
465 if (Lang.hasOwnProperty(userConfig, sKey)) {
466 oConfig[sKey.toLowerCase()] = userConfig[sKey];
469 this.initialConfig = oConfig;
472 for (sKey in userConfig) {
473 if (Lang.hasOwnProperty(userConfig, sKey)) {
474 this.queueProperty(sKey, userConfig[sKey]);
480 * Refires the events for all configuration properties using their
484 refresh: function () {
488 for (prop in this.config) {
489 if (Lang.hasOwnProperty(this.config, prop)) {
490 this.refireEvent(prop);
496 * Fires the normalized list of queued property change events
499 fireQueue: function () {
507 this.queueInProgress = true;
508 for (i = 0;i < this.eventQueue.length; i++) {
509 queueItem = this.eventQueue[i];
513 value = queueItem[1];
514 property = this.config[key];
516 property.value = value;
518 // Clear out queue entry, to avoid it being
519 // re-added to the queue by any queueProperty/supercedes
520 // calls which are invoked during fireEvent
521 this.eventQueue[i] = null;
523 this.fireEvent(key,value);
527 this.queueInProgress = false;
528 this.eventQueue = [];
532 * Subscribes an external handler to the change event for any
534 * @method subscribeToConfigEvent
535 * @param {String} key The property name
536 * @param {Function} handler The handler function to use subscribe to
537 * the property's event
538 * @param {Object} obj The Object to use for scoping the event handler
539 * (see CustomEvent documentation)
540 * @param {Boolean} override Optional. If true, will override "this"
541 * within the handler to map to the scope Object passed into the method.
542 * @return {Boolean} True, if the subscription was successful,
545 subscribeToConfigEvent: function (key, handler, obj, override) {
547 var property = this.config[key.toLowerCase()];
549 if (property && property.event) {
550 if (!Config.alreadySubscribed(property.event, handler, obj)) {
551 property.event.subscribe(handler, obj, override);
561 * Unsubscribes an external handler from the change event for any
563 * @method unsubscribeFromConfigEvent
564 * @param {String} key The property name
565 * @param {Function} handler The handler function to use subscribe to
566 * the property's event
567 * @param {Object} obj The Object to use for scoping the event
568 * handler (see CustomEvent documentation)
569 * @return {Boolean} True, if the unsubscription was successful,
572 unsubscribeFromConfigEvent: function (key, handler, obj) {
573 var property = this.config[key.toLowerCase()];
574 if (property && property.event) {
575 return property.event.unsubscribe(handler, obj);
582 * Returns a string representation of the Config object
584 * @return {String} The Config object in string format.
586 toString: function () {
587 var output = "Config";
589 output += " [" + this.owner.toString() + "]";
595 * Returns a string representation of the Config object's current
597 * @method outputEventQueue
598 * @return {String} The string list of CustomEvents currently queued
601 outputEventQueue: function () {
606 nQueue = this.eventQueue.length;
608 for (q = 0; q < nQueue; q++) {
609 queueItem = this.eventQueue[q];
611 output += queueItem[0] + "=" + queueItem[1] + ", ";
618 * Sets all properties to null, unsubscribes all listeners from each
619 * property's change event and all listeners from the configChangedEvent.
622 destroy: function () {
624 var oConfig = this.config,
629 for (sProperty in oConfig) {
631 if (Lang.hasOwnProperty(oConfig, sProperty)) {
633 oProperty = oConfig[sProperty];
635 oProperty.event.unsubscribeAll();
636 oProperty.event = null;
642 this.configChangedEvent.unsubscribeAll();
644 this.configChangedEvent = null;
647 this.initialConfig = null;
648 this.eventQueue = null;
657 * Checks to determine if a particular function/Object pair are already
658 * subscribed to the specified CustomEvent
659 * @method YAHOO.util.Config.alreadySubscribed
661 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
663 * @param {Function} fn The function to look for in the subscribers list
664 * @param {Object} obj The execution scope Object for the subscription
665 * @return {Boolean} true, if the function/Object pair is already subscribed
666 * to the CustomEvent passed in
668 Config.alreadySubscribed = function (evt, fn, obj) {
670 var nSubscribers = evt.subscribers.length,
674 if (nSubscribers > 0) {
675 i = nSubscribers - 1;
677 subsc = evt.subscribers[i];
678 if (subsc && subsc.obj == obj && subsc.fn == fn) {
689 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
696 * The Container family of components is designed to enable developers to
697 * create different kinds of content-containing modules on the web. Module
698 * and Overlay are the most basic containers, and they can be used directly
699 * or extended to build custom containers. Also part of the Container family
700 * are four UI controls that extend Module and Overlay: Tooltip, Panel,
701 * Dialog, and SimpleDialog.
704 * @requires yahoo, dom, event
705 * @optional dragdrop, animation, button
709 * Module is a JavaScript representation of the Standard Module Format.
710 * Standard Module Format is a simple standard for markup containers where
711 * child nodes representing the header, body, and footer of the content are
712 * denoted using the CSS classes "hd", "bd", and "ft" respectively.
713 * Module is the base class for all other classes in the YUI
715 * @namespace YAHOO.widget
718 * @param {String} el The element ID representing the Module <em>OR</em>
719 * @param {HTMLElement} el The element representing the Module
720 * @param {Object} userConfig The configuration Object literal containing
721 * the configuration that should be set for this module. See configuration
722 * documentation for more details.
724 YAHOO.widget.Module = function (el, userConfig) {
726 this.init(el, userConfig);
731 var Dom = YAHOO.util.Dom,
732 Config = YAHOO.util.Config,
733 Event = YAHOO.util.Event,
734 CustomEvent = YAHOO.util.CustomEvent,
735 Module = YAHOO.widget.Module,
744 * Constant representing the name of the Module's events
745 * @property EVENT_TYPES
751 "BEFORE_INIT": "beforeInit",
754 "BEFORE_RENDER": "beforeRender",
756 "CHANGE_HEADER": "changeHeader",
757 "CHANGE_BODY": "changeBody",
758 "CHANGE_FOOTER": "changeFooter",
759 "CHANGE_CONTENT": "changeContent",
760 "DESTORY": "destroy",
761 "BEFORE_SHOW": "beforeShow",
763 "BEFORE_HIDE": "beforeHide",
768 * Constant representing the Module's configuration properties
769 * @property DEFAULT_CONFIG
779 validator: YAHOO.lang.isBoolean
785 supercedes: ["visible"]
789 key: "monitorresize",
793 "APPEND_TO_DOCUMENT_BODY": {
794 key: "appendtodocumentbody",
800 * Constant representing the prefix path to use for non-secure images
801 * @property YAHOO.widget.Module.IMG_ROOT
806 Module.IMG_ROOT = null;
809 * Constant representing the prefix path to use for securely served images
810 * @property YAHOO.widget.Module.IMG_ROOT_SSL
815 Module.IMG_ROOT_SSL = null;
818 * Constant for the default CSS class name that represents a Module
819 * @property YAHOO.widget.Module.CSS_MODULE
824 Module.CSS_MODULE = "yui-module";
827 * Constant representing the module header
828 * @property YAHOO.widget.Module.CSS_HEADER
833 Module.CSS_HEADER = "hd";
836 * Constant representing the module body
837 * @property YAHOO.widget.Module.CSS_BODY
842 Module.CSS_BODY = "bd";
845 * Constant representing the module footer
846 * @property YAHOO.widget.Module.CSS_FOOTER
851 Module.CSS_FOOTER = "ft";
854 * Constant representing the url for the "src" attribute of the iframe
855 * used to monitor changes to the browser's base font size
856 * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
861 Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
864 * Constant representing the buffer amount (in pixels) to use when positioning
865 * the text resize monitor offscreen. The resize monitor is positioned
866 * offscreen by an amount eqaul to its offsetHeight + the buffer value.
868 * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
872 // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
873 Module.RESIZE_MONITOR_BUFFER = 1;
876 * Singleton CustomEvent fired when the font size is changed in the browser.
877 * Opera's "zoom" functionality currently does not support text
879 * @event YAHOO.widget.Module.textResizeEvent
881 Module.textResizeEvent = new CustomEvent("textResize");
884 * Helper utility method, which forces a document level
885 * redraw for Opera, which can help remove repaint
886 * irregularities after applying DOM changes.
888 * @method YAHOO.widget.Module.forceDocumentRedraw
891 Module.forceDocumentRedraw = function() {
892 var docEl = document.documentElement;
894 docEl.className += " ";
895 docEl.className = YAHOO.lang.trim(docEl.className);
899 function createModuleTemplate() {
901 if (!m_oModuleTemplate) {
902 m_oModuleTemplate = document.createElement("div");
904 m_oModuleTemplate.innerHTML = ("<div class=\"" +
905 Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
906 Module.CSS_BODY + "\"></div><div class=\"" +
907 Module.CSS_FOOTER + "\"></div>");
909 m_oHeaderTemplate = m_oModuleTemplate.firstChild;
910 m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
911 m_oFooterTemplate = m_oBodyTemplate.nextSibling;
914 return m_oModuleTemplate;
917 function createHeader() {
918 if (!m_oHeaderTemplate) {
919 createModuleTemplate();
921 return (m_oHeaderTemplate.cloneNode(false));
924 function createBody() {
925 if (!m_oBodyTemplate) {
926 createModuleTemplate();
928 return (m_oBodyTemplate.cloneNode(false));
931 function createFooter() {
932 if (!m_oFooterTemplate) {
933 createModuleTemplate();
935 return (m_oFooterTemplate.cloneNode(false));
941 * The class's constructor function
942 * @property contructor
948 * The main module element that contains the header, body, and footer
955 * The header element, denoted with CSS class "hd"
962 * The body element, denoted with CSS class "bd"
969 * The footer element, denoted with CSS class "ft"
976 * The id of the element
983 * A string representing the root path for all images created by
985 * @deprecated It is recommend that any images for a Module be applied
986 * via CSS using the "background-image" property.
987 * @property imageRoot
990 imageRoot: Module.IMG_ROOT,
993 * Initializes the custom events for Module which are fired
994 * automatically at appropriate times by the Module class.
997 initEvents: function () {
999 var SIGNATURE = CustomEvent.LIST;
1002 * CustomEvent fired prior to class initalization.
1003 * @event beforeInitEvent
1004 * @param {class} classRef class reference of the initializing
1005 * class, such as this.beforeInitEvent.fire(Module)
1007 this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1008 this.beforeInitEvent.signature = SIGNATURE;
1011 * CustomEvent fired after class initalization.
1013 * @param {class} classRef class reference of the initializing
1014 * class, such as this.beforeInitEvent.fire(Module)
1016 this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1017 this.initEvent.signature = SIGNATURE;
1020 * CustomEvent fired when the Module is appended to the DOM
1021 * @event appendEvent
1023 this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1024 this.appendEvent.signature = SIGNATURE;
1027 * CustomEvent fired before the Module is rendered
1028 * @event beforeRenderEvent
1030 this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1031 this.beforeRenderEvent.signature = SIGNATURE;
1034 * CustomEvent fired after the Module is rendered
1035 * @event renderEvent
1037 this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1038 this.renderEvent.signature = SIGNATURE;
1041 * CustomEvent fired when the header content of the Module
1043 * @event changeHeaderEvent
1044 * @param {String/HTMLElement} content String/element representing
1045 * the new header content
1047 this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1048 this.changeHeaderEvent.signature = SIGNATURE;
1051 * CustomEvent fired when the body content of the Module is modified
1052 * @event changeBodyEvent
1053 * @param {String/HTMLElement} content String/element representing
1054 * the new body content
1056 this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1057 this.changeBodyEvent.signature = SIGNATURE;
1060 * CustomEvent fired when the footer content of the Module
1062 * @event changeFooterEvent
1063 * @param {String/HTMLElement} content String/element representing
1064 * the new footer content
1066 this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1067 this.changeFooterEvent.signature = SIGNATURE;
1070 * CustomEvent fired when the content of the Module is modified
1071 * @event changeContentEvent
1073 this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1074 this.changeContentEvent.signature = SIGNATURE;
1077 * CustomEvent fired when the Module is destroyed
1078 * @event destroyEvent
1080 this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
1081 this.destroyEvent.signature = SIGNATURE;
1084 * CustomEvent fired before the Module is shown
1085 * @event beforeShowEvent
1087 this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1088 this.beforeShowEvent.signature = SIGNATURE;
1091 * CustomEvent fired after the Module is shown
1094 this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1095 this.showEvent.signature = SIGNATURE;
1098 * CustomEvent fired before the Module is hidden
1099 * @event beforeHideEvent
1101 this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1102 this.beforeHideEvent.signature = SIGNATURE;
1105 * CustomEvent fired after the Module is hidden
1108 this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1109 this.hideEvent.signature = SIGNATURE;
1113 * String representing the current user-agent platform
1114 * @property platform
1117 platform: function () {
1118 var ua = navigator.userAgent.toLowerCase();
1120 if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1122 } else if (ua.indexOf("macintosh") != -1) {
1130 * String representing the user-agent of the browser
1131 * @deprecated Use YAHOO.env.ua
1135 browser: function () {
1136 var ua = navigator.userAgent.toLowerCase();
1138 Check Opera first in case of spoof and check Safari before
1139 Gecko since Safari's user agent string includes "like Gecko"
1141 if (ua.indexOf('opera') != -1) {
1143 } else if (ua.indexOf('msie 7') != -1) {
1145 } else if (ua.indexOf('msie') != -1) {
1147 } else if (ua.indexOf('safari') != -1) {
1149 } else if (ua.indexOf('gecko') != -1) {
1157 * Boolean representing whether or not the current browsing context is
1159 * @property isSecure
1162 isSecure: function () {
1163 if (window.location.href.toLowerCase().indexOf("https") === 0) {
1171 * Initializes the custom events for Module which are fired
1172 * automatically at appropriate times by the Module class.
1174 initDefaultConfig: function () {
1175 // Add properties //
1177 * Specifies whether the Module is visible on the page.
1182 this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1183 handler: this.configVisible,
1184 value: DEFAULT_CONFIG.VISIBLE.value,
1185 validator: DEFAULT_CONFIG.VISIBLE.validator
1190 * Object or array of objects representing the ContainerEffect
1191 * classes that are active for animating the container.
1194 * <strong>NOTE:</strong> Although this configuration
1195 * property is introduced at the Module level, an out of the box
1196 * implementation is not shipped for the Module class so setting
1197 * the proroperty on the Module class has no effect. The Overlay
1198 * class is the first class to provide out of the box ContainerEffect
1205 this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1206 suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1207 supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1211 * Specifies whether to create a special proxy iframe to monitor
1212 * for user font resizing in the document
1213 * @config monitorresize
1217 this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1218 handler: this.configMonitorResize,
1219 value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1223 * Specifies if the module should be rendered as the first child
1224 * of document.body or appended as the last child when render is called
1225 * with document.body as the "appendToNode".
1227 * Appending to the body while the DOM is still being constructed can
1228 * lead to Operation Aborted errors in IE hence this flag is set to
1232 * @config appendtodocumentbody
1236 this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1237 value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1242 * The Module class's initialization method, which is executed for
1243 * Module and all of its subclasses. This method is automatically
1244 * called by the constructor, and sets up all DOM references for
1245 * pre-existing markup, and creates required markup if it is not
1248 * If the element passed in does not have an id, one will be generated
1252 * @param {String} el The element ID representing the Module <em>OR</em>
1253 * @param {HTMLElement} el The element representing the Module
1254 * @param {Object} userConfig The configuration Object literal
1255 * containing the configuration that should be set for this module.
1256 * See configuration documentation for more details.
1258 init: function (el, userConfig) {
1263 this.beforeInitEvent.fire(Module);
1266 * The Module's Config object used for monitoring
1267 * configuration properties.
1269 * @type YAHOO.util.Config
1271 this.cfg = new Config(this);
1273 if (this.isSecure) {
1274 this.imageRoot = Module.IMG_ROOT_SSL;
1277 if (typeof el == "string") {
1279 el = document.getElementById(el);
1281 el = (createModuleTemplate()).cloneNode(false);
1286 this.id = Dom.generateId(el);
1289 child = this.element.firstChild;
1292 var fndHd = false, fndBd = false, fndFt = false;
1294 // We're looking for elements
1295 if (1 == child.nodeType) {
1296 if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1297 this.header = child;
1299 } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1302 } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1303 this.footer = child;
1307 } while ((child = child.nextSibling));
1310 this.initDefaultConfig();
1312 Dom.addClass(this.element, Module.CSS_MODULE);
1315 this.cfg.applyConfig(userConfig, true);
1319 Subscribe to the fireQueue() method of Config so that any
1320 queued configuration changes are excecuted upon render of
1324 if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1325 this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1328 this.initEvent.fire(Module);
1332 * Initialize an empty IFRAME that is placed out of the visible area
1333 * that can be used to detect text resize.
1334 * @method initResizeMonitor
1336 initResizeMonitor: function () {
1338 var isGeckoWin = (UA.gecko && this.platform == "windows");
1340 // Help prevent spinning loading icon which
1341 // started with FireFox 2.0.0.8/Win
1343 setTimeout(function(){self._initResizeMonitor();}, 0);
1345 this._initResizeMonitor();
1350 * Create and initialize the text resize monitoring iframe.
1353 * @method _initResizeMonitor
1355 _initResizeMonitor : function() {
1361 function fireTextResize() {
1362 Module.textResizeEvent.fire();
1366 oIFrame = Dom.get("_yuiResizeMonitor");
1368 var supportsCWResize = this._supportsCWResize();
1371 oIFrame = document.createElement("iframe");
1373 if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1374 oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1377 if (!supportsCWResize) {
1378 // Can't monitor on contentWindow, so fire from inside iframe
1379 sHTML = ["<html><head><script ",
1380 "type=\"text/javascript\">",
1381 "window.onresize=function(){window.parent.",
1382 "YAHOO.widget.Module.textResizeEvent.",
1385 "<body></body></html>"].join('');
1387 oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1390 oIFrame.id = "_yuiResizeMonitor";
1391 oIFrame.title = "Text Resize Monitor";
1393 Need to set "position" property before inserting the
1394 iframe into the document or Safari's status bar will
1395 forever indicate the iframe is loading
1396 (See SourceForge bug #1723064)
1398 oIFrame.style.position = "absolute";
1399 oIFrame.style.visibility = "hidden";
1401 var db = document.body,
1404 db.insertBefore(oIFrame, fc);
1406 db.appendChild(oIFrame);
1409 oIFrame.style.width = "2em";
1410 oIFrame.style.height = "2em";
1411 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1412 oIFrame.style.left = "0";
1413 oIFrame.style.borderWidth = "0";
1414 oIFrame.style.visibility = "visible";
1417 Don't open/close the document for Gecko like we used to, since it
1418 leads to duplicate cookies. (See SourceForge bug #1721755)
1421 oDoc = oIFrame.contentWindow.document;
1427 if (oIFrame && oIFrame.contentWindow) {
1428 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1430 if (!Module.textResizeInitialized) {
1431 if (supportsCWResize) {
1432 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1434 This will fail in IE if document.domain has
1435 changed, so we must change the listener to
1436 use the oIFrame element instead
1438 Event.on(oIFrame, "resize", fireTextResize);
1441 Module.textResizeInitialized = true;
1443 this.resizeMonitor = oIFrame;
1449 * Text resize monitor helper method.
1450 * Determines if the browser supports resize events on iframe content windows.
1453 * @method _supportsCWResize
1455 _supportsCWResize : function() {
1457 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1458 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1460 We don't want to start sniffing for patch versions, so fire textResize the same
1461 way on all FF2 flavors
1463 var bSupported = true;
1464 if (UA.gecko && UA.gecko <= 1.8) {
1471 * Event handler fired when the resize monitor element is resized.
1472 * @method onDomResize
1473 * @param {DOMEvent} e The DOM resize event
1474 * @param {Object} obj The scope object passed to the handler
1476 onDomResize: function (e, obj) {
1478 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1480 this.resizeMonitor.style.top = nTop + "px";
1481 this.resizeMonitor.style.left = "0";
1485 * Sets the Module's header content to the string specified, or appends
1486 * the passed element to the header. If no header is present, one will
1487 * be automatically created. An empty string can be passed to the method
1488 * to clear the contents of the header.
1491 * @param {String} headerContent The string used to set the header.
1492 * As a convenience, non HTMLElement objects can also be passed into
1493 * the method, and will be treated as strings, with the header innerHTML
1494 * set to their default toString implementations.
1496 * @param {HTMLElement} headerContent The HTMLElement to append to
1498 * @param {DocumentFragment} headerContent The document fragment
1499 * containing elements which are to be added to the header
1501 setHeader: function (headerContent) {
1502 var oHeader = this.header || (this.header = createHeader());
1504 if (headerContent.nodeName) {
1505 oHeader.innerHTML = "";
1506 oHeader.appendChild(headerContent);
1508 oHeader.innerHTML = headerContent;
1511 this.changeHeaderEvent.fire(headerContent);
1512 this.changeContentEvent.fire();
1517 * Appends the passed element to the header. If no header is present,
1518 * one will be automatically created.
1519 * @method appendToHeader
1520 * @param {HTMLElement | DocumentFragment} element The element to
1521 * append to the header. In the case of a document fragment, the
1522 * children of the fragment will be appended to the header.
1524 appendToHeader: function (element) {
1525 var oHeader = this.header || (this.header = createHeader());
1527 oHeader.appendChild(element);
1529 this.changeHeaderEvent.fire(element);
1530 this.changeContentEvent.fire();
1535 * Sets the Module's body content to the HTML specified.
1537 * If no body is present, one will be automatically created.
1539 * An empty string can be passed to the method to clear the contents of the body.
1541 * @param {String} bodyContent The HTML used to set the body.
1542 * As a convenience, non HTMLElement objects can also be passed into
1543 * the method, and will be treated as strings, with the body innerHTML
1544 * set to their default toString implementations.
1546 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1547 * child of the body element.
1549 * @param {DocumentFragment} bodyContent The document fragment
1550 * containing elements which are to be added to the body
1552 setBody: function (bodyContent) {
1553 var oBody = this.body || (this.body = createBody());
1555 if (bodyContent.nodeName) {
1556 oBody.innerHTML = "";
1557 oBody.appendChild(bodyContent);
1559 oBody.innerHTML = bodyContent;
1562 this.changeBodyEvent.fire(bodyContent);
1563 this.changeContentEvent.fire();
1567 * Appends the passed element to the body. If no body is present, one
1568 * will be automatically created.
1569 * @method appendToBody
1570 * @param {HTMLElement | DocumentFragment} element The element to
1571 * append to the body. In the case of a document fragment, the
1572 * children of the fragment will be appended to the body.
1575 appendToBody: function (element) {
1576 var oBody = this.body || (this.body = createBody());
1578 oBody.appendChild(element);
1580 this.changeBodyEvent.fire(element);
1581 this.changeContentEvent.fire();
1586 * Sets the Module's footer content to the HTML specified, or appends
1587 * the passed element to the footer. If no footer is present, one will
1588 * be automatically created. An empty string can be passed to the method
1589 * to clear the contents of the footer.
1591 * @param {String} footerContent The HTML used to set the footer
1592 * As a convenience, non HTMLElement objects can also be passed into
1593 * the method, and will be treated as strings, with the footer innerHTML
1594 * set to their default toString implementations.
1596 * @param {HTMLElement} footerContent The HTMLElement to append to
1599 * @param {DocumentFragment} footerContent The document fragment containing
1600 * elements which are to be added to the footer
1602 setFooter: function (footerContent) {
1604 var oFooter = this.footer || (this.footer = createFooter());
1606 if (footerContent.nodeName) {
1607 oFooter.innerHTML = "";
1608 oFooter.appendChild(footerContent);
1610 oFooter.innerHTML = footerContent;
1613 this.changeFooterEvent.fire(footerContent);
1614 this.changeContentEvent.fire();
1618 * Appends the passed element to the footer. If no footer is present,
1619 * one will be automatically created.
1620 * @method appendToFooter
1621 * @param {HTMLElement | DocumentFragment} element The element to
1622 * append to the footer. In the case of a document fragment, the
1623 * children of the fragment will be appended to the footer
1625 appendToFooter: function (element) {
1627 var oFooter = this.footer || (this.footer = createFooter());
1629 oFooter.appendChild(element);
1631 this.changeFooterEvent.fire(element);
1632 this.changeContentEvent.fire();
1637 * Renders the Module by inserting the elements that are not already
1638 * in the main Module into their correct places. Optionally appends
1639 * the Module to the specified node prior to the render's execution.
1641 * For Modules without existing markup, the appendToNode argument
1642 * is REQUIRED. If this argument is ommitted and the current element is
1643 * not present in the document, the function will return false,
1644 * indicating that the render was a failure.
1647 * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1648 * then the module is rendered as the first child of the body element,
1649 * and not appended to it, to avoid Operation Aborted errors in IE when
1650 * rendering the module before window's load event is fired. You can
1651 * use the appendtodocumentbody configuration property to change this
1652 * to append to document.body if required.
1655 * @param {String} appendToNode The element id to which the Module
1656 * should be appended to prior to rendering <em>OR</em>
1657 * @param {HTMLElement} appendToNode The element to which the Module
1658 * should be appended to prior to rendering
1659 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1660 * represents the actual Standard Module container.
1661 * @return {Boolean} Success or failure of the render
1663 render: function (appendToNode, moduleElement) {
1668 function appendTo(parentNode) {
1669 if (typeof parentNode == "string") {
1670 parentNode = document.getElementById(parentNode);
1674 me._addToParent(parentNode, me.element);
1675 me.appendEvent.fire();
1679 this.beforeRenderEvent.fire();
1681 if (! moduleElement) {
1682 moduleElement = this.element;
1686 appendTo(appendToNode);
1688 // No node was passed in. If the element is not already in the Dom, this fails
1689 if (! Dom.inDocument(this.element)) {
1694 // Need to get everything into the DOM if it isn't already
1695 if (this.header && ! Dom.inDocument(this.header)) {
1696 // There is a header, but it's not in the DOM yet. Need to add it.
1697 firstChild = moduleElement.firstChild;
1699 moduleElement.insertBefore(this.header, firstChild);
1701 moduleElement.appendChild(this.header);
1705 if (this.body && ! Dom.inDocument(this.body)) {
1706 // There is a body, but it's not in the DOM yet. Need to add it.
1707 if (this.footer && Dom.isAncestor(this.moduleElement, this.footer)) {
1708 moduleElement.insertBefore(this.body, this.footer);
1710 moduleElement.appendChild(this.body);
1714 if (this.footer && ! Dom.inDocument(this.footer)) {
1715 // There is a footer, but it's not in the DOM yet. Need to add it.
1716 moduleElement.appendChild(this.footer);
1719 this.renderEvent.fire();
1724 * Removes the Module element from the DOM and sets all child elements
1728 destroy: function () {
1733 Event.purgeElement(this.element, true);
1734 parent = this.element.parentNode;
1738 parent.removeChild(this.element);
1741 this.element = null;
1746 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1751 this.destroyEvent.fire();
1755 * Shows the Module element by setting the visible configuration
1756 * property to true. Also fires two events: beforeShowEvent prior to
1757 * the visibility change, and showEvent after.
1761 this.cfg.setProperty("visible", true);
1765 * Hides the Module element by setting the visible configuration
1766 * property to false. Also fires two events: beforeHideEvent prior to
1767 * the visibility change, and hideEvent after.
1771 this.cfg.setProperty("visible", false);
1774 // BUILT-IN EVENT HANDLERS FOR MODULE //
1776 * Default event handler for changing the visibility property of a
1777 * Module. By default, this is achieved by switching the "display" style
1778 * between "block" and "none".
1779 * This method is responsible for firing showEvent and hideEvent.
1780 * @param {String} type The CustomEvent type (usually the property name)
1781 * @param {Object[]} args The CustomEvent arguments. For configuration
1782 * handlers, args[0] will equal the newly applied value for the property.
1783 * @param {Object} obj The scope object. For configuration handlers,
1784 * this will usually equal the owner.
1785 * @method configVisible
1787 configVisible: function (type, args, obj) {
1788 var visible = args[0];
1790 this.beforeShowEvent.fire();
1791 Dom.setStyle(this.element, "display", "block");
1792 this.showEvent.fire();
1794 this.beforeHideEvent.fire();
1795 Dom.setStyle(this.element, "display", "none");
1796 this.hideEvent.fire();
1801 * Default event handler for the "monitorresize" configuration property
1802 * @param {String} type The CustomEvent type (usually the property name)
1803 * @param {Object[]} args The CustomEvent arguments. For configuration
1804 * handlers, args[0] will equal the newly applied value for the property.
1805 * @param {Object} obj The scope object. For configuration handlers,
1806 * this will usually equal the owner.
1807 * @method configMonitorResize
1809 configMonitorResize: function (type, args, obj) {
1810 var monitor = args[0];
1812 this.initResizeMonitor();
1814 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1815 this.resizeMonitor = null;
1820 * This method is a protected helper, used when constructing the DOM structure for the module
1821 * to account for situations which may cause Operation Aborted errors in IE. It should not
1822 * be used for general DOM construction.
1824 * If the parentNode is not document.body, the element is appended as the last element.
1827 * If the parentNode is document.body the element is added as the first child to help
1828 * prevent Operation Aborted errors in IE.
1831 * @param {parentNode} The HTML element to which the element will be added
1832 * @param {element} The HTML element to be added to parentNode's children
1833 * @method _addToParent
1836 _addToParent: function(parentNode, element) {
1837 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1838 parentNode.insertBefore(element, parentNode.firstChild);
1840 parentNode.appendChild(element);
1845 * Returns a String representation of the Object.
1847 * @return {String} The string representation of the Module
1849 toString: function () {
1850 return "Module " + this.id;
1854 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1861 * Overlay is a Module that is absolutely positioned above the page flow. It
1862 * has convenience methods for positioning and sizing, as well as options for
1863 * controlling zIndex and constraining the Overlay's position to the current
1864 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1865 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1866 * properly rendered above SELECT elements.
1867 * @namespace YAHOO.widget
1869 * @extends YAHOO.widget.Module
1870 * @param {String} el The element ID representing the Overlay <em>OR</em>
1871 * @param {HTMLElement} el The element representing the Overlay
1872 * @param {Object} userConfig The configuration object literal containing
1873 * the configuration that should be set for this Overlay. See configuration
1874 * documentation for more details.
1877 YAHOO.widget.Overlay = function (el, userConfig) {
1878 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1881 var Lang = YAHOO.lang,
1882 CustomEvent = YAHOO.util.CustomEvent,
1883 Module = YAHOO.widget.Module,
1884 Event = YAHOO.util.Event,
1885 Dom = YAHOO.util.Dom,
1886 Config = YAHOO.util.Config,
1888 Overlay = YAHOO.widget.Overlay,
1890 _SUBSCRIBE = "subscribe",
1891 _UNSUBSCRIBE = "unsubscribe",
1892 _CONTAINED = "contained",
1897 * Constant representing the name of the Overlay's events
1898 * @property EVENT_TYPES
1904 "BEFORE_MOVE": "beforeMove",
1909 * Constant representing the Overlay's configuration properties
1910 * @property DEFAULT_CONFIG
1919 validator: Lang.isNumber,
1920 suppressEvent: true,
1921 supercedes: ["iframe"]
1926 validator: Lang.isNumber,
1927 suppressEvent: true,
1928 supercedes: ["iframe"]
1933 suppressEvent: true,
1934 supercedes: ["iframe"]
1939 suppressEvent: true,
1940 supercedes: ["iframe"]
1946 supercedes: ["iframe", "visible"]
1951 suppressEvent: true,
1952 supercedes: ["context", "fixedcenter", "iframe"]
1957 suppressEvent: true,
1958 supercedes: ["context", "fixedcenter", "iframe"]
1961 "AUTO_FILL_HEIGHT" : {
1962 key: "autofillheight",
1963 supercedes: ["height"],
1972 "CONSTRAIN_TO_VIEWPORT": {
1973 key: "constraintoviewport",
1975 validator: Lang.isBoolean,
1976 supercedes: ["iframe", "x", "y", "xy"]
1981 value: (UA.ie == 6 ? true : false),
1982 validator: Lang.isBoolean,
1983 supercedes: ["zindex"]
1986 "PREVENT_CONTEXT_OVERLAP": {
1987 key: "preventcontextoverlap",
1989 validator: Lang.isBoolean,
1990 supercedes: ["constraintoviewport"]
1996 * The URL that will be placed in the iframe
1997 * @property YAHOO.widget.Overlay.IFRAME_SRC
2002 Overlay.IFRAME_SRC = "javascript:false;";
2005 * Number representing how much the iframe shim should be offset from each
2006 * side of an Overlay instance, in pixels.
2007 * @property YAHOO.widget.Overlay.IFRAME_SRC
2013 Overlay.IFRAME_OFFSET = 3;
2016 * Number representing the minimum distance an Overlay instance should be
2017 * positioned relative to the boundaries of the browser's viewport, in pixels.
2018 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2024 Overlay.VIEWPORT_OFFSET = 10;
2027 * Constant representing the top left corner of an element, used for
2028 * configuring the context element alignment
2029 * @property YAHOO.widget.Overlay.TOP_LEFT
2034 Overlay.TOP_LEFT = "tl";
2037 * Constant representing the top right corner of an element, used for
2038 * configuring the context element alignment
2039 * @property YAHOO.widget.Overlay.TOP_RIGHT
2044 Overlay.TOP_RIGHT = "tr";
2047 * Constant representing the top bottom left corner of an element, used for
2048 * configuring the context element alignment
2049 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2054 Overlay.BOTTOM_LEFT = "bl";
2057 * Constant representing the bottom right corner of an element, used for
2058 * configuring the context element alignment
2059 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2064 Overlay.BOTTOM_RIGHT = "br";
2067 * Constant representing the default CSS class used for an Overlay
2068 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2073 Overlay.CSS_OVERLAY = "yui-overlay";
2076 * Constant representing the names of the standard module elements
2077 * used in the overlay.
2078 * @property YAHOO.widget.Overlay.STD_MOD_RE
2083 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2086 * A singleton CustomEvent used for reacting to the DOM event for
2088 * @event YAHOO.widget.Overlay.windowScrollEvent
2090 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2093 * A singleton CustomEvent used for reacting to the DOM event for
2095 * @event YAHOO.widget.Overlay.windowResizeEvent
2097 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2100 * The DOM event handler used to fire the CustomEvent for window scroll
2101 * @method YAHOO.widget.Overlay.windowScrollHandler
2103 * @param {DOMEvent} e The DOM scroll event
2105 Overlay.windowScrollHandler = function (e) {
2106 var t = Event.getTarget(e);
2108 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2109 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2110 // - IE doesn't recognize scroll registered on the document.
2112 // Also, when document view is scrolled, IE doesn't provide a target,
2113 // rest of the browsers set target to window.document, apart from opera
2114 // which sets target to window.
2115 if (!t || t === window || t === window.document) {
2118 if (! window.scrollEnd) {
2119 window.scrollEnd = -1;
2122 clearTimeout(window.scrollEnd);
2124 window.scrollEnd = setTimeout(function () {
2125 Overlay.windowScrollEvent.fire();
2129 Overlay.windowScrollEvent.fire();
2135 * The DOM event handler used to fire the CustomEvent for window resize
2136 * @method YAHOO.widget.Overlay.windowResizeHandler
2138 * @param {DOMEvent} e The DOM resize event
2140 Overlay.windowResizeHandler = function (e) {
2143 if (! window.resizeEnd) {
2144 window.resizeEnd = -1;
2147 clearTimeout(window.resizeEnd);
2149 window.resizeEnd = setTimeout(function () {
2150 Overlay.windowResizeEvent.fire();
2153 Overlay.windowResizeEvent.fire();
2158 * A boolean that indicated whether the window resize and scroll events have
2159 * already been subscribed to.
2160 * @property YAHOO.widget.Overlay._initialized
2164 Overlay._initialized = null;
2166 if (Overlay._initialized === null) {
2167 Event.on(window, "scroll", Overlay.windowScrollHandler);
2168 Event.on(window, "resize", Overlay.windowResizeHandler);
2169 Overlay._initialized = true;
2173 * Internal map of special event types, which are provided
2174 * by the instance. It maps the event type to the custom event
2175 * instance. Contains entries for the "windowScroll", "windowResize" and
2176 * "textResize" static container events.
2178 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2183 Overlay._TRIGGER_MAP = {
2184 "windowScroll" : Overlay.windowScrollEvent,
2185 "windowResize" : Overlay.windowResizeEvent,
2186 "textResize" : Module.textResizeEvent
2189 YAHOO.extend(Overlay, Module, {
2193 * Array of default event types which will trigger
2194 * context alignment for the Overlay class.
2196 * <p>The array is empty by default for Overlay,
2197 * but maybe populated in future releases, so classes extending
2198 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2199 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2200 * value with their own array of values.
2204 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2207 * @property CONTEXT_TRIGGERS
2211 CONTEXT_TRIGGERS : [],
2214 * The Overlay initialization method, which is executed for Overlay and
2215 * all of its subclasses. This method is automatically called by the
2216 * constructor, and sets up all DOM references for pre-existing markup,
2217 * and creates required markup if it is not already present.
2219 * @param {String} el The element ID representing the Overlay <em>OR</em>
2220 * @param {HTMLElement} el The element representing the Overlay
2221 * @param {Object} userConfig The configuration object literal
2222 * containing the configuration that should be set for this Overlay.
2223 * See configuration documentation for more details.
2225 init: function (el, userConfig) {
2228 Note that we don't pass the user config in here yet because we
2229 only want it executed once, at the lowest subclass level
2232 Overlay.superclass.init.call(this, el/*, userConfig*/);
2234 this.beforeInitEvent.fire(Overlay);
2236 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2239 this.cfg.applyConfig(userConfig, true);
2242 if (this.platform == "mac" && UA.gecko) {
2244 if (! Config.alreadySubscribed(this.showEvent,
2245 this.showMacGeckoScrollbars, this)) {
2247 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2252 if (! Config.alreadySubscribed(this.hideEvent,
2253 this.hideMacGeckoScrollbars, this)) {
2255 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2261 this.initEvent.fire(Overlay);
2265 * Initializes the custom events for Overlay which are fired
2266 * automatically at appropriate times by the Overlay class.
2267 * @method initEvents
2269 initEvents: function () {
2271 Overlay.superclass.initEvents.call(this);
2273 var SIGNATURE = CustomEvent.LIST;
2276 * CustomEvent fired before the Overlay is moved.
2277 * @event beforeMoveEvent
2278 * @param {Number} x x coordinate
2279 * @param {Number} y y coordinate
2281 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2282 this.beforeMoveEvent.signature = SIGNATURE;
2285 * CustomEvent fired after the Overlay is moved.
2287 * @param {Number} x x coordinate
2288 * @param {Number} y y coordinate
2290 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2291 this.moveEvent.signature = SIGNATURE;
2296 * Initializes the class's configurable properties which can be changed
2297 * using the Overlay's Config object (cfg).
2298 * @method initDefaultConfig
2300 initDefaultConfig: function () {
2302 Overlay.superclass.initDefaultConfig.call(this);
2306 // Add overlay config properties //
2309 * The absolute x-coordinate position of the Overlay
2314 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2316 handler: this.configX,
2317 validator: DEFAULT_CONFIG.X.validator,
2318 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2319 supercedes: DEFAULT_CONFIG.X.supercedes
2324 * The absolute y-coordinate position of the Overlay
2329 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2331 handler: this.configY,
2332 validator: DEFAULT_CONFIG.Y.validator,
2333 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2334 supercedes: DEFAULT_CONFIG.Y.supercedes
2339 * An array with the absolute x and y positions of the Overlay
2344 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2345 handler: this.configXY,
2346 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2347 supercedes: DEFAULT_CONFIG.XY.supercedes
2352 * The array of context arguments for context-sensitive positioning.
2356 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional)]</code>, the
2357 * the 4 array elements described in detail below:
2361 * <dt>contextElementOrId <String|HTMLElement></dt>
2362 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2363 * <dt>overlayCorner <String></dt>
2364 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2365 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2366 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2367 * <dt>contextCorner <String></dt>
2368 * <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>
2369 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2372 * 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>
2373 * 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.
2374 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2377 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2378 * 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).
2384 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2385 * align the Overlay's top left corner to the bottom left corner of the
2386 * context element with id "img1".
2389 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"]]</code>,
2390 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2397 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2398 handler: this.configContext,
2399 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2400 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2404 * Determines whether or not the Overlay should be anchored
2405 * to the center of the viewport.
2407 * <p>This property can be set to:</p>
2412 * To enable fixed center positioning
2414 * When enabled, the overlay will
2415 * be positioned in the center of viewport when initially displayed, and
2416 * will remain in the center of the viewport whenever the window is
2417 * scrolled or resized.
2420 * If the overlay is too big for the viewport,
2421 * it's top left corner will be aligned with the top left corner of the viewport.
2426 * To disable fixed center positioning.
2427 * <p>In this case the overlay can still be
2428 * centered as a one-off operation, by invoking the <code>center()</code> method,
2429 * however it will not remain centered when the window is scrolled/resized.
2431 * <dt>"contained"<dt>
2432 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2433 * <p>However, unlike setting the property to <code>true</code>,
2434 * when the property is set to <code>"contained"</code>, if the overlay is
2435 * too big for the viewport, it will not get automatically centered when the
2436 * user scrolls or resizes the window (until the window is large enough to contain the
2437 * overlay). This is useful in cases where the Overlay has both header and footer
2438 * UI controls which the user may need to access.
2443 * @config fixedcenter
2444 * @type Boolean | String
2447 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2448 handler: this.configFixedCenter,
2449 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2450 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2451 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2455 * CSS width of the Overlay.
2460 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2461 handler: this.configWidth,
2462 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2463 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2467 * CSS height of the Overlay.
2472 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2473 handler: this.configHeight,
2474 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2475 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2479 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2480 * Supported values are "header", "body", "footer".
2482 * @config autofillheight
2486 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2487 handler: this.configAutoFillHeight,
2488 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2489 validator : this._validateAutoFill,
2490 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2494 * CSS z-index of the Overlay.
2499 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2500 handler: this.configzIndex,
2501 value: DEFAULT_CONFIG.ZINDEX.value
2505 * True if the Overlay should be prevented from being positioned
2506 * out of the viewport.
2507 * @config constraintoviewport
2511 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2513 handler: this.configConstrainToViewport,
2514 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2515 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2516 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2522 * @description Boolean indicating whether or not the Overlay should
2523 * have an IFRAME shim; used to prevent SELECT elements from
2524 * poking through an Overlay instance in IE6. When set to "true",
2525 * the iframe shim is created when the Overlay instance is intially
2528 * @default true for IE6 and below, false for all other browsers.
2530 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2532 handler: this.configIframe,
2533 value: DEFAULT_CONFIG.IFRAME.value,
2534 validator: DEFAULT_CONFIG.IFRAME.validator,
2535 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2540 * @config preventcontextoverlap
2541 * @description Boolean indicating whether or not the Overlay should overlap its
2542 * context element (defined using the "context" configuration property) when the
2543 * "constraintoviewport" configuration property is set to "true".
2547 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2549 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2550 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2551 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2558 * Moves the Overlay to the specified position. This function is
2559 * identical to calling this.cfg.setProperty("xy", [x,y]);
2561 * @param {Number} x The Overlay's new x position
2562 * @param {Number} y The Overlay's new y position
2564 moveTo: function (x, y) {
2565 this.cfg.setProperty("xy", [x, y]);
2569 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2570 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2571 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2572 * @method hideMacGeckoScrollbars
2574 hideMacGeckoScrollbars: function () {
2575 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2579 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2580 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2581 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2582 * @method showMacGeckoScrollbars
2584 showMacGeckoScrollbars: function () {
2585 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2589 * Internal implementation to set the visibility of the overlay in the DOM.
2591 * @method _setDomVisibility
2592 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2595 _setDomVisibility : function(show) {
2596 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2599 Dom.removeClass(this.element, "yui-overlay-hidden");
2601 Dom.addClass(this.element, "yui-overlay-hidden");
2605 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2607 * The default event handler fired when the "visible" property is
2608 * changed. This method is responsible for firing showEvent
2610 * @method configVisible
2611 * @param {String} type The CustomEvent type (usually the property name)
2612 * @param {Object[]} args The CustomEvent arguments. For configuration
2613 * handlers, args[0] will equal the newly applied value for the property.
2614 * @param {Object} obj The scope object. For configuration handlers,
2615 * this will usually equal the owner.
2617 configVisible: function (type, args, obj) {
2619 var visible = args[0],
2620 currentVis = Dom.getStyle(this.element, "visibility"),
2621 effect = this.cfg.getProperty("effect"),
2622 effectInstances = [],
2623 isMacGecko = (this.platform == "mac" && UA.gecko),
2624 alreadySubscribed = Config.alreadySubscribed,
2625 eff, ei, e, i, j, k, h,
2629 if (currentVis == "inherit") {
2630 e = this.element.parentNode;
2632 while (e.nodeType != 9 && e.nodeType != 11) {
2633 currentVis = Dom.getStyle(e, "visibility");
2635 if (currentVis != "inherit") {
2642 if (currentVis == "inherit") {
2643 currentVis = "visible";
2648 if (effect instanceof Array) {
2649 nEffects = effect.length;
2651 for (i = 0; i < nEffects; i++) {
2653 effectInstances[effectInstances.length] =
2654 eff.effect(this, eff.duration);
2658 effectInstances[effectInstances.length] =
2659 effect.effect(this, effect.duration);
2663 if (visible) { // Show
2665 this.showMacGeckoScrollbars();
2668 if (effect) { // Animate in
2669 if (visible) { // Animate in if not showing
2670 if (currentVis != "visible" || currentVis === "") {
2671 this.beforeShowEvent.fire();
2672 nEffectInstances = effectInstances.length;
2674 for (j = 0; j < nEffectInstances; j++) {
2675 ei = effectInstances[j];
2676 if (j === 0 && !alreadySubscribed(
2677 ei.animateInCompleteEvent,
2678 this.showEvent.fire, this.showEvent)) {
2681 Delegate showEvent until end
2682 of animateInComplete
2685 ei.animateInCompleteEvent.subscribe(
2686 this.showEvent.fire, this.showEvent, true);
2693 if (currentVis != "visible" || currentVis === "") {
2694 this.beforeShowEvent.fire();
2696 this._setDomVisibility(true);
2698 this.cfg.refireEvent("iframe");
2699 this.showEvent.fire();
2701 this._setDomVisibility(true);
2707 this.hideMacGeckoScrollbars();
2710 if (effect) { // Animate out if showing
2711 if (currentVis == "visible") {
2712 this.beforeHideEvent.fire();
2714 nEffectInstances = effectInstances.length;
2715 for (k = 0; k < nEffectInstances; k++) {
2716 h = effectInstances[k];
2718 if (k === 0 && !alreadySubscribed(
2719 h.animateOutCompleteEvent, this.hideEvent.fire,
2723 Delegate hideEvent until end
2724 of animateOutComplete
2727 h.animateOutCompleteEvent.subscribe(
2728 this.hideEvent.fire, this.hideEvent, true);
2734 } else if (currentVis === "") {
2735 this._setDomVisibility(false);
2738 } else { // Simple hide
2740 if (currentVis == "visible" || currentVis === "") {
2741 this.beforeHideEvent.fire();
2742 this._setDomVisibility(false);
2743 this.hideEvent.fire();
2745 this._setDomVisibility(false);
2752 * Fixed center event handler used for centering on scroll/resize, but only if
2753 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2754 * the overlay fits within the viewport.
2756 * @method doCenterOnDOMEvent
2758 doCenterOnDOMEvent: function () {
2760 fc = cfg.getProperty("fixedcenter");
2762 if (cfg.getProperty("visible")) {
2763 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2770 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2771 * will fit entirely inside the viewport, in both dimensions - width and height.
2773 * @method fitsInViewport
2774 * @return boolean true if the Overlay will fit, false if not
2776 fitsInViewport : function() {
2777 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2778 element = this.element,
2779 elementWidth = element.offsetWidth,
2780 elementHeight = element.offsetHeight,
2781 viewportWidth = Dom.getViewportWidth(),
2782 viewportHeight = Dom.getViewportHeight();
2784 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2788 * The default event handler fired when the "fixedcenter" property
2790 * @method configFixedCenter
2791 * @param {String} type The CustomEvent type (usually the property name)
2792 * @param {Object[]} args The CustomEvent arguments. For configuration
2793 * handlers, args[0] will equal the newly applied value for the property.
2794 * @param {Object} obj The scope object. For configuration handlers,
2795 * this will usually equal the owner.
2797 configFixedCenter: function (type, args, obj) {
2800 alreadySubscribed = Config.alreadySubscribed,
2801 windowResizeEvent = Overlay.windowResizeEvent,
2802 windowScrollEvent = Overlay.windowScrollEvent;
2807 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2808 this.beforeShowEvent.subscribe(this.center);
2811 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2812 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2815 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2816 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2820 this.beforeShowEvent.unsubscribe(this.center);
2822 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2823 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2828 * The default event handler fired when the "height" property is changed.
2829 * @method configHeight
2830 * @param {String} type The CustomEvent type (usually the property name)
2831 * @param {Object[]} args The CustomEvent arguments. For configuration
2832 * handlers, args[0] will equal the newly applied value for the property.
2833 * @param {Object} obj The scope object. For configuration handlers,
2834 * this will usually equal the owner.
2836 configHeight: function (type, args, obj) {
2838 var height = args[0],
2841 Dom.setStyle(el, "height", height);
2842 this.cfg.refireEvent("iframe");
2846 * The default event handler fired when the "autofillheight" property is changed.
2847 * @method configAutoFillHeight
2849 * @param {String} type The CustomEvent type (usually the property name)
2850 * @param {Object[]} args The CustomEvent arguments. For configuration
2851 * handlers, args[0] will equal the newly applied value for the property.
2852 * @param {Object} obj The scope object. For configuration handlers,
2853 * this will usually equal the owner.
2855 configAutoFillHeight: function (type, args, obj) {
2856 var fillEl = args[0],
2858 autoFillHeight = "autofillheight",
2860 currEl = cfg.getProperty(autoFillHeight),
2861 autoFill = this._autoFillOnHeightChange;
2863 cfg.unsubscribeFromConfigEvent(height, autoFill);
2864 Module.textResizeEvent.unsubscribe(autoFill);
2865 this.changeContentEvent.unsubscribe(autoFill);
2867 if (currEl && fillEl !== currEl && this[currEl]) {
2868 Dom.setStyle(this[currEl], height, "");
2872 fillEl = Lang.trim(fillEl.toLowerCase());
2874 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
2875 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
2876 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
2878 cfg.setProperty(autoFillHeight, fillEl, true);
2883 * The default event handler fired when the "width" property is changed.
2884 * @method configWidth
2885 * @param {String} type The CustomEvent type (usually the property name)
2886 * @param {Object[]} args The CustomEvent arguments. For configuration
2887 * handlers, args[0] will equal the newly applied value for the property.
2888 * @param {Object} obj The scope object. For configuration handlers,
2889 * this will usually equal the owner.
2891 configWidth: function (type, args, obj) {
2893 var width = args[0],
2896 Dom.setStyle(el, "width", width);
2897 this.cfg.refireEvent("iframe");
2901 * The default event handler fired when the "zIndex" property is changed.
2902 * @method configzIndex
2903 * @param {String} type The CustomEvent type (usually the property name)
2904 * @param {Object[]} args The CustomEvent arguments. For configuration
2905 * handlers, args[0] will equal the newly applied value for the property.
2906 * @param {Object} obj The scope object. For configuration handlers,
2907 * this will usually equal the owner.
2909 configzIndex: function (type, args, obj) {
2911 var zIndex = args[0],
2915 zIndex = Dom.getStyle(el, "zIndex");
2916 if (! zIndex || isNaN(zIndex)) {
2921 if (this.iframe || this.cfg.getProperty("iframe") === true) {
2927 Dom.setStyle(el, "zIndex", zIndex);
2928 this.cfg.setProperty("zIndex", zIndex, true);
2936 * The default event handler fired when the "xy" property is changed.
2938 * @param {String} type The CustomEvent type (usually the property name)
2939 * @param {Object[]} args The CustomEvent arguments. For configuration
2940 * handlers, args[0] will equal the newly applied value for the property.
2941 * @param {Object} obj The scope object. For configuration handlers,
2942 * this will usually equal the owner.
2944 configXY: function (type, args, obj) {
2950 this.cfg.setProperty("x", x);
2951 this.cfg.setProperty("y", y);
2953 this.beforeMoveEvent.fire([x, y]);
2955 x = this.cfg.getProperty("x");
2956 y = this.cfg.getProperty("y");
2959 this.cfg.refireEvent("iframe");
2960 this.moveEvent.fire([x, y]);
2964 * The default event handler fired when the "x" property is changed.
2966 * @param {String} type The CustomEvent type (usually the property name)
2967 * @param {Object[]} args The CustomEvent arguments. For configuration
2968 * handlers, args[0] will equal the newly applied value for the property.
2969 * @param {Object} obj The scope object. For configuration handlers,
2970 * this will usually equal the owner.
2972 configX: function (type, args, obj) {
2975 y = this.cfg.getProperty("y");
2977 this.cfg.setProperty("x", x, true);
2978 this.cfg.setProperty("y", y, true);
2980 this.beforeMoveEvent.fire([x, y]);
2982 x = this.cfg.getProperty("x");
2983 y = this.cfg.getProperty("y");
2985 Dom.setX(this.element, x, true);
2987 this.cfg.setProperty("xy", [x, y], true);
2989 this.cfg.refireEvent("iframe");
2990 this.moveEvent.fire([x, y]);
2994 * The default event handler fired when the "y" property is changed.
2996 * @param {String} type The CustomEvent type (usually the property name)
2997 * @param {Object[]} args The CustomEvent arguments. For configuration
2998 * handlers, args[0] will equal the newly applied value for the property.
2999 * @param {Object} obj The scope object. For configuration handlers,
3000 * this will usually equal the owner.
3002 configY: function (type, args, obj) {
3004 var x = this.cfg.getProperty("x"),
3007 this.cfg.setProperty("x", x, true);
3008 this.cfg.setProperty("y", y, true);
3010 this.beforeMoveEvent.fire([x, y]);
3012 x = this.cfg.getProperty("x");
3013 y = this.cfg.getProperty("y");
3015 Dom.setY(this.element, y, true);
3017 this.cfg.setProperty("xy", [x, y], true);
3019 this.cfg.refireEvent("iframe");
3020 this.moveEvent.fire([x, y]);
3024 * Shows the iframe shim, if it has been enabled.
3025 * @method showIframe
3027 showIframe: function () {
3029 var oIFrame = this.iframe,
3033 oParentNode = this.element.parentNode;
3035 if (oParentNode != oIFrame.parentNode) {
3036 this._addToParent(oParentNode, oIFrame);
3038 oIFrame.style.display = "block";
3043 * Hides the iframe shim, if it has been enabled.
3044 * @method hideIframe
3046 hideIframe: function () {
3048 this.iframe.style.display = "none";
3053 * Syncronizes the size and position of iframe shim to that of its
3054 * corresponding Overlay instance.
3055 * @method syncIframe
3057 syncIframe: function () {
3059 var oIFrame = this.iframe,
3060 oElement = this.element,
3061 nOffset = Overlay.IFRAME_OFFSET,
3062 nDimensionOffset = (nOffset * 2),
3067 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3068 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3070 // Position <iframe>
3071 aXY = this.cfg.getProperty("xy");
3073 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3074 this.syncPosition();
3075 aXY = this.cfg.getProperty("xy");
3077 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3082 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3083 * the Overlay element. The zindex of the iframe is set to be one less
3084 * than the Overlay element's zindex.
3086 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3087 * to ensure that the iframe shim has a non-negative zindex.
3088 * If you require the iframe zindex to be 0 or higher, the zindex of
3089 * the Overlay element should be set to a value greater than 0, before
3090 * this method is called.
3092 * @method stackIframe
3094 stackIframe: function () {
3096 var overlayZ = Dom.getStyle(this.element, "zIndex");
3097 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3098 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3104 * The default event handler fired when the "iframe" property is changed.
3105 * @method configIframe
3106 * @param {String} type The CustomEvent type (usually the property name)
3107 * @param {Object[]} args The CustomEvent arguments. For configuration
3108 * handlers, args[0] will equal the newly applied value for the property.
3109 * @param {Object} obj The scope object. For configuration handlers,
3110 * this will usually equal the owner.
3112 configIframe: function (type, args, obj) {
3114 var bIFrame = args[0];
3116 function createIFrame() {
3118 var oIFrame = this.iframe,
3119 oElement = this.element,
3123 if (!m_oIFrameTemplate) {
3124 m_oIFrameTemplate = document.createElement("iframe");
3126 if (this.isSecure) {
3127 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3131 Set the opacity of the <iframe> to 0 so that it
3132 doesn't modify the opacity of any transparent
3133 elements that may be on top of it (like a shadow).
3136 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3138 Need to set the "frameBorder" property to 0
3139 supress the default <iframe> border in IE.
3140 Setting the CSS "border" property alone
3143 m_oIFrameTemplate.frameBorder = 0;
3146 m_oIFrameTemplate.style.opacity = "0";
3149 m_oIFrameTemplate.style.position = "absolute";
3150 m_oIFrameTemplate.style.border = "none";
3151 m_oIFrameTemplate.style.margin = "0";
3152 m_oIFrameTemplate.style.padding = "0";
3153 m_oIFrameTemplate.style.display = "none";
3154 m_oIFrameTemplate.tabIndex = -1;
3157 oIFrame = m_oIFrameTemplate.cloneNode(false);
3158 oParent = oElement.parentNode;
3160 var parentNode = oParent || document.body;
3162 this._addToParent(parentNode, oIFrame);
3163 this.iframe = oIFrame;
3167 Show the <iframe> before positioning it since the "setXY"
3168 method of DOM requires the element be in the document
3174 Syncronize the size and position of the <iframe> to that
3180 // Add event listeners to update the <iframe> when necessary
3181 if (!this._hasIframeEventListeners) {
3182 this.showEvent.subscribe(this.showIframe);
3183 this.hideEvent.subscribe(this.hideIframe);
3184 this.changeContentEvent.subscribe(this.syncIframe);
3186 this._hasIframeEventListeners = true;
3190 function onBeforeShow() {
3191 createIFrame.call(this);
3192 this.beforeShowEvent.unsubscribe(onBeforeShow);
3193 this._iframeDeferred = false;
3196 if (bIFrame) { // <iframe> shim is enabled
3198 if (this.cfg.getProperty("visible")) {
3199 createIFrame.call(this);
3201 if (!this._iframeDeferred) {
3202 this.beforeShowEvent.subscribe(onBeforeShow);
3203 this._iframeDeferred = true;
3207 } else { // <iframe> shim is disabled
3210 if (this._hasIframeEventListeners) {
3211 this.showEvent.unsubscribe(this.showIframe);
3212 this.hideEvent.unsubscribe(this.hideIframe);
3213 this.changeContentEvent.unsubscribe(this.syncIframe);
3215 this._hasIframeEventListeners = false;
3221 * Set's the container's XY value from DOM if not already set.
3223 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3224 * not already set. The method also refire's the XY config property event, so any
3225 * beforeMove, Move event listeners are invoked.
3227 * @method _primeXYFromDOM
3230 _primeXYFromDOM : function() {
3231 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3232 // Set CFG XY based on DOM XY
3233 this.syncPosition();
3234 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3235 this.cfg.refireEvent("xy");
3236 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3241 * The default event handler fired when the "constraintoviewport"
3242 * property is changed.
3243 * @method configConstrainToViewport
3244 * @param {String} type The CustomEvent type (usually the property name)
3245 * @param {Object[]} args The CustomEvent arguments. For configuration
3246 * handlers, args[0] will equal the newly applied value for
3248 * @param {Object} obj The scope object. For configuration handlers,
3249 * this will usually equal the owner.
3251 configConstrainToViewport: function (type, args, obj) {
3255 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3256 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3258 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3259 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3262 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3263 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3268 * The default event handler fired when the "context" property
3271 * @method configContext
3272 * @param {String} type The CustomEvent type (usually the property name)
3273 * @param {Object[]} args The CustomEvent arguments. For configuration
3274 * handlers, args[0] will equal the newly applied value for the property.
3275 * @param {Object} obj The scope object. For configuration handlers,
3276 * this will usually equal the owner.
3278 configContext: function (type, args, obj) {
3280 var contextArgs = args[0],
3282 elementMagnetCorner,
3283 contextMagnetCorner,
3285 defTriggers = this.CONTEXT_TRIGGERS;
3289 contextEl = contextArgs[0];
3290 elementMagnetCorner = contextArgs[1];
3291 contextMagnetCorner = contextArgs[2];
3292 triggers = contextArgs[3];
3294 if (defTriggers && defTriggers.length > 0) {
3295 triggers = (triggers || []).concat(defTriggers);
3299 if (typeof contextEl == "string") {
3300 this.cfg.setProperty("context", [
3301 document.getElementById(contextEl),
3302 elementMagnetCorner,
3303 contextMagnetCorner,
3308 if (elementMagnetCorner && contextMagnetCorner) {
3309 this.align(elementMagnetCorner, contextMagnetCorner);
3312 if (this._contextTriggers) {
3313 // Unsubscribe Old Set
3314 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3318 // Subscribe New Set
3319 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3320 this._contextTriggers = triggers;
3327 * Custom Event handler for context alignment triggers. Invokes the align method
3329 * @method _alignOnTrigger
3332 * @param {String} type The event type (not used by the default implementation)
3333 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3335 _alignOnTrigger: function(type, args) {
3340 * Helper method to locate the custom event instance for the event name string
3341 * passed in. As a convenience measure, any custom events passed in are returned.
3343 * @method _findTriggerCE
3346 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3347 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3349 _findTriggerCE : function(t) {
3351 if (t instanceof CustomEvent) {
3353 } else if (Overlay._TRIGGER_MAP[t]) {
3354 tce = Overlay._TRIGGER_MAP[t];
3360 * Utility method that subscribes or unsubscribes the given
3361 * function from the list of trigger events provided.
3363 * @method _processTriggers
3366 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3367 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3368 * subscribed/unsubscribed respectively.
3370 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3371 * we are subscribing or unsubscribing trigger listeners
3373 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3374 * Context is always set to the overlay instance, and no additional object argument
3375 * get passed to the subscribed function.
3377 _processTriggers : function(triggers, mode, fn) {
3380 for (var i = 0, l = triggers.length; i < l; ++i) {
3382 tce = this._findTriggerCE(t);
3384 tce[mode](fn, this, true);
3391 // END BUILT-IN PROPERTY EVENT HANDLERS //
3393 * Aligns the Overlay to its context element using the specified corner
3394 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3397 * @param {String} elementAlign The String representing the corner of
3398 * the Overlay that should be aligned to the context element
3399 * @param {String} contextAlign The corner of the context element
3400 * that the elementAlign corner should stick to.
3402 align: function (elementAlign, contextAlign) {
3404 var contextArgs = this.cfg.getProperty("context"),
3410 function doAlign(v, h) {
3412 switch (elementAlign) {
3414 case Overlay.TOP_LEFT:
3418 case Overlay.TOP_RIGHT:
3419 me.moveTo((h - element.offsetWidth), v);
3422 case Overlay.BOTTOM_LEFT:
3423 me.moveTo(h, (v - element.offsetHeight));
3426 case Overlay.BOTTOM_RIGHT:
3427 me.moveTo((h - element.offsetWidth),
3428 (v - element.offsetHeight));
3436 context = contextArgs[0];
3437 element = this.element;
3440 if (! elementAlign) {
3441 elementAlign = contextArgs[1];
3444 if (! contextAlign) {
3445 contextAlign = contextArgs[2];
3448 if (element && context) {
3449 contextRegion = Dom.getRegion(context);
3451 switch (contextAlign) {
3453 case Overlay.TOP_LEFT:
3454 doAlign(contextRegion.top, contextRegion.left);
3457 case Overlay.TOP_RIGHT:
3458 doAlign(contextRegion.top, contextRegion.right);
3461 case Overlay.BOTTOM_LEFT:
3462 doAlign(contextRegion.bottom, contextRegion.left);
3465 case Overlay.BOTTOM_RIGHT:
3466 doAlign(contextRegion.bottom, contextRegion.right);
3477 * The default event handler executed when the moveEvent is fired, if the
3478 * "constraintoviewport" is set to true.
3479 * @method enforceConstraints
3480 * @param {String} type The CustomEvent type (usually the property name)
3481 * @param {Object[]} args The CustomEvent arguments. For configuration
3482 * handlers, args[0] will equal the newly applied value for the property.
3483 * @param {Object} obj The scope object. For configuration handlers,
3484 * this will usually equal the owner.
3486 enforceConstraints: function (type, args, obj) {
3489 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3490 this.cfg.setProperty("x", cXY[0], true);
3491 this.cfg.setProperty("y", cXY[1], true);
3492 this.cfg.setProperty("xy", cXY, true);
3497 * Given x coordinate value, returns the calculated x coordinate required to
3498 * position the Overlay if it is to be constrained to the viewport, based on the
3499 * current element size, viewport dimensions and scroll values.
3501 * @param {Number} x The X coordinate value to be constrained
3502 * @return {Number} The constrained x coordinate
3504 getConstrainedX: function (x) {
3506 var oOverlay = this,
3507 oOverlayEl = oOverlay.element,
3508 nOverlayOffsetWidth = oOverlayEl.offsetWidth,
3510 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3511 viewPortWidth = Dom.getViewportWidth(),
3512 scrollX = Dom.getDocumentScrollLeft(),
3514 bCanConstrain = (nOverlayOffsetWidth + nViewportOffset < viewPortWidth),
3516 aContext = this.cfg.getProperty("context"),
3526 leftConstraint = scrollX + nViewportOffset,
3527 rightConstraint = scrollX + viewPortWidth - nOverlayOffsetWidth - nViewportOffset,
3531 oOverlapPositions = {
3541 var flipHorizontal = function () {
3545 if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
3546 nNewX = (nContextElX - nOverlayOffsetWidth);
3549 nNewX = (nContextElX + nContextElWidth);
3553 oOverlay.cfg.setProperty("x", (nNewX + scrollX), true);
3562 Uses the context element's position to calculate the availble width
3563 to the right and left of it to display its corresponding Overlay.
3566 var getDisplayRegionWidth = function () {
3568 // The Overlay is to the right of the context element
3570 if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
3571 return (nRightRegionWidth - nViewportOffset);
3573 else { // The Overlay is to the left of the context element
3574 return (nLeftRegionWidth - nViewportOffset);
3581 Positions the Overlay to the left or right of the context element so that it remains
3582 inside the viewport.
3585 var setHorizontalPosition = function () {
3587 var nDisplayRegionWidth = getDisplayRegionWidth(),
3590 if (nOverlayOffsetWidth > nDisplayRegionWidth) {
3595 All possible positions and values have been
3596 tried, but none were successful, so fall back
3597 to the original size and position.
3609 fnReturnVal = setHorizontalPosition();
3619 // Determine if the current value for the Overlay's "x" configuration property will
3620 // result in the Overlay being positioned outside the boundaries of the viewport
3622 if (x < leftConstraint || x > rightConstraint) {
3624 // The current value for the Overlay's "x" configuration property WILL
3625 // result in the Overlay being positioned outside the boundaries of the viewport
3627 if (bCanConstrain) {
3629 // If the "preventcontextoverlap" configuration property is set to "true",
3630 // try to flip the Overlay to both keep it inside the boundaries of the
3631 // viewport AND from overlaping its context element.
3633 if (this.cfg.getProperty("preventcontextoverlap") && aContext &&
3634 oOverlapPositions[(aContext[1] + aContext[2])]) {
3636 oContextEl = aContext[0];
3637 nContextElX = Dom.getX(oContextEl) - scrollX;
3638 nContextElWidth = oContextEl.offsetWidth;
3639 nLeftRegionWidth = nContextElX;
3640 nRightRegionWidth = (viewPortWidth - (nContextElX + nContextElWidth));
3642 setHorizontalPosition();
3644 xNew = this.cfg.getProperty("x");
3649 if (x < leftConstraint) {
3650 xNew = leftConstraint;
3651 } else if (x > rightConstraint) {
3652 xNew = rightConstraint;
3658 // The "x" configuration property cannot be set to a value that will keep
3659 // entire Overlay inside the boundary of the viewport. Therefore, set
3660 // the "x" configuration property to scrollY to keep as much of the
3661 // Overlay inside the viewport as possible.
3662 xNew = nViewportOffset + scrollX;
3673 * Given y coordinate value, returns the calculated y coordinate required to
3674 * position the Overlay if it is to be constrained to the viewport, based on the
3675 * current element size, viewport dimensions and scroll values.
3677 * @param {Number} y The Y coordinate value to be constrained
3678 * @return {Number} The constrained y coordinate
3680 getConstrainedY: function (y) {
3682 var oOverlay = this,
3683 oOverlayEl = oOverlay.element,
3684 nOverlayOffsetHeight = oOverlayEl.offsetHeight,
3686 nViewportOffset = Overlay.VIEWPORT_OFFSET,
3687 viewPortHeight = Dom.getViewportHeight(),
3688 scrollY = Dom.getDocumentScrollTop(),
3690 bCanConstrain = (nOverlayOffsetHeight + nViewportOffset < viewPortHeight),
3692 aContext = this.cfg.getProperty("context"),
3700 nBottomRegionHeight,
3702 topConstraint = scrollY + nViewportOffset,
3703 bottomConstraint = scrollY + viewPortHeight - nOverlayOffsetHeight - nViewportOffset,
3707 oOverlapPositions = {
3715 var flipVertical = function () {
3719 // The Overlay is below the context element, flip it above
3720 if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
3721 nNewY = (nContextElY - nOverlayOffsetHeight);
3723 else { // The Overlay is above the context element, flip it below
3724 nNewY = (nContextElY + nContextElHeight);
3727 oOverlay.cfg.setProperty("y", (nNewY + scrollY), true);
3735 Uses the context element's position to calculate the availble height
3736 above and below it to display its corresponding Overlay.
3739 var getDisplayRegionHeight = function () {
3741 // The Overlay is below the context element
3742 if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
3743 return (nBottomRegionHeight - nViewportOffset);
3745 else { // The Overlay is above the context element
3746 return (nTopRegionHeight - nViewportOffset);
3753 Trys to place the Overlay in the best possible position (either above or
3754 below its corresponding context element).
3757 var setVerticalPosition = function () {
3759 var nDisplayRegionHeight = getDisplayRegionHeight(),
3763 if (nOverlayOffsetHeight > nDisplayRegionHeight) {
3768 All possible positions and values for the
3769 "maxheight" configuration property have been
3770 tried, but none were successful, so fall back
3771 to the original size and position.
3783 fnReturnVal = setVerticalPosition();
3794 // Determine if the current value for the Overlay's "y" configuration property will
3795 // result in the Overlay being positioned outside the boundaries of the viewport
3797 if (y < topConstraint || y > bottomConstraint) {
3799 // The current value for the Overlay's "y" configuration property WILL
3800 // result in the Overlay being positioned outside the boundaries of the viewport
3802 if (bCanConstrain) {
3804 // If the "preventcontextoverlap" configuration property is set to "true",
3805 // try to flip the Overlay to both keep it inside the boundaries of the
3806 // viewport AND from overlaping its context element.
3808 if (this.cfg.getProperty("preventcontextoverlap") && aContext &&
3809 oOverlapPositions[(aContext[1] + aContext[2])]) {
3811 oContextEl = aContext[0];
3812 nContextElHeight = oContextEl.offsetHeight;
3813 nContextElY = (Dom.getY(oContextEl) - scrollY);
3815 nTopRegionHeight = nContextElY;
3816 nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
3818 setVerticalPosition();
3820 yNew = oOverlay.cfg.getProperty("y");
3825 if (y < topConstraint) {
3826 yNew = topConstraint;
3827 } else if (y > bottomConstraint) {
3828 yNew = bottomConstraint;
3836 // The "y" configuration property cannot be set to a value that will keep
3837 // entire Overlay inside the boundary of the viewport. Therefore, set
3838 // the "y" configuration property to scrollY to keep as much of the
3839 // Overlay inside the viewport as possible.
3841 yNew = nViewportOffset + scrollY;
3851 * Given x, y coordinate values, returns the calculated coordinates required to
3852 * position the Overlay if it is to be constrained to the viewport, based on the
3853 * current element size, viewport dimensions and scroll values.
3855 * @param {Number} x The X coordinate value to be constrained
3856 * @param {Number} y The Y coordinate value to be constrained
3857 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3859 getConstrainedXY: function(x, y) {
3860 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3864 * Centers the container in the viewport.
3867 center: function () {
3869 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3870 elementWidth = this.element.offsetWidth,
3871 elementHeight = this.element.offsetHeight,
3872 viewPortWidth = Dom.getViewportWidth(),
3873 viewPortHeight = Dom.getViewportHeight(),
3877 if (elementWidth < viewPortWidth) {
3878 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3880 x = nViewportOffset + Dom.getDocumentScrollLeft();
3883 if (elementHeight < viewPortHeight) {
3884 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3886 y = nViewportOffset + Dom.getDocumentScrollTop();
3889 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3890 this.cfg.refireEvent("iframe");
3893 this.forceContainerRedraw();
3898 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3899 * Panel's position in the DOM. This is primarily used to update
3900 * position information during drag & drop.
3901 * @method syncPosition
3903 syncPosition: function () {
3905 var pos = Dom.getXY(this.element);
3907 this.cfg.setProperty("x", pos[0], true);
3908 this.cfg.setProperty("y", pos[1], true);
3909 this.cfg.setProperty("xy", pos, true);
3914 * Event handler fired when the resize monitor element is resized.
3915 * @method onDomResize
3916 * @param {DOMEvent} e The resize DOM event
3917 * @param {Object} obj The scope object
3919 onDomResize: function (e, obj) {
3923 Overlay.superclass.onDomResize.call(this, e, obj);
3925 setTimeout(function () {
3927 me.cfg.refireEvent("iframe");
3928 me.cfg.refireEvent("context");
3933 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3935 * @method _getComputedHeight
3937 * @param {HTMLElement} el The element for which the content height needs to be determined
3938 * @return {Number} The content box height of the given element, or null if it could not be determined.
3940 _getComputedHeight : (function() {
3942 if (document.defaultView && document.defaultView.getComputedStyle) {
3943 return function(el) {
3945 if (el.ownerDocument && el.ownerDocument.defaultView) {
3946 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3948 height = parseInt(computed.height, 10);
3951 return (Lang.isNumber(height)) ? height : null;
3954 return function(el) {
3956 if (el.style.pixelHeight) {
3957 height = el.style.pixelHeight;
3959 return (Lang.isNumber(height)) ? height : null;
3965 * autofillheight validator. Verifies that the autofill value is either null
3966 * or one of the strings : "body", "header" or "footer".
3968 * @method _validateAutoFillHeight
3970 * @param {String} val
3971 * @return true, if valid, false otherwise
3973 _validateAutoFillHeight : function(val) {
3974 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3978 * The default custom event handler executed when the overlay's height is changed,
3979 * if the autofillheight property has been set.
3981 * @method _autoFillOnHeightChange
3983 * @param {String} type The event type
3984 * @param {Array} args The array of arguments passed to event subscribers
3985 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3986 * out the containers height
3988 _autoFillOnHeightChange : function(type, args, el) {
3989 var height = this.cfg.getProperty("height");
3990 if ((height && height !== "auto") || (height === 0)) {
3991 this.fillHeight(el);
3996 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3997 * otherwise returns the offsetHeight
3998 * @method _getPreciseHeight
4000 * @param {HTMLElement} el
4001 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
4003 _getPreciseHeight : function(el) {
4004 var height = el.offsetHeight;
4006 if (el.getBoundingClientRect) {
4007 var rect = el.getBoundingClientRect();
4008 height = rect.bottom - rect.top;
4016 * Sets the height on the provided header, body or footer element to
4017 * fill out the height of the container. It determines the height of the
4018 * containers content box, based on it's configured height value, and
4019 * sets the height of the autofillheight element to fill out any
4020 * space remaining after the other standard module element heights
4021 * have been accounted for.
4023 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
4024 * height has not been set on the container, since for an "auto" height container,
4025 * the heights of the header/body/footer will drive the height of the container.</p>
4027 * @method fillHeight
4028 * @param {HTMLElement} el The element which should be resized to fill out the height
4029 * of the container element.
4031 fillHeight : function(el) {
4033 var container = this.innerElement || this.element,
4034 containerEls = [this.header, this.body, this.footer],
4041 for (var i = 0, l = containerEls.length; i < l; i++) {
4042 containerEl = containerEls[i];
4044 if (el !== containerEl) {
4045 filled += this._getPreciseHeight(containerEl);
4054 if (UA.ie || UA.opera) {
4055 // Need to set height to 0, to allow height to be reduced
4056 Dom.setStyle(el, 'height', 0 + 'px');
4059 total = this._getComputedHeight(container);
4061 // Fallback, if we can't get computed value for content height
4062 if (total === null) {
4063 Dom.addClass(container, "yui-override-padding");
4064 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4065 Dom.removeClass(container, "yui-override-padding");
4068 remaining = Math.max(total - filled, 0);
4070 Dom.setStyle(el, "height", remaining + "px");
4072 // Re-adjust height if required, to account for el padding and border
4073 if (el.offsetHeight != remaining) {
4074 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4076 Dom.setStyle(el, "height", remaining + "px");
4082 * Places the Overlay on top of all other instances of
4083 * YAHOO.widget.Overlay.
4084 * @method bringToTop
4086 bringToTop: function () {
4089 oElement = this.element;
4091 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4093 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4094 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4096 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4097 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4099 if (nZIndex1 > nZIndex2) {
4101 } else if (nZIndex1 < nZIndex2) {
4108 function isOverlayElement(p_oElement) {
4110 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4111 Panel = YAHOO.widget.Panel;
4113 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4114 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4115 aOverlays[aOverlays.length] = p_oElement.parentNode;
4117 aOverlays[aOverlays.length] = p_oElement;
4122 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
4124 aOverlays.sort(compareZIndexDesc);
4126 var oTopOverlay = aOverlays[0],
4130 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4132 if (!isNaN(nTopZIndex)) {
4133 var bRequiresBump = false;
4135 if (oTopOverlay != oElement) {
4136 bRequiresBump = true;
4137 } else if (aOverlays.length > 1) {
4138 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4139 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4140 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4141 bRequiresBump = true;
4144 if (bRequiresBump) {
4145 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4152 * Removes the Overlay element from the DOM and sets all child
4156 destroy: function () {
4159 this.iframe.parentNode.removeChild(this.iframe);
4164 Overlay.windowResizeEvent.unsubscribe(
4165 this.doCenterOnDOMEvent, this);
4167 Overlay.windowScrollEvent.unsubscribe(
4168 this.doCenterOnDOMEvent, this);
4170 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4172 Overlay.superclass.destroy.call(this);
4176 * Can be used to force the container to repaint/redraw it's contents.
4178 * By default applies and then removes a 1px bottom margin through the
4179 * application/removal of a "yui-force-redraw" class.
4182 * It is currently used by Overlay to force a repaint for webkit
4183 * browsers, when centering.
4185 * @method forceContainerRedraw
4187 forceContainerRedraw : function() {
4189 Dom.addClass(c.element, "yui-force-redraw");
4190 setTimeout(function() {
4191 Dom.removeClass(c.element, "yui-force-redraw");
4196 * Returns a String representation of the object.
4198 * @return {String} The string representation of the Overlay.
4200 toString: function () {
4201 return "Overlay " + this.id;
4210 * OverlayManager is used for maintaining the focus status of
4211 * multiple Overlays.
4212 * @namespace YAHOO.widget
4213 * @namespace YAHOO.widget
4214 * @class OverlayManager
4216 * @param {Array} overlays Optional. A collection of Overlays to register
4218 * @param {Object} userConfig The object literal representing the user
4219 * configuration of the OverlayManager
4221 YAHOO.widget.OverlayManager = function (userConfig) {
4222 this.init(userConfig);
4225 var Overlay = YAHOO.widget.Overlay,
4226 Event = YAHOO.util.Event,
4227 Dom = YAHOO.util.Dom,
4228 Config = YAHOO.util.Config,
4229 CustomEvent = YAHOO.util.CustomEvent,
4230 OverlayManager = YAHOO.widget.OverlayManager;
4233 * The CSS class representing a focused Overlay
4234 * @property OverlayManager.CSS_FOCUSED
4239 OverlayManager.CSS_FOCUSED = "focused";
4241 OverlayManager.prototype = {
4244 * The class's constructor function
4245 * @property contructor
4248 constructor: OverlayManager,
4251 * The array of Overlays that are currently registered
4252 * @property overlays
4253 * @type YAHOO.widget.Overlay[]
4258 * Initializes the default configuration of the OverlayManager
4259 * @method initDefaultConfig
4261 initDefaultConfig: function () {
4263 * The collection of registered Overlays in use by
4264 * the OverlayManager
4266 * @type YAHOO.widget.Overlay[]
4269 this.cfg.addProperty("overlays", { suppressEvent: true } );
4272 * The default DOM event that should be used to focus an Overlay
4273 * @config focusevent
4275 * @default "mousedown"
4277 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4281 * Initializes the OverlayManager
4283 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4284 * register with the manager.
4285 * @param {Object} userConfig The object literal representing the user
4286 * configuration of the OverlayManager
4288 init: function (userConfig) {
4291 * The OverlayManager's Config object used for monitoring
4292 * configuration properties.
4296 this.cfg = new Config(this);
4298 this.initDefaultConfig();
4301 this.cfg.applyConfig(userConfig, true);
4303 this.cfg.fireQueue();
4306 * The currently activated Overlay
4307 * @property activeOverlay
4309 * @type YAHOO.widget.Overlay
4311 var activeOverlay = null;
4314 * Returns the currently focused Overlay
4316 * @return {Overlay} The currently focused Overlay
4318 this.getActive = function () {
4319 return activeOverlay;
4323 * Focuses the specified Overlay
4325 * @param {Overlay} overlay The Overlay to focus
4326 * @param {String} overlay The id of the Overlay to focus
4328 this.focus = function (overlay) {
4329 var o = this.find(overlay);
4336 * Removes the specified Overlay from the manager
4338 * @param {Overlay} overlay The Overlay to remove
4339 * @param {String} overlay The id of the Overlay to remove
4341 this.remove = function (overlay) {
4343 var o = this.find(overlay),
4347 if (activeOverlay == o) {
4348 activeOverlay = null;
4351 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4354 // Set it's zindex so that it's sorted to the end.
4355 originalZ = Dom.getStyle(o.element, "zIndex");
4356 o.cfg.setProperty("zIndex", -1000, true);
4359 this.overlays.sort(this.compareZIndexDesc);
4360 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4362 o.hideEvent.unsubscribe(o.blur);
4363 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4364 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4365 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4368 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4369 o.cfg.setProperty("zIndex", originalZ, true);
4370 o.cfg.setProperty("manager", null);
4373 /* _managed Flag for custom or existing. Don't want to remove existing */
4374 if (o.focusEvent._managed) { o.focusEvent = null; }
4375 if (o.blurEvent._managed) { o.blurEvent = null; }
4377 if (o.focus._managed) { o.focus = null; }
4378 if (o.blur._managed) { o.blur = null; }
4383 * Removes focus from all registered Overlays in the manager
4386 this.blurAll = function () {
4388 var nOverlays = this.overlays.length,
4391 if (nOverlays > 0) {
4394 this.overlays[i].blur();
4401 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4404 * @method _manageBlur
4405 * @param {Overlay} overlay The overlay instance which got blurred.
4408 this._manageBlur = function (overlay) {
4409 var changed = false;
4410 if (activeOverlay == overlay) {
4411 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4412 activeOverlay = null;
4419 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4422 * @method _manageFocus
4423 * @param {Overlay} overlay The overlay instance which got focus.
4426 this._manageFocus = function(overlay) {
4427 var changed = false;
4428 if (activeOverlay != overlay) {
4429 if (activeOverlay) {
4430 activeOverlay.blur();
4432 activeOverlay = overlay;
4433 this.bringToTop(activeOverlay);
4434 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4440 var overlays = this.cfg.getProperty("overlays");
4442 if (! this.overlays) {
4447 this.register(overlays);
4448 this.overlays.sort(this.compareZIndexDesc);
4453 * @method _onOverlayElementFocus
4454 * @description Event handler for the DOM event that is used to focus
4455 * the Overlay instance as specified by the "focusevent"
4456 * configuration property.
4458 * @param {Event} p_oEvent Object representing the DOM event
4459 * object passed back by the event utility (Event).
4461 _onOverlayElementFocus: function (p_oEvent) {
4463 var oTarget = Event.getTarget(p_oEvent),
4464 oClose = this.close;
4466 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4474 * @method _onOverlayDestroy
4475 * @description "destroy" event handler for the Overlay.
4477 * @param {String} p_sType String representing the name of the event
4479 * @param {Array} p_aArgs Array of arguments sent when the event
4481 * @param {Overlay} p_oOverlay Object representing the overlay that
4484 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4485 this.remove(p_oOverlay);
4489 * @method _onOverlayFocusHandler
4491 * focusEvent Handler, used to delegate to _manageFocus with the
4492 * correct arguments.
4495 * @param {String} p_sType String representing the name of the event
4497 * @param {Array} p_aArgs Array of arguments sent when the event
4499 * @param {Overlay} p_oOverlay Object representing the overlay that
4502 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4503 this._manageFocus(p_oOverlay);
4507 * @method _onOverlayBlurHandler
4509 * blurEvent Handler, used to delegate to _manageBlur with the
4510 * correct arguments.
4513 * @param {String} p_sType String representing the name of the event
4515 * @param {Array} p_aArgs Array of arguments sent when the event
4517 * @param {Overlay} p_oOverlay Object representing the overlay that
4520 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4521 this._manageBlur(p_oOverlay);
4525 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4526 * monitor focus state.
4528 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4529 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4530 * on the instance, the _bindFocus method will add them, and the focus method will
4531 * update the OverlayManager's state directly.
4533 * @method _bindFocus
4534 * @param {Overlay} overlay The overlay for which focus needs to be managed
4537 _bindFocus : function(overlay) {
4540 if (!overlay.focusEvent) {
4541 overlay.focusEvent = overlay.createEvent("focus");
4542 overlay.focusEvent.signature = CustomEvent.LIST;
4543 overlay.focusEvent._managed = true;
4545 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4548 if (!overlay.focus) {
4549 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4550 overlay.focus = function () {
4551 if (mgr._manageFocus(this)) {
4553 if (this.cfg.getProperty("visible") && this.focusFirst) {
4556 this.focusEvent.fire();
4559 overlay.focus._managed = true;
4564 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4565 * monitor blur state.
4567 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4568 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4569 * on the instance, the _bindBlur method will add them, and the blur method
4570 * update the OverlayManager's state directly.
4573 * @param {Overlay} overlay The overlay for which blur needs to be managed
4576 _bindBlur : function(overlay) {
4579 if (!overlay.blurEvent) {
4580 overlay.blurEvent = overlay.createEvent("blur");
4581 overlay.blurEvent.signature = CustomEvent.LIST;
4582 overlay.focusEvent._managed = true;
4584 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4587 if (!overlay.blur) {
4588 overlay.blur = function () {
4589 if (mgr._manageBlur(this)) {
4590 this.blurEvent.fire();
4593 overlay.blur._managed = true;
4596 overlay.hideEvent.subscribe(overlay.blur);
4600 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4601 * to be removed for the OverlayManager when destroyed.
4603 * @method _bindDestroy
4604 * @param {Overlay} overlay The overlay instance being managed
4607 _bindDestroy : function(overlay) {
4609 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4613 * Ensures the zIndex configuration property on the managed overlay based instance
4614 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4616 * @method _syncZIndex
4617 * @param {Overlay} overlay The overlay instance being managed
4620 _syncZIndex : function(overlay) {
4621 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4622 if (!isNaN(zIndex)) {
4623 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4625 overlay.cfg.setProperty("zIndex", 0);
4630 * Registers an Overlay or an array of Overlays with the manager. Upon
4631 * registration, the Overlay receives functions for focus and blur,
4632 * along with CustomEvents for each.
4635 * @param {Overlay} overlay An Overlay to register with the manager.
4636 * @param {Overlay[]} overlay An array of Overlays to register with
4638 * @return {boolean} true if any Overlays are registered.
4640 register: function (overlay) {
4642 var registered = false,
4646 if (overlay instanceof Overlay) {
4648 overlay.cfg.addProperty("manager", { value: this } );
4650 this._bindFocus(overlay);
4651 this._bindBlur(overlay);
4652 this._bindDestroy(overlay);
4653 this._syncZIndex(overlay);
4655 this.overlays.push(overlay);
4656 this.bringToTop(overlay);
4660 } else if (overlay instanceof Array) {
4662 for (i = 0, n = overlay.length; i < n; i++) {
4663 registered = this.register(overlay[i]) || registered;
4672 * Places the specified Overlay instance on top of all other
4673 * Overlay instances.
4674 * @method bringToTop
4675 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4677 * @param {String} p_oOverlay String representing the id of an
4680 bringToTop: function (p_oOverlay) {
4682 var oOverlay = this.find(p_oOverlay),
4689 aOverlays = this.overlays;
4690 aOverlays.sort(this.compareZIndexDesc);
4692 oTopOverlay = aOverlays[0];
4695 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4697 if (!isNaN(nTopZIndex)) {
4699 var bRequiresBump = false;
4701 if (oTopOverlay !== oOverlay) {
4702 bRequiresBump = true;
4703 } else if (aOverlays.length > 1) {
4704 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4705 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4706 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4707 bRequiresBump = true;
4711 if (bRequiresBump) {
4712 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4715 aOverlays.sort(this.compareZIndexDesc);
4721 * Attempts to locate an Overlay by instance or ID.
4723 * @param {Overlay} overlay An Overlay to locate within the manager
4724 * @param {String} overlay An Overlay id to locate within the manager
4725 * @return {Overlay} The requested Overlay, if found, or null if it
4726 * cannot be located.
4728 find: function (overlay) {
4730 var isInstance = overlay instanceof Overlay,
4731 overlays = this.overlays,
4732 n = overlays.length,
4737 if (isInstance || typeof overlay == "string") {
4738 for (i = n-1; i >= 0; i--) {
4740 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4751 * Used for sorting the manager's Overlays by z-index.
4752 * @method compareZIndexDesc
4754 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4755 * fall in the stacking order.
4757 compareZIndexDesc: function (o1, o2) {
4759 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4760 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4762 if (zIndex1 === null && zIndex2 === null) {
4764 } else if (zIndex1 === null){
4766 } else if (zIndex2 === null) {
4768 } else if (zIndex1 > zIndex2) {
4770 } else if (zIndex1 < zIndex2) {
4778 * Shows all Overlays in the manager.
4781 showAll: function () {
4782 var overlays = this.overlays,
4783 n = overlays.length,
4786 for (i = n - 1; i >= 0; i--) {
4792 * Hides all Overlays in the manager.
4795 hideAll: function () {
4796 var overlays = this.overlays,
4797 n = overlays.length,
4800 for (i = n - 1; i >= 0; i--) {
4806 * Returns a string representation of the object.
4808 * @return {String} The string representation of the OverlayManager
4810 toString: function () {
4811 return "OverlayManager";
4819 * Tooltip is an implementation of Overlay that behaves like an OS tooltip,
4820 * displaying when the user mouses over a particular element, and
4821 * disappearing on mouse out.
4822 * @namespace YAHOO.widget
4824 * @extends YAHOO.widget.Overlay
4826 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4827 * @param {HTMLElement} el The element representing the Tooltip
4828 * @param {Object} userConfig The configuration object literal containing
4829 * the configuration that should be set for this Overlay. See configuration
4830 * documentation for more details.
4832 YAHOO.widget.Tooltip = function (el, userConfig) {
4833 YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4836 var Lang = YAHOO.lang,
4837 Event = YAHOO.util.Event,
4838 CustomEvent = YAHOO.util.CustomEvent,
4839 Dom = YAHOO.util.Dom,
4840 Tooltip = YAHOO.widget.Tooltip,
4842 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
4847 * Constant representing the Tooltip's configuration properties
4848 * @property DEFAULT_CONFIG
4855 "PREVENT_OVERLAP": {
4856 key: "preventoverlap",
4858 validator: Lang.isBoolean,
4859 supercedes: ["x", "y", "xy"]
4865 validator: Lang.isNumber
4868 "AUTO_DISMISS_DELAY": {
4869 key: "autodismissdelay",
4871 validator: Lang.isNumber
4877 validator: Lang.isNumber
4897 * Constant representing the name of the Tooltip's events
4898 * @property EVENT_TYPES
4904 "CONTEXT_MOUSE_OVER": "contextMouseOver",
4905 "CONTEXT_MOUSE_OUT": "contextMouseOut",
4906 "CONTEXT_TRIGGER": "contextTrigger"
4910 * Constant representing the Tooltip CSS class
4911 * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4916 Tooltip.CSS_TOOLTIP = "yui-tt";
4918 function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
4920 var oConfig = this.cfg,
4921 sCurrentWidth = oConfig.getProperty("width");
4923 if (sCurrentWidth == sForcedWidth) {
4924 oConfig.setProperty("width", sOriginalWidth);
4929 changeContent event handler that sets a Tooltip instance's "width"
4930 configuration property to the value of its root HTML
4931 elements's offsetWidth if a specific width has not been set.
4934 function setWidthToOffsetWidth(p_sType, p_aArgs) {
4936 if ("_originalWidth" in this) {
4937 restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
4940 var oBody = document.body,
4942 sOriginalWidth = oConfig.getProperty("width"),
4946 if ((!sOriginalWidth || sOriginalWidth == "auto") &&
4947 (oConfig.getProperty("container") != oBody ||
4948 oConfig.getProperty("x") >= Dom.getViewportWidth() ||
4949 oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4951 oClone = this.element.cloneNode(true);
4952 oClone.style.visibility = "hidden";
4953 oClone.style.top = "0px";
4954 oClone.style.left = "0px";
4956 oBody.appendChild(oClone);
4958 sNewWidth = (oClone.offsetWidth + "px");
4960 oBody.removeChild(oClone);
4963 oConfig.setProperty("width", sNewWidth);
4964 oConfig.refireEvent("xy");
4966 this._originalWidth = sOriginalWidth || "";
4967 this._forcedWidth = sNewWidth;
4971 // "onDOMReady" that renders the ToolTip
4973 function onDOMReady(p_sType, p_aArgs, p_oObject) {
4974 this.render(p_oObject);
4977 // "init" event handler that automatically renders the Tooltip
4980 Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4983 YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
4986 * The Tooltip initialization method. This method is automatically
4987 * called by the constructor. A Tooltip is automatically rendered by
4988 * the init method, and it also is set to be invisible by default,
4989 * and constrained to viewport by default as well.
4991 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4992 * @param {HTMLElement} el The element representing the Tooltip
4993 * @param {Object} userConfig The configuration object literal
4994 * containing the configuration that should be set for this Tooltip.
4995 * See configuration documentation for more details.
4997 init: function (el, userConfig) {
5000 Tooltip.superclass.init.call(this, el);
5002 this.beforeInitEvent.fire(Tooltip);
5004 Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
5007 this.cfg.applyConfig(userConfig, true);
5010 this.cfg.queueProperty("visible", false);
5011 this.cfg.queueProperty("constraintoviewport", true);
5015 this.subscribe("changeContent", setWidthToOffsetWidth);
5016 this.subscribe("init", onInit);
5017 this.subscribe("render", this.onRender);
5019 this.initEvent.fire(Tooltip);
5023 * Initializes the custom events for Tooltip
5024 * @method initEvents
5026 initEvents: function () {
5028 Tooltip.superclass.initEvents.call(this);
5029 var SIGNATURE = CustomEvent.LIST;
5032 * CustomEvent fired when user mouses over a context element. Returning false from
5033 * a subscriber to this event will prevent the tooltip from being displayed for
5034 * the current context element.
5036 * @event contextMouseOverEvent
5037 * @param {HTMLElement} context The context element which the user just moused over
5038 * @param {DOMEvent} e The DOM event object, associated with the mouse over
5040 this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
5041 this.contextMouseOverEvent.signature = SIGNATURE;
5044 * CustomEvent fired when the user mouses out of a context element.
5046 * @event contextMouseOutEvent
5047 * @param {HTMLElement} context The context element which the user just moused out of
5048 * @param {DOMEvent} e The DOM event object, associated with the mouse out
5050 this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
5051 this.contextMouseOutEvent.signature = SIGNATURE;
5054 * CustomEvent fired just before the tooltip is displayed for the current context.
5056 * You can subscribe to this event if you need to set up the text for the
5057 * tooltip based on the context element for which it is about to be displayed.
5059 * <p>This event differs from the beforeShow event in following respects:</p>
5062 * When moving from one context element to another, if the tooltip is not
5063 * hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
5064 * be fired when the tooltip is displayed for the new context since it is already visible.
5065 * However the contextTrigger event is always fired before displaying the tooltip for
5069 * The trigger event provides access to the context element, allowing you to
5070 * set the text of the tooltip based on context element for which the tooltip is
5075 * It is not possible to prevent the tooltip from being displayed
5076 * using this event. You can use the contextMouseOverEvent if you need to prevent
5077 * the tooltip from being displayed.
5079 * @event contextTriggerEvent
5080 * @param {HTMLElement} context The context element for which the tooltip is triggered
5082 this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
5083 this.contextTriggerEvent.signature = SIGNATURE;
5087 * Initializes the class's configurable properties which can be
5088 * changed using the Overlay's Config object (cfg).
5089 * @method initDefaultConfig
5091 initDefaultConfig: function () {
5093 Tooltip.superclass.initDefaultConfig.call(this);
5096 * Specifies whether the Tooltip should be kept from overlapping
5097 * its context element.
5098 * @config preventoverlap
5102 this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
5103 value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
5104 validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
5105 supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
5109 * The number of milliseconds to wait before showing a Tooltip
5115 this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
5116 handler: this.configShowDelay,
5118 validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5122 * The number of milliseconds to wait before automatically
5123 * dismissing a Tooltip after the mouse has been resting on the
5125 * @config autodismissdelay
5129 this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
5130 handler: this.configAutoDismissDelay,
5131 value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
5132 validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
5136 * The number of milliseconds to wait before hiding a Tooltip
5142 this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
5143 handler: this.configHideDelay,
5144 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5145 validator: DEFAULT_CONFIG.HIDE_DELAY.validator
5149 * Specifies the Tooltip's text.
5154 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
5155 handler: this.configText,
5156 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
5160 * Specifies the container element that the Tooltip's markup
5161 * should be rendered into.
5163 * @type HTMLElement/String
5164 * @default document.body
5166 this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
5167 handler: this.configContainer,
5168 value: document.body
5172 * Specifies whether or not the tooltip is disabled. Disabled tooltips
5173 * will not be displayed. If the tooltip is driven by the title attribute
5174 * of the context element, the title attribute will still be removed for
5175 * disabled tooltips, to prevent default tooltip behavior.
5181 this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
5182 handler: this.configContainer,
5183 value: DEFAULT_CONFIG.DISABLED.value,
5184 supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5188 * Specifies the element or elements that the Tooltip should be
5189 * anchored to on mouseover.
5191 * @type HTMLElement[]/String[]
5196 * String representing the width of the Tooltip. <em>Please note:
5197 * </em> As of version 2.3 if either no value or a value of "auto"
5198 * is specified, and the Toolip's "container" configuration property
5199 * is set to something other than <code>document.body</code> or
5200 * its "context" element resides outside the immediately visible
5201 * portion of the document, the width of the Tooltip will be
5202 * calculated based on the offsetWidth of its root HTML and set just
5203 * before it is made visible. The original value will be
5204 * restored when the Tooltip is hidden. This ensures the Tooltip is
5205 * rendered at a usable width. For more information see
5206 * SourceForge bug #1685496 and SourceForge
5215 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5218 * The default event handler fired when the "text" property is changed.
5219 * @method configText
5220 * @param {String} type The CustomEvent type (usually the property name)
5221 * @param {Object[]} args The CustomEvent arguments. For configuration
5222 * handlers, args[0] will equal the newly applied value for the property.
5223 * @param {Object} obj The scope object. For configuration handlers,
5224 * this will usually equal the owner.
5226 configText: function (type, args, obj) {
5234 * The default event handler fired when the "container" property
5236 * @method configContainer
5237 * @param {String} type The CustomEvent type (usually the property name)
5238 * @param {Object[]} args The CustomEvent arguments. For
5239 * configuration handlers, args[0] will equal the newly applied value
5241 * @param {Object} obj The scope object. For configuration handlers,
5242 * this will usually equal the owner.
5244 configContainer: function (type, args, obj) {
5245 var container = args[0];
5247 if (typeof container == 'string') {
5248 this.cfg.setProperty("container", document.getElementById(container), true);
5253 * @method _removeEventListeners
5254 * @description Removes all of the DOM event handlers from the HTML
5255 * element(s) that trigger the display of the tooltip.
5258 _removeEventListeners: function () {
5260 var aElements = this._context,
5266 nElements = aElements.length;
5267 if (nElements > 0) {
5270 oElement = aElements[i];
5271 Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
5272 Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
5273 Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
5281 * The default event handler fired when the "context" property
5283 * @method configContext
5284 * @param {String} type The CustomEvent type (usually the property name)
5285 * @param {Object[]} args The CustomEvent arguments. For configuration
5286 * handlers, args[0] will equal the newly applied value for the property.
5287 * @param {Object} obj The scope object. For configuration handlers,
5288 * this will usually equal the owner.
5290 configContext: function (type, args, obj) {
5292 var context = args[0],
5300 // Normalize parameter into an array
5301 if (! (context instanceof Array)) {
5302 if (typeof context == "string") {
5303 this.cfg.setProperty("context", [document.getElementById(context)], true);
5304 } else { // Assuming this is an element
5305 this.cfg.setProperty("context", [context], true);
5307 context = this.cfg.getProperty("context");
5310 // Remove any existing mouseover/mouseout listeners
5311 this._removeEventListeners();
5313 // Add mouseover/mouseout listeners to context elements
5314 this._context = context;
5316 aElements = this._context;
5319 nElements = aElements.length;
5320 if (nElements > 0) {
5323 oElement = aElements[i];
5324 Event.on(oElement, "mouseover", this.onContextMouseOver, this);
5325 Event.on(oElement, "mousemove", this.onContextMouseMove, this);
5326 Event.on(oElement, "mouseout", this.onContextMouseOut, this);
5334 // END BUILT-IN PROPERTY EVENT HANDLERS //
5336 // BEGIN BUILT-IN DOM EVENT HANDLERS //
5339 * The default event handler fired when the user moves the mouse while
5340 * over the context element.
5341 * @method onContextMouseMove
5342 * @param {DOMEvent} e The current DOM event
5343 * @param {Object} obj The object argument
5345 onContextMouseMove: function (e, obj) {
5346 obj.pageX = Event.getPageX(e);
5347 obj.pageY = Event.getPageY(e);
5351 * The default event handler fired when the user mouses over the
5353 * @method onContextMouseOver
5354 * @param {DOMEvent} e The current DOM event
5355 * @param {Object} obj The object argument
5357 onContextMouseOver: function (e, obj) {
5360 if (context.title) {
5361 obj._tempTitle = context.title;
5365 // Fire first, to honor disabled set in the listner
5366 if (obj.fireEvent("contextMouseOver", context, e) !== false
5367 && !obj.cfg.getProperty("disabled")) {
5369 // Stop the tooltip from being hidden (set on last mouseout)
5370 if (obj.hideProcId) {
5371 clearTimeout(obj.hideProcId);
5372 obj.hideProcId = null;
5375 Event.on(context, "mousemove", obj.onContextMouseMove, obj);
5378 * The unique process ID associated with the thread responsible
5379 * for showing the Tooltip.
5382 obj.showProcId = obj.doShow(e, context);
5387 * The default event handler fired when the user mouses out of
5388 * the context element.
5389 * @method onContextMouseOut
5390 * @param {DOMEvent} e The current DOM event
5391 * @param {Object} obj The object argument
5393 onContextMouseOut: function (e, obj) {
5396 if (obj._tempTitle) {
5397 el.title = obj._tempTitle;
5398 obj._tempTitle = null;
5401 if (obj.showProcId) {
5402 clearTimeout(obj.showProcId);
5403 obj.showProcId = null;
5406 if (obj.hideProcId) {
5407 clearTimeout(obj.hideProcId);
5408 obj.hideProcId = null;
5411 obj.fireEvent("contextMouseOut", el, e);
5413 obj.hideProcId = setTimeout(function () {
5415 }, obj.cfg.getProperty("hidedelay"));
5418 // END BUILT-IN DOM EVENT HANDLERS //
5421 * Processes the showing of the Tooltip by setting the timeout delay
5422 * and offset of the Tooltip.
5424 * @param {DOMEvent} e The current DOM event
5425 * @param {HTMLElement} context The current context element
5426 * @return {Number} The process ID of the timeout function associated
5429 doShow: function (e, context) {
5434 if (UA.opera && context.tagName &&
5435 context.tagName.toUpperCase() == "A") {
5439 return setTimeout(function () {
5441 var txt = me.cfg.getProperty("text");
5443 // title does not over-ride text
5444 if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
5445 me.setBody(me._tempTitle);
5447 me.cfg.refireEvent("text");
5450 me.moveTo(me.pageX, me.pageY + yOffset);
5452 if (me.cfg.getProperty("preventoverlap")) {
5453 me.preventOverlap(me.pageX, me.pageY);
5456 Event.removeListener(context, "mousemove", me.onContextMouseMove);
5458 me.contextTriggerEvent.fire(context);
5462 me.hideProcId = me.doHide();
5464 }, this.cfg.getProperty("showdelay"));
5468 * Sets the timeout for the auto-dismiss delay, which by default is 5
5469 * seconds, meaning that a tooltip will automatically dismiss itself
5470 * after 5 seconds of being displayed.
5473 doHide: function () {
5478 return setTimeout(function () {
5482 }, this.cfg.getProperty("autodismissdelay"));
5487 * Fired when the Tooltip is moved, this event handler is used to
5488 * prevent the Tooltip from overlapping with its context element.
5489 * @method preventOverlay
5490 * @param {Number} pageX The x coordinate position of the mouse pointer
5491 * @param {Number} pageY The y coordinate position of the mouse pointer
5493 preventOverlap: function (pageX, pageY) {
5495 var height = this.element.offsetHeight,
5496 mousePoint = new YAHOO.util.Point(pageX, pageY),
5497 elementRegion = Dom.getRegion(this.element);
5499 elementRegion.top -= 5;
5500 elementRegion.left -= 5;
5501 elementRegion.right += 5;
5502 elementRegion.bottom += 5;
5505 if (elementRegion.contains(mousePoint)) {
5506 this.cfg.setProperty("y", (pageY - height - 5));
5513 * @description "render" event handler for the Tooltip.
5514 * @param {String} p_sType String representing the name of the event
5516 * @param {Array} p_aArgs Array of arguments sent when the event
5519 onRender: function (p_sType, p_aArgs) {
5521 function sizeShadow() {
5523 var oElement = this.element,
5524 oShadow = this.underlay;
5527 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
5528 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
5533 function addShadowVisibleClass() {
5534 Dom.addClass(this.underlay, "yui-tt-shadow-visible");
5537 this.forceUnderlayRedraw();
5541 function removeShadowVisibleClass() {
5542 Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
5545 function createShadow() {
5547 var oShadow = this.underlay,
5555 oElement = this.element;
5556 Module = YAHOO.widget.Module;
5560 if (!m_oShadowTemplate) {
5561 m_oShadowTemplate = document.createElement("div");
5562 m_oShadowTemplate.className = "yui-tt-shadow";
5565 oShadow = m_oShadowTemplate.cloneNode(false);
5567 oElement.appendChild(oShadow);
5569 this.underlay = oShadow;
5571 // Backward compatibility, even though it's probably
5572 // intended to be "private", it isn't marked as such in the api docs
5573 this._shadow = this.underlay;
5575 addShadowVisibleClass.call(this);
5577 this.subscribe("beforeShow", addShadowVisibleClass);
5578 this.subscribe("hide", removeShadowVisibleClass);
5581 window.setTimeout(function () {
5582 sizeShadow.call(me);
5585 this.cfg.subscribeToConfigEvent("width", sizeShadow);
5586 this.cfg.subscribeToConfigEvent("height", sizeShadow);
5587 this.subscribe("changeContent", sizeShadow);
5589 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5590 this.subscribe("destroy", function () {
5591 Module.textResizeEvent.unsubscribe(sizeShadow, this);
5597 function onBeforeShow() {
5598 createShadow.call(this);
5599 this.unsubscribe("beforeShow", onBeforeShow);
5602 if (this.cfg.getProperty("visible")) {
5603 createShadow.call(this);
5605 this.subscribe("beforeShow", onBeforeShow);
5611 * Forces the underlay element to be repainted, through the application/removal
5612 * of a yui-force-redraw class to the underlay element.
5614 * @method forceUnderlayRedraw
5616 forceUnderlayRedraw : function() {
5618 Dom.addClass(tt.underlay, "yui-force-redraw");
5619 setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
5623 * Removes the Tooltip element from the DOM and sets all child
5627 destroy: function () {
5629 // Remove any existing mouseover/mouseout listeners
5630 this._removeEventListeners();
5632 Tooltip.superclass.destroy.call(this);
5637 * Returns a string representation of the object.
5639 * @return {String} The string representation of the Tooltip
5641 toString: function () {
5642 return "Tooltip " + this.id;
5652 * Panel is an implementation of Overlay that behaves like an OS window,
5653 * with a draggable header and an optional close icon at the top right.
5654 * @namespace YAHOO.widget
5656 * @extends YAHOO.widget.Overlay
5658 * @param {String} el The element ID representing the Panel <em>OR</em>
5659 * @param {HTMLElement} el The element representing the Panel
5660 * @param {Object} userConfig The configuration object literal containing
5661 * the configuration that should be set for this Panel. See configuration
5662 * documentation for more details.
5664 YAHOO.widget.Panel = function (el, userConfig) {
5665 YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5668 var _currentModal = null;
5670 var Lang = YAHOO.lang,
5674 CustomEvent = Util.CustomEvent,
5675 KeyListener = YAHOO.util.KeyListener,
5676 Config = Util.Config,
5677 Overlay = YAHOO.widget.Overlay,
5678 Panel = YAHOO.widget.Panel,
5681 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
5684 m_oUnderlayTemplate,
5685 m_oCloseIconTemplate,
5688 * Constant representing the name of the Panel's events
5689 * @property EVENT_TYPES
5695 "SHOW_MASK": "showMask",
5696 "HIDE_MASK": "hideMask",
5701 * Constant representing the Panel's configuration properties
5702 * @property DEFAULT_CONFIG
5712 validator: Lang.isBoolean,
5713 supercedes: ["visible"]
5718 value: (Util.DD ? true : false),
5719 validator: Lang.isBoolean,
5720 supercedes: ["visible"]
5726 validator: Lang.isBoolean,
5727 supercedes: ["draggable"]
5733 supercedes: ["visible"]
5739 validator: Lang.isBoolean,
5740 supercedes: ["visible", "zindex"]
5744 key: "keylisteners",
5745 suppressEvent: true,
5746 supercedes: ["visible"]
5751 supercedes: ["close"],
5752 validator: Lang.isObject,
5760 * Constant representing the default CSS class used for a Panel
5761 * @property YAHOO.widget.Panel.CSS_PANEL
5766 Panel.CSS_PANEL = "yui-panel";
5769 * Constant representing the default CSS class used for a Panel's
5770 * wrapping container
5771 * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5776 Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5779 * Constant representing the default set of focusable elements
5780 * on the pagewhich Modal Panels will prevent access to, when
5781 * the modal mask is displayed
5783 * @property YAHOO.widget.Panel.FOCUSABLE
5796 // Private CustomEvent listeners
5799 "beforeRender" event handler that creates an empty header for a Panel
5800 instance if its "draggable" configuration property is set to "true"
5801 and no header has been created.
5804 function createHeader(p_sType, p_aArgs) {
5805 if (!this.header && this.cfg.getProperty("draggable")) {
5806 this.setHeader(" ");
5811 "hide" event handler that sets a Panel instance's "width"
5812 configuration property back to its original value before
5813 "setWidthToOffsetWidth" was called.
5816 function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5818 var sOriginalWidth = p_oObject[0],
5819 sNewWidth = p_oObject[1],
5821 sCurrentWidth = oConfig.getProperty("width");
5823 if (sCurrentWidth == sNewWidth) {
5824 oConfig.setProperty("width", sOriginalWidth);
5827 this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5831 "beforeShow" event handler that sets a Panel instance's "width"
5832 configuration property to the value of its root HTML
5833 elements's offsetWidth
5836 function setWidthToOffsetWidth(p_sType, p_aArgs) {
5845 sOriginalWidth = oConfig.getProperty("width");
5847 if (!sOriginalWidth || sOriginalWidth == "auto") {
5849 sNewWidth = (this.element.offsetWidth + "px");
5851 oConfig.setProperty("width", sNewWidth);
5853 this.subscribe("hide", restoreOriginalWidth,
5854 [(sOriginalWidth || ""), sNewWidth]);
5860 YAHOO.extend(Panel, Overlay, {
5863 * The Overlay initialization method, which is executed for Overlay and
5864 * all of its subclasses. This method is automatically called by the
5865 * constructor, and sets up all DOM references for pre-existing markup,
5866 * and creates required markup if it is not already present.
5868 * @param {String} el The element ID representing the Overlay <em>OR</em>
5869 * @param {HTMLElement} el The element representing the Overlay
5870 * @param {Object} userConfig The configuration object literal
5871 * containing the configuration that should be set for this Overlay.
5872 * See configuration documentation for more details.
5874 init: function (el, userConfig) {
5876 Note that we don't pass the user config in here yet because
5877 we only want it executed once, at the lowest subclass level
5880 Panel.superclass.init.call(this, el/*, userConfig*/);
5882 this.beforeInitEvent.fire(Panel);
5884 Dom.addClass(this.element, Panel.CSS_PANEL);
5886 this.buildWrapper();
5889 this.cfg.applyConfig(userConfig, true);
5892 this.subscribe("showMask", this._addFocusHandlers);
5893 this.subscribe("hideMask", this._removeFocusHandlers);
5894 this.subscribe("beforeRender", createHeader);
5896 this.subscribe("render", function() {
5897 this.setFirstLastFocusable();
5898 this.subscribe("changeContent", this.setFirstLastFocusable);
5901 this.subscribe("show", this.focusFirst);
5903 this.initEvent.fire(Panel);
5907 * @method _onElementFocus
5910 * "focus" event handler for a focuable element. Used to automatically
5911 * blur the element when it receives focus to ensure that a Panel
5912 * instance's modality is not compromised.
5914 * @param {Event} e The DOM event object
5916 _onElementFocus : function(e){
5918 if(_currentModal === this) {
5920 var target = Event.getTarget(e),
5921 doc = document.documentElement,
5922 insideDoc = (target !== doc && target !== window);
5924 // mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on
5925 // the documentElement, when the document scrollbars are clicked on
5926 if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
5928 if (this.firstElement) {
5929 this.firstElement.focus();
5931 if (this._modalFocus) {
5932 this._modalFocus.focus();
5934 this.innerElement.focus();
5938 // Just in case we fail to focus
5940 if (insideDoc && target !== document.body) {
5950 * @method _addFocusHandlers
5953 * "showMask" event handler that adds a "focus" event handler to all
5954 * focusable elements in the document to enforce a Panel instance's
5955 * modality from being compromised.
5957 * @param p_sType {String} Custom event type
5958 * @param p_aArgs {Array} Custom event arguments
5960 _addFocusHandlers: function(p_sType, p_aArgs) {
5961 if (!this.firstElement) {
5962 if (UA.webkit || UA.opera) {
5963 if (!this._modalFocus) {
5964 this._createHiddenFocusElement();
5967 this.innerElement.tabIndex = 0;
5970 this.setTabLoop(this.firstElement, this.lastElement);
5971 Event.onFocus(document.documentElement, this._onElementFocus, this, true);
5972 _currentModal = this;
5976 * Creates a hidden focusable element, used to focus on,
5977 * to enforce modality for browsers in which focus cannot
5978 * be applied to the container box.
5980 * @method _createHiddenFocusElement
5983 _createHiddenFocusElement : function() {
5984 var e = document.createElement("button");
5985 e.style.height = "1px";
5986 e.style.width = "1px";
5987 e.style.position = "absolute";
5988 e.style.left = "-10000em";
5989 e.style.opacity = 0;
5991 this.innerElement.appendChild(e);
5992 this._modalFocus = e;
5996 * @method _removeFocusHandlers
5999 * "hideMask" event handler that removes all "focus" event handlers added
6000 * by the "addFocusEventHandlers" method.
6002 * @param p_sType {String} Event type
6003 * @param p_aArgs {Array} Event Arguments
6005 _removeFocusHandlers: function(p_sType, p_aArgs) {
6006 Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
6008 if (_currentModal == this) {
6009 _currentModal = null;
6014 * Sets focus to the first element in the Panel.
6016 * @method focusFirst
6018 focusFirst: function (type, args, obj) {
6019 var el = this.firstElement;
6021 if (args && args[1]) {
6022 Event.stopEvent(args[1]);
6035 * Sets focus to the last element in the Panel.
6039 focusLast: function (type, args, obj) {
6040 var el = this.lastElement;
6042 if (args && args[1]) {
6043 Event.stopEvent(args[1]);
6056 * Sets up a tab, shift-tab loop between the first and last elements
6057 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
6058 * instance properties, which are reset everytime this method is invoked.
6060 * @method setTabLoop
6061 * @param {HTMLElement} firstElement
6062 * @param {HTMLElement} lastElement
6065 setTabLoop : function(firstElement, lastElement) {
6067 var backTab = this.preventBackTab, tab = this.preventTabOut,
6068 showEvent = this.showEvent, hideEvent = this.hideEvent;
6072 showEvent.unsubscribe(backTab.enable, backTab);
6073 hideEvent.unsubscribe(backTab.disable, backTab);
6074 backTab = this.preventBackTab = null;
6079 showEvent.unsubscribe(tab.enable, tab);
6080 hideEvent.unsubscribe(tab.disable,tab);
6081 tab = this.preventTabOut = null;
6085 this.preventBackTab = new KeyListener(firstElement,
6086 {shift:true, keys:9},
6087 {fn:this.focusLast, scope:this, correctScope:true}
6089 backTab = this.preventBackTab;
6091 showEvent.subscribe(backTab.enable, backTab, true);
6092 hideEvent.subscribe(backTab.disable,backTab, true);
6096 this.preventTabOut = new KeyListener(lastElement,
6097 {shift:false, keys:9},
6098 {fn:this.focusFirst, scope:this, correctScope:true}
6100 tab = this.preventTabOut;
6102 showEvent.subscribe(tab.enable, tab, true);
6103 hideEvent.subscribe(tab.disable,tab, true);
6108 * Returns an array of the currently focusable items which reside within
6109 * Panel. The set of focusable elements the method looks for are defined
6110 * in the Panel.FOCUSABLE static property
6112 * @method getFocusableElements
6113 * @param {HTMLElement} root element to start from.
6115 getFocusableElements : function(root) {
6117 root = root || this.innerElement;
6120 for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
6121 focusable[Panel.FOCUSABLE[i]] = true;
6124 function isFocusable(el) {
6125 if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
6131 // Not looking by Tag, since we want elements in DOM order
6132 return Dom.getElementsBy(isFocusable, null, root);
6136 * Sets the firstElement and lastElement instance properties
6137 * to the first and last focusable elements in the Panel.
6139 * @method setFirstLastFocusable
6141 setFirstLastFocusable : function() {
6143 this.firstElement = null;
6144 this.lastElement = null;
6146 var elements = this.getFocusableElements();
6147 this.focusableElements = elements;
6149 if (elements.length > 0) {
6150 this.firstElement = elements[0];
6151 this.lastElement = elements[elements.length - 1];
6154 if (this.cfg.getProperty("modal")) {
6155 this.setTabLoop(this.firstElement, this.lastElement);
6160 * Initializes the custom events for Module which are fired
6161 * automatically at appropriate times by the Module class.
6163 initEvents: function () {
6164 Panel.superclass.initEvents.call(this);
6166 var SIGNATURE = CustomEvent.LIST;
6169 * CustomEvent fired after the modality mask is shown
6170 * @event showMaskEvent
6172 this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
6173 this.showMaskEvent.signature = SIGNATURE;
6176 * CustomEvent fired after the modality mask is hidden
6177 * @event hideMaskEvent
6179 this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
6180 this.hideMaskEvent.signature = SIGNATURE;
6183 * CustomEvent when the Panel is dragged
6186 this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
6187 this.dragEvent.signature = SIGNATURE;
6191 * Initializes the class's configurable properties which can be changed
6192 * using the Panel's Config object (cfg).
6193 * @method initDefaultConfig
6195 initDefaultConfig: function () {
6196 Panel.superclass.initDefaultConfig.call(this);
6198 // Add panel config properties //
6201 * True if the Panel should display a "close" button
6206 this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
6207 handler: this.configClose,
6208 value: DEFAULT_CONFIG.CLOSE.value,
6209 validator: DEFAULT_CONFIG.CLOSE.validator,
6210 supercedes: DEFAULT_CONFIG.CLOSE.supercedes
6214 * Boolean specifying if the Panel should be draggable. The default
6215 * value is "true" if the Drag and Drop utility is included,
6216 * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
6217 * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
6218 * (Quirks Mode) where Panels that either don't have a value set for
6219 * their "width" configuration property, or their "width"
6220 * configuration property is set to "auto" will only be draggable by
6221 * placing the mouse on the text of the Panel's header element.
6222 * To fix this bug, draggable Panels missing a value for their
6223 * "width" configuration property, or whose "width" configuration
6224 * property is set to "auto" will have it set to the value of
6225 * their root HTML element's offsetWidth before they are made
6226 * visible. The calculated width is then removed when the Panel is
6227 * hidden. <em>This fix is only applied to draggable Panels in IE 6
6228 * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
6229 * more information on this issue see:
6230 * SourceForge bugs #1726972 and #1589210.
6235 this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
6236 handler: this.configDraggable,
6237 value: (Util.DD) ? true : false,
6238 validator: DEFAULT_CONFIG.DRAGGABLE.validator,
6239 supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
6243 * Boolean specifying if the draggable Panel should be drag only, not interacting with drop
6244 * targets on the page.
6246 * When set to true, draggable Panels will not check to see if they are over drop targets,
6247 * or fire the DragDrop events required to support drop target interaction (onDragEnter,
6248 * onDragOver, onDragOut, onDragDrop etc.).
6249 * If the Panel is not designed to be dropped on any target elements on the page, then this
6250 * flag can be set to true to improve performance.
6253 * When set to false, all drop target related events will be fired.
6256 * The property is set to false by default to maintain backwards compatibility but should be
6257 * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
6263 this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, {
6264 value: DEFAULT_CONFIG.DRAG_ONLY.value,
6265 validator: DEFAULT_CONFIG.DRAG_ONLY.validator,
6266 supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes
6270 * Sets the type of underlay to display for the Panel. Valid values
6271 * are "shadow," "matte," and "none". <strong>PLEASE NOTE:</strong>
6272 * The creation of the underlay element is deferred until the Panel
6273 * is initially made visible. For Gecko-based browsers on Mac
6274 * OS X the underlay elment is always created as it is used as a
6275 * shim to prevent Aqua scrollbars below a Panel instance from poking
6276 * through it (See SourceForge bug #836476).
6281 this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
6282 handler: this.configUnderlay,
6283 value: DEFAULT_CONFIG.UNDERLAY.value,
6284 supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
6288 * True if the Panel should be displayed in a modal fashion,
6289 * automatically creating a transparent mask over the document that
6290 * will not be removed until the Panel is dismissed.
6295 this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
6296 handler: this.configModal,
6297 value: DEFAULT_CONFIG.MODAL.value,
6298 validator: DEFAULT_CONFIG.MODAL.validator,
6299 supercedes: DEFAULT_CONFIG.MODAL.supercedes
6303 * A KeyListener (or array of KeyListeners) that will be enabled
6304 * when the Panel is shown, and disabled when the Panel is hidden.
6305 * @config keylisteners
6306 * @type YAHOO.util.KeyListener[]
6309 this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
6310 handler: this.configKeyListeners,
6311 suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
6312 supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
6316 * UI Strings used by the Panel
6320 * @default An object literal with the properties shown below:
6322 * <dt>close</dt><dd><em>String</em> : The string to use for the close icon. Defaults to "Close".</dd>
6325 this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, {
6326 value:DEFAULT_CONFIG.STRINGS.value,
6327 handler:this.configStrings,
6328 validator:DEFAULT_CONFIG.STRINGS.validator,
6329 supercedes:DEFAULT_CONFIG.STRINGS.supercedes
6333 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6336 * The default event handler fired when the "close" property is changed.
6337 * The method controls the appending or hiding of the close icon at the
6338 * top right of the Panel.
6339 * @method configClose
6340 * @param {String} type The CustomEvent type (usually the property name)
6341 * @param {Object[]} args The CustomEvent arguments. For configuration
6342 * handlers, args[0] will equal the newly applied value for the property.
6343 * @param {Object} obj The scope object. For configuration handlers,
6344 * this will usually equal the owner.
6346 configClose: function (type, args, obj) {
6349 oClose = this.close,
6350 strings = this.cfg.getProperty("strings");
6355 if (!m_oCloseIconTemplate) {
6356 m_oCloseIconTemplate = document.createElement("a");
6357 m_oCloseIconTemplate.className = "container-close";
6358 m_oCloseIconTemplate.href = "#";
6361 oClose = m_oCloseIconTemplate.cloneNode(true);
6362 this.innerElement.appendChild(oClose);
6364 oClose.innerHTML = (strings && strings.close) ? strings.close : " ";
6366 Event.on(oClose, "click", this._doClose, this, true);
6368 this.close = oClose;
6371 oClose.style.display = "block";
6376 oClose.style.display = "none";
6383 * Event handler for the close icon
6388 * @param {DOMEvent} e
6390 _doClose : function (e) {
6391 Event.preventDefault(e);
6396 * The default event handler fired when the "draggable" property
6398 * @method configDraggable
6399 * @param {String} type The CustomEvent type (usually the property name)
6400 * @param {Object[]} args The CustomEvent arguments. For configuration
6401 * handlers, args[0] will equal the newly applied value for the property.
6402 * @param {Object} obj The scope object. For configuration handlers,
6403 * this will usually equal the owner.
6405 configDraggable: function (type, args, obj) {
6410 this.cfg.setProperty("draggable", false);
6415 Dom.setStyle(this.header, "cursor", "move");
6416 this.registerDragDrop();
6419 this.subscribe("beforeShow", setWidthToOffsetWidth);
6428 Dom.setStyle(this.header,"cursor","auto");
6431 this.unsubscribe("beforeShow", setWidthToOffsetWidth);
6436 * The default event handler fired when the "underlay" property
6438 * @method configUnderlay
6439 * @param {String} type The CustomEvent type (usually the property name)
6440 * @param {Object[]} args The CustomEvent arguments. For configuration
6441 * handlers, args[0] will equal the newly applied value for the property.
6442 * @param {Object} obj The scope object. For configuration handlers,
6443 * this will usually equal the owner.
6445 configUnderlay: function (type, args, obj) {
6447 var bMacGecko = (this.platform == "mac" && UA.gecko),
6448 sUnderlay = args[0].toLowerCase(),
6449 oUnderlay = this.underlay,
6450 oElement = this.element;
6452 function createUnderlay() {
6454 if (!oUnderlay) { // create if not already in DOM
6456 if (!m_oUnderlayTemplate) {
6457 m_oUnderlayTemplate = document.createElement("div");
6458 m_oUnderlayTemplate.className = "underlay";
6461 oUnderlay = m_oUnderlayTemplate.cloneNode(false);
6462 this.element.appendChild(oUnderlay);
6464 this.underlay = oUnderlay;
6467 this.sizeUnderlay();
6468 this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
6469 this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
6471 this.changeContentEvent.subscribe(this.sizeUnderlay);
6472 YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
6475 if (UA.webkit && UA.webkit < 420) {
6476 this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
6483 function onBeforeShow() {
6484 var bNew = createUnderlay.call(this);
6485 if (!bNew && bIEQuirks) {
6486 this.sizeUnderlay();
6488 this._underlayDeferred = false;
6489 this.beforeShowEvent.unsubscribe(onBeforeShow);
6492 function destroyUnderlay() {
6493 if (this._underlayDeferred) {
6494 this.beforeShowEvent.unsubscribe(onBeforeShow);
6495 this._underlayDeferred = false;
6499 this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
6500 this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
6501 this.changeContentEvent.unsubscribe(this.sizeUnderlay);
6502 this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
6503 YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
6505 this.element.removeChild(oUnderlay);
6507 this.underlay = null;
6511 switch (sUnderlay) {
6513 Dom.removeClass(oElement, "matte");
6514 Dom.addClass(oElement, "shadow");
6518 destroyUnderlay.call(this);
6520 Dom.removeClass(oElement, "shadow");
6521 Dom.addClass(oElement, "matte");
6525 destroyUnderlay.call(this);
6527 Dom.removeClass(oElement, "shadow");
6528 Dom.removeClass(oElement, "matte");
6532 if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
6533 if (this.cfg.getProperty("visible")) {
6534 var bNew = createUnderlay.call(this);
6535 if (!bNew && bIEQuirks) {
6536 this.sizeUnderlay();
6539 if (!this._underlayDeferred) {
6540 this.beforeShowEvent.subscribe(onBeforeShow);
6541 this._underlayDeferred = true;
6548 * The default event handler fired when the "modal" property is
6549 * changed. This handler subscribes or unsubscribes to the show and hide
6550 * events to handle the display or hide of the modality mask.
6551 * @method configModal
6552 * @param {String} type The CustomEvent type (usually the property name)
6553 * @param {Object[]} args The CustomEvent arguments. For configuration
6554 * handlers, args[0] will equal the newly applied value for the property.
6555 * @param {Object} obj The scope object. For configuration handlers,
6556 * this will usually equal the owner.
6558 configModal: function (type, args, obj) {
6560 var modal = args[0];
6562 if (!this._hasModalityEventListeners) {
6564 this.subscribe("beforeShow", this.buildMask);
6565 this.subscribe("beforeShow", this.bringToTop);
6566 this.subscribe("beforeShow", this.showMask);
6567 this.subscribe("hide", this.hideMask);
6569 Overlay.windowResizeEvent.subscribe(this.sizeMask,
6572 this._hasModalityEventListeners = true;
6575 if (this._hasModalityEventListeners) {
6577 if (this.cfg.getProperty("visible")) {
6582 this.unsubscribe("beforeShow", this.buildMask);
6583 this.unsubscribe("beforeShow", this.bringToTop);
6584 this.unsubscribe("beforeShow", this.showMask);
6585 this.unsubscribe("hide", this.hideMask);
6587 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6589 this._hasModalityEventListeners = false;
6595 * Removes the modality mask.
6596 * @method removeMask
6598 removeMask: function () {
6600 var oMask = this.mask,
6605 Hide the mask before destroying it to ensure that DOM
6606 event handlers on focusable elements get removed.
6610 oParentNode = oMask.parentNode;
6612 oParentNode.removeChild(oMask);
6620 * The default event handler fired when the "keylisteners" property
6622 * @method configKeyListeners
6623 * @param {String} type The CustomEvent type (usually the property name)
6624 * @param {Object[]} args The CustomEvent arguments. For configuration
6625 * handlers, args[0] will equal the newly applied value for the property.
6626 * @param {Object} obj The scope object. For configuration handlers,
6627 * this will usually equal the owner.
6629 configKeyListeners: function (type, args, obj) {
6631 var listeners = args[0],
6638 if (listeners instanceof Array) {
6640 nListeners = listeners.length;
6642 for (i = 0; i < nListeners; i++) {
6644 listener = listeners[i];
6646 if (!Config.alreadySubscribed(this.showEvent,
6647 listener.enable, listener)) {
6649 this.showEvent.subscribe(listener.enable,
6654 if (!Config.alreadySubscribed(this.hideEvent,
6655 listener.disable, listener)) {
6657 this.hideEvent.subscribe(listener.disable,
6660 this.destroyEvent.subscribe(listener.disable,
6667 if (!Config.alreadySubscribed(this.showEvent,
6668 listeners.enable, listeners)) {
6670 this.showEvent.subscribe(listeners.enable,
6674 if (!Config.alreadySubscribed(this.hideEvent,
6675 listeners.disable, listeners)) {
6677 this.hideEvent.subscribe(listeners.disable,
6680 this.destroyEvent.subscribe(listeners.disable,
6692 * The default handler for the "strings" property
6693 * @method configStrings
6695 configStrings : function(type, args, obj) {
6696 var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
6697 this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
6701 * The default event handler fired when the "height" property is changed.
6702 * @method configHeight
6703 * @param {String} type The CustomEvent type (usually the property name)
6704 * @param {Object[]} args The CustomEvent arguments. For configuration
6705 * handlers, args[0] will equal the newly applied value for the property.
6706 * @param {Object} obj The scope object. For configuration handlers,
6707 * this will usually equal the owner.
6709 configHeight: function (type, args, obj) {
6710 var height = args[0],
6711 el = this.innerElement;
6713 Dom.setStyle(el, "height", height);
6714 this.cfg.refireEvent("iframe");
6718 * The default custom event handler executed when the Panel's height is changed,
6719 * if the autofillheight property has been set.
6721 * @method _autoFillOnHeightChange
6723 * @param {String} type The event type
6724 * @param {Array} args The array of arguments passed to event subscribers
6725 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
6726 * out the containers height
6728 _autoFillOnHeightChange : function(type, args, el) {
6729 Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
6732 setTimeout(function() {
6733 panel.sizeUnderlay();
6739 * The default event handler fired when the "width" property is changed.
6740 * @method configWidth
6741 * @param {String} type The CustomEvent type (usually the property name)
6742 * @param {Object[]} args The CustomEvent arguments. For configuration
6743 * handlers, args[0] will equal the newly applied value for the property.
6744 * @param {Object} obj The scope object. For configuration handlers,
6745 * this will usually equal the owner.
6747 configWidth: function (type, args, obj) {
6749 var width = args[0],
6750 el = this.innerElement;
6752 Dom.setStyle(el, "width", width);
6753 this.cfg.refireEvent("iframe");
6758 * The default event handler fired when the "zIndex" property is changed.
6759 * @method configzIndex
6760 * @param {String} type The CustomEvent type (usually the property name)
6761 * @param {Object[]} args The CustomEvent arguments. For configuration
6762 * handlers, args[0] will equal the newly applied value for the property.
6763 * @param {Object} obj The scope object. For configuration handlers,
6764 * this will usually equal the owner.
6766 configzIndex: function (type, args, obj) {
6767 Panel.superclass.configzIndex.call(this, type, args, obj);
6769 if (this.mask || this.cfg.getProperty("modal") === true) {
6770 var panelZ = Dom.getStyle(this.element, "zIndex");
6771 if (!panelZ || isNaN(panelZ)) {
6776 // Recursive call to configzindex (which should be stopped
6777 // from going further because panelZ should no longer === 0)
6778 this.cfg.setProperty("zIndex", 1);
6785 // END BUILT-IN PROPERTY EVENT HANDLERS //
6787 * Builds the wrapping container around the Panel that is used for
6788 * positioning the shadow and matte underlays. The container element is
6789 * assigned to a local instance variable called container, and the
6790 * element is reinserted inside of it.
6791 * @method buildWrapper
6793 buildWrapper: function () {
6795 var elementParent = this.element.parentNode,
6796 originalElement = this.element,
6797 wrapper = document.createElement("div");
6799 wrapper.className = Panel.CSS_PANEL_CONTAINER;
6800 wrapper.id = originalElement.id + "_c";
6802 if (elementParent) {
6803 elementParent.insertBefore(wrapper, originalElement);
6806 wrapper.appendChild(originalElement);
6808 this.element = wrapper;
6809 this.innerElement = originalElement;
6811 Dom.setStyle(this.innerElement, "visibility", "inherit");
6815 * Adjusts the size of the shadow based on the size of the element.
6816 * @method sizeUnderlay
6818 sizeUnderlay: function () {
6819 var oUnderlay = this.underlay,
6823 oElement = this.element;
6824 oUnderlay.style.width = oElement.offsetWidth + "px";
6825 oUnderlay.style.height = oElement.offsetHeight + "px";
6830 * Registers the Panel's header for drag & drop capability.
6831 * @method registerDragDrop
6833 registerDragDrop: function () {
6843 var bDragOnly = (this.cfg.getProperty("dragonly") === true);
6844 this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
6846 if (!this.header.id) {
6847 this.header.id = this.id + "_h";
6850 this.dd.startDrag = function () {
6859 if (YAHOO.env.ua.ie == 6) {
6860 Dom.addClass(me.element,"drag");
6863 if (me.cfg.getProperty("constraintoviewport")) {
6865 var nViewportOffset = Overlay.VIEWPORT_OFFSET;
6867 offsetHeight = me.element.offsetHeight;
6868 offsetWidth = me.element.offsetWidth;
6870 viewPortWidth = Dom.getViewportWidth();
6871 viewPortHeight = Dom.getViewportHeight();
6873 scrollX = Dom.getDocumentScrollLeft();
6874 scrollY = Dom.getDocumentScrollTop();
6876 if (offsetHeight + nViewportOffset < viewPortHeight) {
6877 this.minY = scrollY + nViewportOffset;
6878 this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
6880 this.minY = scrollY + nViewportOffset;
6881 this.maxY = scrollY + nViewportOffset;
6884 if (offsetWidth + nViewportOffset < viewPortWidth) {
6885 this.minX = scrollX + nViewportOffset;
6886 this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
6888 this.minX = scrollX + nViewportOffset;
6889 this.maxX = scrollX + nViewportOffset;
6892 this.constrainX = true;
6893 this.constrainY = true;
6895 this.constrainX = false;
6896 this.constrainY = false;
6899 me.dragEvent.fire("startDrag", arguments);
6902 this.dd.onDrag = function () {
6904 me.cfg.refireEvent("iframe");
6905 if (this.platform == "mac" && YAHOO.env.ua.gecko) {
6906 this.showMacGeckoScrollbars();
6909 me.dragEvent.fire("onDrag", arguments);
6912 this.dd.endDrag = function () {
6914 if (YAHOO.env.ua.ie == 6) {
6915 Dom.removeClass(me.element,"drag");
6918 me.dragEvent.fire("endDrag", arguments);
6919 me.moveEvent.fire(me.cfg.getProperty("xy"));
6923 this.dd.setHandleElId(this.header.id);
6924 this.dd.addInvalidHandleType("INPUT");
6925 this.dd.addInvalidHandleType("SELECT");
6926 this.dd.addInvalidHandleType("TEXTAREA");
6931 * Builds the mask that is laid over the document when the Panel is
6932 * configured to be modal.
6935 buildMask: function () {
6936 var oMask = this.mask;
6938 if (!m_oMaskTemplate) {
6939 m_oMaskTemplate = document.createElement("div");
6940 m_oMaskTemplate.className = "mask";
6941 m_oMaskTemplate.innerHTML = " ";
6943 oMask = m_oMaskTemplate.cloneNode(true);
6944 oMask.id = this.id + "_mask";
6946 document.body.insertBefore(oMask, document.body.firstChild);
6950 if (YAHOO.env.ua.gecko && this.platform == "mac") {
6951 Dom.addClass(this.mask, "block-scrollbars");
6954 // Stack mask based on the element zindex
6960 * Hides the modality mask.
6963 hideMask: function () {
6964 if (this.cfg.getProperty("modal") && this.mask) {
6965 this.mask.style.display = "none";
6966 Dom.removeClass(document.body, "masked");
6967 this.hideMaskEvent.fire();
6972 * Shows the modality mask.
6975 showMask: function () {
6976 if (this.cfg.getProperty("modal") && this.mask) {
6977 Dom.addClass(document.body, "masked");
6979 this.mask.style.display = "block";
6980 this.showMaskEvent.fire();
6985 * Sets the size of the modality mask to cover the entire scrollable
6986 * area of the document
6989 sizeMask: function () {
6992 // Shrink mask first, so it doesn't affect the document size.
6993 var mask = this.mask,
6994 viewWidth = Dom.getViewportWidth(),
6995 viewHeight = Dom.getViewportHeight();
6997 if (mask.offsetHeight > viewHeight) {
6998 mask.style.height = viewHeight + "px";
7001 if (mask.offsetWidth > viewWidth) {
7002 mask.style.width = viewWidth + "px";
7005 // Then size it to the document
7006 mask.style.height = Dom.getDocumentHeight() + "px";
7007 mask.style.width = Dom.getDocumentWidth() + "px";
7012 * Sets the zindex of the mask, if it exists, based on the zindex of
7013 * the Panel element. The zindex of the mask is set to be one less
7014 * than the Panel element's zindex.
7016 * <p>NOTE: This method will not bump up the zindex of the Panel
7017 * to ensure that the mask has a non-negative zindex. If you require the
7018 * mask zindex to be 0 or higher, the zindex of the Panel
7019 * should be set to a value higher than 0, before this method is called.
7023 stackMask: function() {
7025 var panelZ = Dom.getStyle(this.element, "zIndex");
7026 if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
7027 Dom.setStyle(this.mask, "zIndex", panelZ - 1);
7033 * Renders the Panel by inserting the elements that are not already in
7034 * the main Panel into their correct places. Optionally appends the
7035 * Panel to the specified node prior to the render's execution. NOTE:
7036 * For Panels without existing markup, the appendToNode argument is
7037 * REQUIRED. If this argument is ommitted and the current element is
7038 * not present in the document, the function will return false,
7039 * indicating that the render was a failure.
7041 * @param {String} appendToNode The element id to which the Module
7042 * should be appended to prior to rendering <em>OR</em>
7043 * @param {HTMLElement} appendToNode The element to which the Module
7044 * should be appended to prior to rendering
7045 * @return {boolean} Success or failure of the render
7047 render: function (appendToNode) {
7049 return Panel.superclass.render.call(this,
7050 appendToNode, this.innerElement);
7055 * Removes the Panel element from the DOM and sets all child elements
7059 destroy: function () {
7060 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
7063 Event.purgeElement(this.close);
7065 Panel.superclass.destroy.call(this);
7069 * Forces the underlay element to be repainted through the application/removal
7070 * of a yui-force-redraw class to the underlay element.
7072 * @method forceUnderlayRedraw
7074 forceUnderlayRedraw : function () {
7075 var u = this.underlay;
7076 Dom.addClass(u, "yui-force-redraw");
7077 setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
7081 * Returns a String representation of the object.
7083 * @return {String} The string representation of the Panel.
7085 toString: function () {
7086 return "Panel " + this.id;
7097 * Dialog is an implementation of Panel that can be used to submit form
7101 * Built-in functionality for buttons with event handlers is included.
7102 * If the optional YUI Button dependancy is included on the page, the buttons
7103 * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
7107 * Forms can be processed in 3 ways -- via an asynchronous Connection utility call,
7108 * a simple form POST or GET, or manually. The YUI Connection utility should be
7109 * included if you're using the default "async" postmethod, but is not required if
7110 * you're using any of the other postmethod values.
7112 * @namespace YAHOO.widget
7114 * @extends YAHOO.widget.Panel
7116 * @param {String} el The element ID representing the Dialog <em>OR</em>
7117 * @param {HTMLElement} el The element representing the Dialog
7118 * @param {Object} userConfig The configuration object literal containing
7119 * the configuration that should be set for this Dialog. See configuration
7120 * documentation for more details.
7122 YAHOO.widget.Dialog = function (el, userConfig) {
7123 YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
7126 var Event = YAHOO.util.Event,
7127 CustomEvent = YAHOO.util.CustomEvent,
7128 Dom = YAHOO.util.Dom,
7129 Dialog = YAHOO.widget.Dialog,
7133 * Constant representing the name of the Dialog's events
7134 * @property EVENT_TYPES
7140 "BEFORE_SUBMIT": "beforeSubmit",
7142 "MANUAL_SUBMIT": "manualSubmit",
7143 "ASYNC_SUBMIT": "asyncSubmit",
7144 "FORM_SUBMIT": "formSubmit",
7149 * Constant representing the Dialog's configuration properties
7150 * @property DEFAULT_CONFIG
7170 supercedes: ["visible"]
7173 "HIDEAFTERSUBMIT" : {
7174 key: "hideaftersubmit",
7181 * Constant representing the default CSS class used for a Dialog
7182 * @property YAHOO.widget.Dialog.CSS_DIALOG
7187 Dialog.CSS_DIALOG = "yui-dialog";
7189 function removeButtonEventHandlers() {
7191 var aButtons = this._aButtons,
7196 if (Lang.isArray(aButtons)) {
7197 nButtons = aButtons.length;
7202 oButton = aButtons[i];
7204 if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
7207 else if (oButton.tagName.toUpperCase() == "BUTTON") {
7208 Event.purgeElement(oButton);
7209 Event.purgeElement(oButton, false);
7217 YAHOO.extend(Dialog, YAHOO.widget.Panel, {
7221 * @description Object reference to the Dialog's
7222 * <code><form></code> element.
7224 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7225 * level-one-html.html#ID-40002357">HTMLFormElement</a>
7230 * Initializes the class's configurable properties which can be changed
7231 * using the Dialog's Config object (cfg).
7232 * @method initDefaultConfig
7234 initDefaultConfig: function () {
7235 Dialog.superclass.initDefaultConfig.call(this);
7238 * The internally maintained callback object for use with the
7239 * Connection utility. The format of the callback object is
7240 * similar to Connection Manager's callback object and is
7241 * simply passed through to Connection Manager when the async
7243 * @property callback
7249 * The function to execute upon success of the
7250 * Connection submission (when the form does not
7251 * contain a file input element).
7253 * @property callback.success
7259 * The function to execute upon failure of the
7260 * Connection submission
7261 * @property callback.failure
7268 * The function to execute upon success of the
7269 * Connection submission, when the form contains
7270 * a file input element.
7273 * <em>NOTE:</em> Connection manager will not
7274 * invoke the success or failure handlers for the file
7275 * upload use case. This will be the only callback
7279 * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
7280 * Connection Manager documenation on file uploads</a>.
7282 * @property callback.upload
7287 * The arbitraty argument or arguments to pass to the Connection
7288 * callback functions
7289 * @property callback.argument
7296 // Add form dialog config properties //
7298 * The method to use for posting the Dialog's form. Possible values
7299 * are "async", "form", and "manual".
7300 * @config postmethod
7304 this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
7305 handler: this.configPostMethod,
7306 value: DEFAULT_CONFIG.POST_METHOD.value,
7307 validator: function (val) {
7308 if (val != "form" && val != "async" && val != "none" &&
7318 * Any additional post data which needs to be sent when using the
7319 * <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
7320 * The format for the post data string is defined by Connection Manager's
7321 * <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a>
7327 this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
7328 value: DEFAULT_CONFIG.POST_DATA.value
7332 * This property is used to configure whether or not the
7333 * dialog should be automatically hidden after submit.
7335 * @config hideaftersubmit
7339 this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
7340 value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
7344 * Array of object literals, each containing a set of properties
7345 * defining a button to be appended into the Dialog's footer.
7347 * <p>Each button object in the buttons array can have three properties:</p>
7351 * The text that will display on the face of the button. The text can
7352 * include HTML, as long as it is compliant with HTML Button specifications.
7355 * <dd>Can be either:
7357 * <li>A reference to a function that should fire when the
7358 * button is clicked. (In this case scope of this function is
7359 * always its Dialog instance.)</li>
7361 * <li>An object literal representing the code to be
7362 * executed when the button is clicked.
7369 * <strong>fn:</strong> Function, //
7370 * The handler to call when the event fires.
7372 * <strong>obj:</strong> Object, //
7373 * An object to pass back to the handler.
7375 * <strong>scope:</strong> Object //
7376 * The object to use for the scope of the handler.
7383 * <dt>isDefault:</dt>
7385 * An optional boolean value that specifies that a button
7386 * should be highlighted and focused by default.
7390 * <em>NOTE:</em>If the YUI Button Widget is included on the page,
7391 * the buttons created will be instances of YAHOO.widget.Button.
7392 * Otherwise, HTML Buttons (<code><BUTTON></code>) will be
7396 * @type {Array|String}
7399 this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
7400 handler: this.configButtons,
7401 value: DEFAULT_CONFIG.BUTTONS.value,
7402 supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
7408 * Initializes the custom events for Dialog which are fired
7409 * automatically at appropriate times by the Dialog class.
7410 * @method initEvents
7412 initEvents: function () {
7413 Dialog.superclass.initEvents.call(this);
7415 var SIGNATURE = CustomEvent.LIST;
7418 * CustomEvent fired prior to submission
7419 * @event beforeSubmitEvent
7421 this.beforeSubmitEvent =
7422 this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
7423 this.beforeSubmitEvent.signature = SIGNATURE;
7426 * CustomEvent fired after submission
7427 * @event submitEvent
7429 this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
7430 this.submitEvent.signature = SIGNATURE;
7433 * CustomEvent fired for manual submission, before the generic submit event is fired
7434 * @event manualSubmitEvent
7436 this.manualSubmitEvent =
7437 this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
7438 this.manualSubmitEvent.signature = SIGNATURE;
7441 * CustomEvent fired after asynchronous submission, before the generic submit event is fired
7443 * @event asyncSubmitEvent
7444 * @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
7446 this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
7447 this.asyncSubmitEvent.signature = SIGNATURE;
7450 * CustomEvent fired after form-based submission, before the generic submit event is fired
7451 * @event formSubmitEvent
7453 this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
7454 this.formSubmitEvent.signature = SIGNATURE;
7457 * CustomEvent fired after cancel
7458 * @event cancelEvent
7460 this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
7461 this.cancelEvent.signature = SIGNATURE;
7466 * The Dialog initialization method, which is executed for Dialog and
7467 * all of its subclasses. This method is automatically called by the
7468 * constructor, and sets up all DOM references for pre-existing markup,
7469 * and creates required markup if it is not already present.
7472 * @param {String} el The element ID representing the Dialog <em>OR</em>
7473 * @param {HTMLElement} el The element representing the Dialog
7474 * @param {Object} userConfig The configuration object literal
7475 * containing the configuration that should be set for this Dialog.
7476 * See configuration documentation for more details.
7478 init: function (el, userConfig) {
7481 Note that we don't pass the user config in here yet because
7482 we only want it executed once, at the lowest subclass level
7485 Dialog.superclass.init.call(this, el/*, userConfig*/);
7487 this.beforeInitEvent.fire(Dialog);
7489 Dom.addClass(this.element, Dialog.CSS_DIALOG);
7491 this.cfg.setProperty("visible", false);
7494 this.cfg.applyConfig(userConfig, true);
7497 this.showEvent.subscribe(this.focusFirst, this, true);
7498 this.beforeHideEvent.subscribe(this.blurButtons, this, true);
7500 this.subscribe("changeBody", this.registerForm);
7502 this.initEvent.fire(Dialog);
7506 * Submits the Dialog's form depending on the value of the
7507 * "postmethod" configuration property. <strong>Please note:
7508 * </strong> As of version 2.3 this method will automatically handle
7509 * asyncronous file uploads should the Dialog instance's form contain
7510 * <code><input type="file"></code> elements. If a Dialog
7511 * instance will be handling asyncronous file uploads, its
7512 * <code>callback</code> property will need to be setup with a
7513 * <code>upload</code> handler rather than the standard
7514 * <code>success</code> and, or <code>failure</code> handlers. For more
7515 * information, see the <a href="http://developer.yahoo.com/yui/
7516 * connection/#file">Connection Manager documenation on file uploads</a>.
7519 doSubmit: function () {
7521 var Connect = YAHOO.util.Connect,
7523 bUseFileUpload = false,
7524 bUseSecureFileUpload = false,
7530 switch (this.cfg.getProperty("postmethod")) {
7533 aElements = oForm.elements;
7534 nElements = aElements.length;
7536 if (nElements > 0) {
7539 if (aElements[i].type == "file") {
7540 bUseFileUpload = true;
7547 if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
7548 bUseSecureFileUpload = true;
7551 formAttrs = this._getFormAttributes(oForm);
7553 Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
7555 var postData = this.cfg.getProperty("postdata");
7556 var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
7558 this.asyncSubmitEvent.fire(c);
7564 this.formSubmitEvent.fire();
7569 this.manualSubmitEvent.fire();
7575 * Retrieves important attributes (currently method and action) from
7576 * the form element, accounting for any elements which may have the same name
7577 * as the attributes. Defaults to "POST" and "" for method and action respectively
7578 * if the attribute cannot be retrieved.
7580 * @method _getFormAttributes
7582 * @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
7583 * @return {Object} Object literal, with method and action String properties.
7585 _getFormAttributes : function(oForm){
7592 if (oForm.getAttributeNode) {
7593 var action = oForm.getAttributeNode("action");
7594 var method = oForm.getAttributeNode("method");
7597 attrs.action = action.value;
7601 attrs.method = method.value;
7605 attrs.action = oForm.getAttribute("action");
7606 attrs.method = oForm.getAttribute("method");
7610 attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
7611 attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
7617 * Prepares the Dialog's internal FORM object, creating one if one is
7618 * not currently present.
7619 * @method registerForm
7621 registerForm: function() {
7623 var form = this.element.getElementsByTagName("form")[0];
7626 if (this.form == form && Dom.isAncestor(this.element, this.form)) {
7629 Event.purgeElement(this.form);
7635 form = document.createElement("form");
7636 form.name = "frm_" + this.id;
7637 this.body.appendChild(form);
7642 Event.on(form, "submit", this._submitHandler, this, true);
7647 * Internal handler for the form submit event
7649 * @method _submitHandler
7651 * @param {DOMEvent} e The DOM Event object
7653 _submitHandler : function(e) {
7660 * Sets up a tab, shift-tab loop between the first and last elements
7661 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
7662 * instance properties, which are reset everytime this method is invoked.
7664 * @method setTabLoop
7665 * @param {HTMLElement} firstElement
7666 * @param {HTMLElement} lastElement
7669 setTabLoop : function(firstElement, lastElement) {
7671 firstElement = firstElement || this.firstButton;
7672 lastElement = this.lastButton || lastElement;
7674 Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
7678 * Configures instance properties, pointing to the
7679 * first and last focusable elements in the Dialog's form.
7681 * @method setFirstLastFocusable
7683 setFirstLastFocusable : function() {
7685 Dialog.superclass.setFirstLastFocusable.call(this);
7687 var i, l, el, elements = this.focusableElements;
7689 this.firstFormElement = null;
7690 this.lastFormElement = null;
7692 if (this.form && elements && elements.length > 0) {
7693 l = elements.length;
7695 for (i = 0; i < l; ++i) {
7697 if (this.form === el.form) {
7698 this.firstFormElement = el;
7703 for (i = l-1; i >= 0; --i) {
7705 if (this.form === el.form) {
7706 this.lastFormElement = el;
7713 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7715 * The default event handler fired when the "close" property is
7716 * changed. The method controls the appending or hiding of the close
7717 * icon at the top right of the Dialog.
7718 * @method configClose
7719 * @param {String} type The CustomEvent type (usually the property name)
7720 * @param {Object[]} args The CustomEvent arguments. For
7721 * configuration handlers, args[0] will equal the newly applied value
7723 * @param {Object} obj The scope object. For configuration handlers,
7724 * this will usually equal the owner.
7726 configClose: function (type, args, obj) {
7727 Dialog.superclass.configClose.apply(this, arguments);
7731 * Event handler for the close icon
7736 * @param {DOMEvent} e
7738 _doClose : function(e) {
7739 Event.preventDefault(e);
7744 * The default event handler for the "buttons" configuration property
7745 * @method configButtons
7746 * @param {String} type The CustomEvent type (usually the property name)
7747 * @param {Object[]} args The CustomEvent arguments. For configuration
7748 * handlers, args[0] will equal the newly applied value for the property.
7749 * @param {Object} obj The scope object. For configuration handlers,
7750 * this will usually equal the owner.
7752 configButtons: function (type, args, obj) {
7754 var Button = YAHOO.widget.Button,
7756 oInnerElement = this.innerElement,
7765 removeButtonEventHandlers.call(this);
7767 this._aButtons = null;
7769 if (Lang.isArray(aButtons)) {
7771 oSpan = document.createElement("span");
7772 oSpan.className = "button-group";
7773 nButtons = aButtons.length;
7775 this._aButtons = [];
7776 this.defaultHtmlButton = null;
7778 for (i = 0; i < nButtons; i++) {
7779 oButton = aButtons[i];
7782 oYUIButton = new Button({ label: oButton.text});
7783 oYUIButton.appendTo(oSpan);
7785 oButtonEl = oYUIButton.get("element");
7787 if (oButton.isDefault) {
7788 oYUIButton.addClass("default");
7789 this.defaultHtmlButton = oButtonEl;
7792 if (Lang.isFunction(oButton.handler)) {
7794 oYUIButton.set("onclick", {
7795 fn: oButton.handler,
7800 } else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
7802 oYUIButton.set("onclick", {
7803 fn: oButton.handler.fn,
7804 obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7805 scope: (oButton.handler.scope || this)
7810 this._aButtons[this._aButtons.length] = oYUIButton;
7814 oButtonEl = document.createElement("button");
7815 oButtonEl.setAttribute("type", "button");
7817 if (oButton.isDefault) {
7818 oButtonEl.className = "default";
7819 this.defaultHtmlButton = oButtonEl;
7822 oButtonEl.innerHTML = oButton.text;
7824 if (Lang.isFunction(oButton.handler)) {
7825 Event.on(oButtonEl, "click", oButton.handler, this, true);
7826 } else if (Lang.isObject(oButton.handler) &&
7827 Lang.isFunction(oButton.handler.fn)) {
7829 Event.on(oButtonEl, "click",
7831 ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7832 (oButton.handler.scope || this));
7835 oSpan.appendChild(oButtonEl);
7836 this._aButtons[this._aButtons.length] = oButtonEl;
7839 oButton.htmlButton = oButtonEl;
7842 this.firstButton = oButtonEl;
7845 if (i == (nButtons - 1)) {
7846 this.lastButton = oButtonEl;
7850 this.setFooter(oSpan);
7852 oFooter = this.footer;
7854 if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
7855 oInnerElement.appendChild(oFooter);
7858 this.buttonSpan = oSpan;
7860 } else { // Do cleanup
7861 oSpan = this.buttonSpan;
7862 oFooter = this.footer;
7863 if (oSpan && oFooter) {
7864 oFooter.removeChild(oSpan);
7865 this.buttonSpan = null;
7866 this.firstButton = null;
7867 this.lastButton = null;
7868 this.defaultHtmlButton = null;
7872 this.changeContentEvent.fire();
7876 * @method getButtons
7877 * @description Returns an array containing each of the Dialog's
7878 * buttons, by default an array of HTML <code><BUTTON></code>
7879 * elements. If the Dialog's buttons were created using the
7880 * YAHOO.widget.Button class (via the inclusion of the optional Button
7881 * dependancy on the page), an array of YAHOO.widget.Button instances
7885 getButtons: function () {
7886 return this._aButtons || null;
7891 * Sets focus to the first focusable element in the Dialog's form if found,
7892 * else, the default button if found, else the first button defined via the
7893 * "buttons" configuration property.
7896 * This method is invoked when the Dialog is made visible.
7898 * @method focusFirst
7900 focusFirst: function (type, args, obj) {
7902 var el = this.firstFormElement;
7904 if (args && args[1]) {
7905 Event.stopEvent(args[1]);
7911 } catch(oException) {
7915 if (this.defaultHtmlButton) {
7916 this.focusDefaultButton();
7918 this.focusFirstButton();
7924 * Sets focus to the last element in the Dialog's form or the last
7925 * button defined via the "buttons" configuration property.
7928 focusLast: function (type, args, obj) {
7930 var aButtons = this.cfg.getProperty("buttons"),
7931 el = this.lastFormElement;
7933 if (args && args[1]) {
7934 Event.stopEvent(args[1]);
7937 if (aButtons && Lang.isArray(aButtons)) {
7938 this.focusLastButton();
7943 } catch(oException) {
7951 * Helper method to normalize button references. It either returns the
7952 * YUI Button instance for the given element if found,
7953 * or the passes back the HTMLElement reference if a corresponding YUI Button
7954 * reference is not found or YAHOO.widget.Button does not exist on the page.
7956 * @method _getButton
7958 * @param {HTMLElement} button
7959 * @return {YAHOO.widget.Button|HTMLElement}
7961 _getButton : function(button) {
7962 var Button = YAHOO.widget.Button;
7964 // If we have an HTML button and YUI Button is on the page,
7965 // get the YUI Button reference if available.
7966 if (Button && button && button.nodeName && button.id) {
7967 button = Button.getButton(button.id) || button;
7974 * Sets the focus to the button that is designated as the default via
7975 * the "buttons" configuration property. By default, this method is
7976 * called when the Dialog is made visible.
7977 * @method focusDefaultButton
7979 focusDefaultButton: function () {
7980 var button = this._getButton(this.defaultHtmlButton);
7983 Place the call to the "focus" method inside a try/catch
7984 block to prevent IE from throwing JavaScript errors if
7985 the element is disabled or hidden.
7989 } catch(oException) {
7995 * Blurs all the buttons defined via the "buttons"
7996 * configuration property.
7997 * @method blurButtons
7999 blurButtons: function () {
8001 var aButtons = this.cfg.getProperty("buttons"),
8007 if (aButtons && Lang.isArray(aButtons)) {
8008 nButtons = aButtons.length;
8012 oButton = aButtons[i];
8014 oElement = this._getButton(oButton.htmlButton);
8017 Place the call to the "blur" method inside
8018 a try/catch block to prevent IE from
8019 throwing JavaScript errors if the element
8020 is disabled or hidden.
8024 } catch(oException) {
8035 * Sets the focus to the first button created via the "buttons"
8036 * configuration property.
8037 * @method focusFirstButton
8039 focusFirstButton: function () {
8041 var aButtons = this.cfg.getProperty("buttons"),
8045 if (aButtons && Lang.isArray(aButtons)) {
8046 oButton = aButtons[0];
8048 oElement = this._getButton(oButton.htmlButton);
8051 Place the call to the "focus" method inside a
8052 try/catch block to prevent IE from throwing
8053 JavaScript errors if the element is disabled
8058 } catch(oException) {
8067 * Sets the focus to the last button created via the "buttons"
8068 * configuration property.
8069 * @method focusLastButton
8071 focusLastButton: function () {
8073 var aButtons = this.cfg.getProperty("buttons"),
8078 if (aButtons && Lang.isArray(aButtons)) {
8079 nButtons = aButtons.length;
8081 oButton = aButtons[(nButtons - 1)];
8084 oElement = this._getButton(oButton.htmlButton);
8087 Place the call to the "focus" method inside a
8088 try/catch block to prevent IE from throwing
8089 JavaScript errors if the element is disabled
8095 } catch(oException) {
8105 * The default event handler for the "postmethod" configuration property
8106 * @method configPostMethod
8107 * @param {String} type The CustomEvent type (usually the property name)
8108 * @param {Object[]} args The CustomEvent arguments. For
8109 * configuration handlers, args[0] will equal the newly applied value
8111 * @param {Object} obj The scope object. For configuration handlers,
8112 * this will usually equal the owner.
8114 configPostMethod: function (type, args, obj) {
8115 this.registerForm();
8118 // END BUILT-IN PROPERTY EVENT HANDLERS //
8121 * Built-in function hook for writing a validation function that will
8122 * be checked for a "true" value prior to a submit. This function, as
8123 * implemented by default, always returns true, so it should be
8124 * overridden if validation is necessary.
8127 validate: function () {
8132 * Executes a submit of the Dialog if validation
8133 * is successful. By default the Dialog is hidden
8134 * after submission, but you can set the "hideaftersubmit"
8135 * configuration property to false, to prevent the Dialog
8136 * from being hidden.
8140 submit: function () {
8141 if (this.validate()) {
8142 this.beforeSubmitEvent.fire();
8144 this.submitEvent.fire();
8146 if (this.cfg.getProperty("hideaftersubmit")) {
8157 * Executes the cancel of the Dialog followed by a hide.
8160 cancel: function () {
8161 this.cancelEvent.fire();
8166 * Returns a JSON-compatible data structure representing the data
8167 * currently contained in the form.
8169 * @return {Object} A JSON object reprsenting the data of the
8172 getData: function () {
8174 var oForm = this.form,
8193 function isFormElement(p_oElement) {
8194 var sTag = p_oElement.tagName.toUpperCase();
8195 return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
8196 sTag == "SELECT") && p_oElement.name == sName);
8201 aElements = oForm.elements;
8202 nTotalElements = aElements.length;
8205 for (i = 0; i < nTotalElements; i++) {
8206 sName = aElements[i].name;
8209 Using "Dom.getElementsBy" to safeguard user from JS
8210 errors that result from giving a form field (or set of
8211 fields) the same name as a native method of a form
8212 (like "submit") or a DOM collection (such as the "item"
8213 method). Originally tried accessing fields via the
8214 "namedItem" method of the "element" collection, but
8215 discovered that it won't return a collection of fields
8219 oElement = Dom.getElementsBy(isFormElement, "*", oForm);
8220 nElements = oElement.length;
8222 if (nElements > 0) {
8223 if (nElements == 1) {
8224 oElement = oElement[0];
8226 sType = oElement.type;
8227 sTagName = oElement.tagName.toUpperCase();
8231 if (sType == "checkbox") {
8232 oData[sName] = oElement.checked;
8233 } else if (sType != "radio") {
8234 oData[sName] = oElement.value;
8239 oData[sName] = oElement.value;
8243 aOptions = oElement.options;
8244 nOptions = aOptions.length;
8247 for (n = 0; n < nOptions; n++) {
8248 oOption = aOptions[n];
8250 if (oOption.selected) {
8251 sValue = oOption.value;
8252 if (!sValue || sValue === "") {
8253 sValue = oOption.text;
8255 aValues[aValues.length] = sValue;
8258 oData[sName] = aValues;
8263 sType = oElement[0].type;
8266 for (n = 0; n < nElements; n++) {
8267 oRadio = oElement[n];
8268 if (oRadio.checked) {
8269 oData[sName] = oRadio.value;
8277 for (n = 0; n < nElements; n++) {
8278 oCheckbox = oElement[n];
8279 if (oCheckbox.checked) {
8280 aValues[aValues.length] = oCheckbox.value;
8283 oData[sName] = aValues;
8295 * Removes the Panel element from the DOM and sets all child elements
8299 destroy: function () {
8300 removeButtonEventHandlers.call(this);
8302 this._aButtons = null;
8304 var aForms = this.element.getElementsByTagName("form"),
8307 if (aForms.length > 0) {
8311 Event.purgeElement(oForm);
8312 if (oForm.parentNode) {
8313 oForm.parentNode.removeChild(oForm);
8318 Dialog.superclass.destroy.call(this);
8322 * Returns a string representation of the object.
8324 * @return {String} The string representation of the Dialog
8326 toString: function () {
8327 return "Dialog " + this.id;
8337 * SimpleDialog is a simple implementation of Dialog that can be used to
8338 * submit a single value. Forms can be processed in 3 ways -- via an
8339 * asynchronous Connection utility call, a simple form POST or GET,
8341 * @namespace YAHOO.widget
8342 * @class SimpleDialog
8343 * @extends YAHOO.widget.Dialog
8345 * @param {String} el The element ID representing the SimpleDialog
8347 * @param {HTMLElement} el The element representing the SimpleDialog
8348 * @param {Object} userConfig The configuration object literal containing
8349 * the configuration that should be set for this SimpleDialog. See
8350 * configuration documentation for more details.
8352 YAHOO.widget.SimpleDialog = function (el, userConfig) {
8354 YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
8359 var Dom = YAHOO.util.Dom,
8360 SimpleDialog = YAHOO.widget.SimpleDialog,
8363 * Constant representing the SimpleDialog's configuration properties
8364 * @property DEFAULT_CONFIG
8380 suppressEvent: true,
8381 supercedes: ["icon"]
8387 * Constant for the standard network icon for a blocking action
8388 * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
8393 SimpleDialog.ICON_BLOCK = "blckicon";
8396 * Constant for the standard network icon for alarm
8397 * @property YAHOO.widget.SimpleDialog.ICON_ALARM
8402 SimpleDialog.ICON_ALARM = "alrticon";
8405 * Constant for the standard network icon for help
8406 * @property YAHOO.widget.SimpleDialog.ICON_HELP
8411 SimpleDialog.ICON_HELP = "hlpicon";
8414 * Constant for the standard network icon for info
8415 * @property YAHOO.widget.SimpleDialog.ICON_INFO
8420 SimpleDialog.ICON_INFO = "infoicon";
8423 * Constant for the standard network icon for warn
8424 * @property YAHOO.widget.SimpleDialog.ICON_WARN
8429 SimpleDialog.ICON_WARN = "warnicon";
8432 * Constant for the standard network icon for a tip
8433 * @property YAHOO.widget.SimpleDialog.ICON_TIP
8438 SimpleDialog.ICON_TIP = "tipicon";
8441 * Constant representing the name of the CSS class applied to the element
8442 * created by the "icon" configuration property.
8443 * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
8448 SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
8451 * Constant representing the default CSS class used for a SimpleDialog
8452 * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
8457 SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
8460 YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
8463 * Initializes the class's configurable properties which can be changed
8464 * using the SimpleDialog's Config object (cfg).
8465 * @method initDefaultConfig
8467 initDefaultConfig: function () {
8469 SimpleDialog.superclass.initDefaultConfig.call(this);
8471 // Add dialog config properties //
8474 * Sets the informational icon for the SimpleDialog
8479 this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
8480 handler: this.configIcon,
8481 value: DEFAULT_CONFIG.ICON.value,
8482 suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
8486 * Sets the text for the SimpleDialog
8491 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
8492 handler: this.configText,
8493 value: DEFAULT_CONFIG.TEXT.value,
8494 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
8495 supercedes: DEFAULT_CONFIG.TEXT.supercedes
8502 * The SimpleDialog initialization method, which is executed for
8503 * SimpleDialog and all of its subclasses. This method is automatically
8504 * called by the constructor, and sets up all DOM references for
8505 * pre-existing markup, and creates required markup if it is not
8508 * @param {String} el The element ID representing the SimpleDialog
8510 * @param {HTMLElement} el The element representing the SimpleDialog
8511 * @param {Object} userConfig The configuration object literal
8512 * containing the configuration that should be set for this
8513 * SimpleDialog. See configuration documentation for more details.
8515 init: function (el, userConfig) {
8518 Note that we don't pass the user config in here yet because we
8519 only want it executed once, at the lowest subclass level
8522 SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
8524 this.beforeInitEvent.fire(SimpleDialog);
8526 Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
8528 this.cfg.queueProperty("postmethod", "manual");
8531 this.cfg.applyConfig(userConfig, true);
8534 this.beforeRenderEvent.subscribe(function () {
8540 this.initEvent.fire(SimpleDialog);
8545 * Prepares the SimpleDialog's internal FORM object, creating one if one
8546 * is not currently present, and adding the value hidden field.
8547 * @method registerForm
8549 registerForm: function () {
8551 SimpleDialog.superclass.registerForm.call(this);
8553 this.form.innerHTML += "<input type=\"hidden\" name=\"" +
8554 this.id + "\" value=\"\"/>";
8558 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
8561 * Fired when the "icon" property is set.
8562 * @method configIcon
8563 * @param {String} type The CustomEvent type (usually the property name)
8564 * @param {Object[]} args The CustomEvent arguments. For configuration
8565 * handlers, args[0] will equal the newly applied value for the property.
8566 * @param {Object} obj The scope object. For configuration handlers,
8567 * this will usually equal the owner.
8569 configIcon: function (type,args,obj) {
8571 var sIcon = args[0],
8573 sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
8577 if (sIcon && sIcon != "none") {
8579 oIcon = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
8583 oIconParent = oIcon.parentNode;
8587 oIconParent.removeChild(oIcon);
8596 if (sIcon.indexOf(".") == -1) {
8598 oIcon = document.createElement("span");
8599 oIcon.className = (sCSSClass + " " + sIcon);
8600 oIcon.innerHTML = " ";
8604 oIcon = document.createElement("img");
8605 oIcon.src = (this.imageRoot + sIcon);
8606 oIcon.className = sCSSClass;
8613 oBody.insertBefore(oIcon, oBody.firstChild);
8622 * Fired when the "text" property is set.
8623 * @method configText
8624 * @param {String} type The CustomEvent type (usually the property name)
8625 * @param {Object[]} args The CustomEvent arguments. For configuration
8626 * handlers, args[0] will equal the newly applied value for the property.
8627 * @param {Object} obj The scope object. For configuration handlers,
8628 * this will usually equal the owner.
8630 configText: function (type,args,obj) {
8634 this.cfg.refireEvent("icon");
8638 // END BUILT-IN PROPERTY EVENT HANDLERS //
8641 * Returns a string representation of the object.
8643 * @return {String} The string representation of the SimpleDialog
8645 toString: function () {
8646 return "SimpleDialog " + this.id;
8651 * Sets the SimpleDialog's body content to the HTML specified.
8652 * If no body is present, one will be automatically created.
8653 * An empty string can be passed to the method to clear the contents of the body.
8655 * <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
8656 * and <a href="#config_icon">icon</a> configuration properties to set the contents
8657 * of it's body element in accordance with the UI design for a SimpleDialog (an
8658 * icon and message text). Calling setBody on the SimpleDialog will not enforce this
8659 * UI design constraint and will replace the entire contents of the SimpleDialog body.
8660 * It should only be used if you wish the replace the default icon/text body structure
8661 * of a SimpleDialog with your own custom markup.</p>
8664 * @param {String} bodyContent The HTML used to set the body.
8665 * As a convenience, non HTMLElement objects can also be passed into
8666 * the method, and will be treated as strings, with the body innerHTML
8667 * set to their default toString implementations.
8669 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
8671 * @param {DocumentFragment} bodyContent The document fragment
8672 * containing elements which are to be added to the body
8681 * ContainerEffect encapsulates animation transitions that are executed when
8682 * an Overlay is shown or hidden.
8683 * @namespace YAHOO.widget
8684 * @class ContainerEffect
8686 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
8687 * should be associated with
8688 * @param {Object} attrIn The object literal representing the animation
8689 * arguments to be used for the animate-in transition. The arguments for
8690 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8691 * duration(Number), and method(i.e. Easing.easeIn).
8692 * @param {Object} attrOut The object literal representing the animation
8693 * arguments to be used for the animate-out transition. The arguments for
8694 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8695 * duration(Number), and method(i.e. Easing.easeIn).
8696 * @param {HTMLElement} targetElement Optional. The target element that
8697 * should be animated during the transition. Defaults to overlay.element.
8698 * @param {class} Optional. The animation class to instantiate. Defaults to
8699 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
8701 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
8704 animClass = YAHOO.util.Anim;
8708 * The overlay to animate
8710 * @type YAHOO.widget.Overlay
8712 this.overlay = overlay;
8715 * The animation attributes to use when transitioning into view
8719 this.attrIn = attrIn;
8722 * The animation attributes to use when transitioning out of view
8726 this.attrOut = attrOut;
8729 * The target element to be animated
8730 * @property targetElement
8733 this.targetElement = targetElement || overlay.element;
8736 * The animation class to use for animating the overlay
8737 * @property animClass
8740 this.animClass = animClass;
8745 var Dom = YAHOO.util.Dom,
8746 CustomEvent = YAHOO.util.CustomEvent,
8747 ContainerEffect = YAHOO.widget.ContainerEffect;
8751 * A pre-configured ContainerEffect instance that can be used for fading
8752 * an overlay in and out.
8755 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8756 * @param {Number} dur The duration of the animation
8757 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8759 ContainerEffect.FADE = function (overlay, dur) {
8761 var Easing = YAHOO.util.Easing,
8763 attributes: {opacity:{from:0, to:1}},
8765 method: Easing.easeIn
8768 attributes: {opacity:{to:0}},
8770 method: Easing.easeOut
8772 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
8774 fade.handleUnderlayStart = function() {
8775 var underlay = this.overlay.underlay;
8776 if (underlay && YAHOO.env.ua.ie) {
8777 var hasFilters = (underlay.filters && underlay.filters.length > 0);
8779 Dom.addClass(overlay.element, "yui-effect-fade");
8784 fade.handleUnderlayComplete = function() {
8785 var underlay = this.overlay.underlay;
8786 if (underlay && YAHOO.env.ua.ie) {
8787 Dom.removeClass(overlay.element, "yui-effect-fade");
8791 fade.handleStartAnimateIn = function (type, args, obj) {
8792 Dom.addClass(obj.overlay.element, "hide-select");
8794 if (!obj.overlay.underlay) {
8795 obj.overlay.cfg.refireEvent("underlay");
8798 obj.handleUnderlayStart();
8800 obj.overlay._setDomVisibility(true);
8801 Dom.setStyle(obj.overlay.element, "opacity", 0);
8804 fade.handleCompleteAnimateIn = function (type,args,obj) {
8805 Dom.removeClass(obj.overlay.element, "hide-select");
8807 if (obj.overlay.element.style.filter) {
8808 obj.overlay.element.style.filter = null;
8811 obj.handleUnderlayComplete();
8813 obj.overlay.cfg.refireEvent("iframe");
8814 obj.animateInCompleteEvent.fire();
8817 fade.handleStartAnimateOut = function (type, args, obj) {
8818 Dom.addClass(obj.overlay.element, "hide-select");
8819 obj.handleUnderlayStart();
8822 fade.handleCompleteAnimateOut = function (type, args, obj) {
8823 Dom.removeClass(obj.overlay.element, "hide-select");
8824 if (obj.overlay.element.style.filter) {
8825 obj.overlay.element.style.filter = null;
8827 obj.overlay._setDomVisibility(false);
8828 Dom.setStyle(obj.overlay.element, "opacity", 1);
8830 obj.handleUnderlayComplete();
8832 obj.overlay.cfg.refireEvent("iframe");
8833 obj.animateOutCompleteEvent.fire();
8842 * A pre-configured ContainerEffect instance that can be used for sliding an
8843 * overlay in and out.
8846 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8847 * @param {Number} dur The duration of the animation
8848 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8850 ContainerEffect.SLIDE = function (overlay, dur) {
8851 var Easing = YAHOO.util.Easing,
8853 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
8854 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
8855 clientWidth = Dom.getClientWidth(),
8856 offsetWidth = overlay.element.offsetWidth,
8859 attributes: { points: { to: [x, y] } },
8861 method: Easing.easeIn
8865 attributes: { points: { to: [(clientWidth + 25), y] } },
8867 method: Easing.easeOut
8870 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
8872 slide.handleStartAnimateIn = function (type,args,obj) {
8873 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
8874 obj.overlay.element.style.top = y + "px";
8877 slide.handleTweenAnimateIn = function (type, args, obj) {
8879 var pos = Dom.getXY(obj.overlay.element),
8883 if (Dom.getStyle(obj.overlay.element, "visibility") ==
8884 "hidden" && currentX < x) {
8886 obj.overlay._setDomVisibility(true);
8890 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
8891 obj.overlay.cfg.refireEvent("iframe");
8894 slide.handleCompleteAnimateIn = function (type, args, obj) {
8895 obj.overlay.cfg.setProperty("xy", [x, y], true);
8898 obj.overlay.cfg.refireEvent("iframe");
8899 obj.animateInCompleteEvent.fire();
8902 slide.handleStartAnimateOut = function (type, args, obj) {
8904 var vw = Dom.getViewportWidth(),
8905 pos = Dom.getXY(obj.overlay.element),
8908 obj.animOut.attributes.points.to = [(vw + 25), yso];
8911 slide.handleTweenAnimateOut = function (type, args, obj) {
8913 var pos = Dom.getXY(obj.overlay.element),
8917 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
8918 obj.overlay.cfg.refireEvent("iframe");
8921 slide.handleCompleteAnimateOut = function (type, args, obj) {
8922 obj.overlay._setDomVisibility(false);
8924 obj.overlay.cfg.setProperty("xy", [x, y]);
8925 obj.animateOutCompleteEvent.fire();
8932 ContainerEffect.prototype = {
8935 * Initializes the animation classes and events.
8940 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
8941 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
8943 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
8944 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
8946 this.animateInCompleteEvent = this.createEvent("animateInComplete");
8947 this.animateInCompleteEvent.signature = CustomEvent.LIST;
8949 this.animateOutCompleteEvent =
8950 this.createEvent("animateOutComplete");
8951 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
8953 this.animIn = new this.animClass(this.targetElement,
8954 this.attrIn.attributes, this.attrIn.duration,
8955 this.attrIn.method);
8957 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
8958 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
8960 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
8963 this.animOut = new this.animClass(this.targetElement,
8964 this.attrOut.attributes, this.attrOut.duration,
8965 this.attrOut.method);
8967 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
8968 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
8969 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
8975 * Triggers the in-animation.
8978 animateIn: function () {
8979 this.beforeAnimateInEvent.fire();
8980 this.animIn.animate();
8984 * Triggers the out-animation.
8985 * @method animateOut
8987 animateOut: function () {
8988 this.beforeAnimateOutEvent.fire();
8989 this.animOut.animate();
8993 * The default onStart handler for the in-animation.
8994 * @method handleStartAnimateIn
8995 * @param {String} type The CustomEvent type
8996 * @param {Object[]} args The CustomEvent arguments
8997 * @param {Object} obj The scope object
8999 handleStartAnimateIn: function (type, args, obj) { },
9002 * The default onTween handler for the in-animation.
9003 * @method handleTweenAnimateIn
9004 * @param {String} type The CustomEvent type
9005 * @param {Object[]} args The CustomEvent arguments
9006 * @param {Object} obj The scope object
9008 handleTweenAnimateIn: function (type, args, obj) { },
9011 * The default onComplete handler for the in-animation.
9012 * @method handleCompleteAnimateIn
9013 * @param {String} type The CustomEvent type
9014 * @param {Object[]} args The CustomEvent arguments
9015 * @param {Object} obj The scope object
9017 handleCompleteAnimateIn: function (type, args, obj) { },
9020 * The default onStart handler for the out-animation.
9021 * @method handleStartAnimateOut
9022 * @param {String} type The CustomEvent type
9023 * @param {Object[]} args The CustomEvent arguments
9024 * @param {Object} obj The scope object
9026 handleStartAnimateOut: function (type, args, obj) { },
9029 * The default onTween handler for the out-animation.
9030 * @method handleTweenAnimateOut
9031 * @param {String} type The CustomEvent type
9032 * @param {Object[]} args The CustomEvent arguments
9033 * @param {Object} obj The scope object
9035 handleTweenAnimateOut: function (type, args, obj) { },
9038 * The default onComplete handler for the out-animation.
9039 * @method handleCompleteAnimateOut
9040 * @param {String} type The CustomEvent type
9041 * @param {Object[]} args The CustomEvent arguments
9042 * @param {Object} obj The scope object
9044 handleCompleteAnimateOut: function (type, args, obj) { },
9047 * Returns a string representation of the object.
9049 * @return {String} The string representation of the ContainerEffect
9051 toString: function () {
9052 var output = "ContainerEffect";
9054 output += " [" + this.overlay.toString() + "]";
9060 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
9064 YAHOO.register("container", YAHOO.widget.Module, {version: "2.7.0", build: "1799"});