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} overrideContext Optional. If true, will override
541 * "this" within the handler to map to the scope Object passed into the
543 * @return {Boolean} True, if the subscription was successful,
546 subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
548 var property = this.config[key.toLowerCase()];
550 if (property && property.event) {
551 if (!Config.alreadySubscribed(property.event, handler, obj)) {
552 property.event.subscribe(handler, obj, overrideContext);
562 * Unsubscribes an external handler from the change event for any
564 * @method unsubscribeFromConfigEvent
565 * @param {String} key The property name
566 * @param {Function} handler The handler function to use subscribe to
567 * the property's event
568 * @param {Object} obj The Object to use for scoping the event
569 * handler (see CustomEvent documentation)
570 * @return {Boolean} True, if the unsubscription was successful,
573 unsubscribeFromConfigEvent: function (key, handler, obj) {
574 var property = this.config[key.toLowerCase()];
575 if (property && property.event) {
576 return property.event.unsubscribe(handler, obj);
583 * Returns a string representation of the Config object
585 * @return {String} The Config object in string format.
587 toString: function () {
588 var output = "Config";
590 output += " [" + this.owner.toString() + "]";
596 * Returns a string representation of the Config object's current
598 * @method outputEventQueue
599 * @return {String} The string list of CustomEvents currently queued
602 outputEventQueue: function () {
607 nQueue = this.eventQueue.length;
609 for (q = 0; q < nQueue; q++) {
610 queueItem = this.eventQueue[q];
612 output += queueItem[0] + "=" + queueItem[1] + ", ";
619 * Sets all properties to null, unsubscribes all listeners from each
620 * property's change event and all listeners from the configChangedEvent.
623 destroy: function () {
625 var oConfig = this.config,
630 for (sProperty in oConfig) {
632 if (Lang.hasOwnProperty(oConfig, sProperty)) {
634 oProperty = oConfig[sProperty];
636 oProperty.event.unsubscribeAll();
637 oProperty.event = null;
643 this.configChangedEvent.unsubscribeAll();
645 this.configChangedEvent = null;
648 this.initialConfig = null;
649 this.eventQueue = null;
658 * Checks to determine if a particular function/Object pair are already
659 * subscribed to the specified CustomEvent
660 * @method YAHOO.util.Config.alreadySubscribed
662 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
664 * @param {Function} fn The function to look for in the subscribers list
665 * @param {Object} obj The execution scope Object for the subscription
666 * @return {Boolean} true, if the function/Object pair is already subscribed
667 * to the CustomEvent passed in
669 Config.alreadySubscribed = function (evt, fn, obj) {
671 var nSubscribers = evt.subscribers.length,
675 if (nSubscribers > 0) {
676 i = nSubscribers - 1;
678 subsc = evt.subscribers[i];
679 if (subsc && subsc.obj == obj && subsc.fn == fn) {
690 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 "DESTROY": "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.DESTROY);
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 YUILibrary 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 // Setting the background color fixes an issue with IE6/IE7, where
1410 // elements in the DOM, with -ve margin-top which positioned them
1411 // offscreen (so they would be overlapped by the iframe and its -ve top
1412 // setting), would have their -ve margin-top ignored, when the iframe
1414 oIFrame.style.backgroundColor = "transparent";
1416 oIFrame.style.borderWidth = "0";
1417 oIFrame.style.width = "2em";
1418 oIFrame.style.height = "2em";
1419 oIFrame.style.left = "0";
1420 oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1421 oIFrame.style.visibility = "visible";
1424 Don't open/close the document for Gecko like we used to, since it
1425 leads to duplicate cookies. (See YUILibrary bug #1721755)
1428 oDoc = oIFrame.contentWindow.document;
1434 if (oIFrame && oIFrame.contentWindow) {
1435 Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1437 if (!Module.textResizeInitialized) {
1438 if (supportsCWResize) {
1439 if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1441 This will fail in IE if document.domain has
1442 changed, so we must change the listener to
1443 use the oIFrame element instead
1445 Event.on(oIFrame, "resize", fireTextResize);
1448 Module.textResizeInitialized = true;
1450 this.resizeMonitor = oIFrame;
1456 * Text resize monitor helper method.
1457 * Determines if the browser supports resize events on iframe content windows.
1460 * @method _supportsCWResize
1462 _supportsCWResize : function() {
1464 Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1465 Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1467 We don't want to start sniffing for patch versions, so fire textResize the same
1468 way on all FF2 flavors
1470 var bSupported = true;
1471 if (UA.gecko && UA.gecko <= 1.8) {
1478 * Event handler fired when the resize monitor element is resized.
1479 * @method onDomResize
1480 * @param {DOMEvent} e The DOM resize event
1481 * @param {Object} obj The scope object passed to the handler
1483 onDomResize: function (e, obj) {
1485 var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1487 this.resizeMonitor.style.top = nTop + "px";
1488 this.resizeMonitor.style.left = "0";
1492 * Sets the Module's header content to the string specified, or appends
1493 * the passed element to the header. If no header is present, one will
1494 * be automatically created. An empty string can be passed to the method
1495 * to clear the contents of the header.
1498 * @param {String} headerContent The string used to set the header.
1499 * As a convenience, non HTMLElement objects can also be passed into
1500 * the method, and will be treated as strings, with the header innerHTML
1501 * set to their default toString implementations.
1503 * @param {HTMLElement} headerContent The HTMLElement to append to
1505 * @param {DocumentFragment} headerContent The document fragment
1506 * containing elements which are to be added to the header
1508 setHeader: function (headerContent) {
1509 var oHeader = this.header || (this.header = createHeader());
1511 if (headerContent.nodeName) {
1512 oHeader.innerHTML = "";
1513 oHeader.appendChild(headerContent);
1515 oHeader.innerHTML = headerContent;
1518 if (this._rendered) {
1519 this._renderHeader();
1522 this.changeHeaderEvent.fire(headerContent);
1523 this.changeContentEvent.fire();
1528 * Appends the passed element to the header. If no header is present,
1529 * one will be automatically created.
1530 * @method appendToHeader
1531 * @param {HTMLElement | DocumentFragment} element The element to
1532 * append to the header. In the case of a document fragment, the
1533 * children of the fragment will be appended to the header.
1535 appendToHeader: function (element) {
1536 var oHeader = this.header || (this.header = createHeader());
1538 oHeader.appendChild(element);
1540 this.changeHeaderEvent.fire(element);
1541 this.changeContentEvent.fire();
1546 * Sets the Module's body content to the HTML specified.
1548 * If no body is present, one will be automatically created.
1550 * An empty string can be passed to the method to clear the contents of the body.
1552 * @param {String} bodyContent The HTML used to set the body.
1553 * As a convenience, non HTMLElement objects can also be passed into
1554 * the method, and will be treated as strings, with the body innerHTML
1555 * set to their default toString implementations.
1557 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1558 * child of the body element.
1560 * @param {DocumentFragment} bodyContent The document fragment
1561 * containing elements which are to be added to the body
1563 setBody: function (bodyContent) {
1564 var oBody = this.body || (this.body = createBody());
1566 if (bodyContent.nodeName) {
1567 oBody.innerHTML = "";
1568 oBody.appendChild(bodyContent);
1570 oBody.innerHTML = bodyContent;
1573 if (this._rendered) {
1577 this.changeBodyEvent.fire(bodyContent);
1578 this.changeContentEvent.fire();
1582 * Appends the passed element to the body. If no body is present, one
1583 * will be automatically created.
1584 * @method appendToBody
1585 * @param {HTMLElement | DocumentFragment} element The element to
1586 * append to the body. In the case of a document fragment, the
1587 * children of the fragment will be appended to the body.
1590 appendToBody: function (element) {
1591 var oBody = this.body || (this.body = createBody());
1593 oBody.appendChild(element);
1595 this.changeBodyEvent.fire(element);
1596 this.changeContentEvent.fire();
1601 * Sets the Module's footer content to the HTML specified, or appends
1602 * the passed element to the footer. If no footer is present, one will
1603 * be automatically created. An empty string can be passed to the method
1604 * to clear the contents of the footer.
1606 * @param {String} footerContent The HTML used to set the footer
1607 * As a convenience, non HTMLElement objects can also be passed into
1608 * the method, and will be treated as strings, with the footer innerHTML
1609 * set to their default toString implementations.
1611 * @param {HTMLElement} footerContent The HTMLElement to append to
1614 * @param {DocumentFragment} footerContent The document fragment containing
1615 * elements which are to be added to the footer
1617 setFooter: function (footerContent) {
1619 var oFooter = this.footer || (this.footer = createFooter());
1621 if (footerContent.nodeName) {
1622 oFooter.innerHTML = "";
1623 oFooter.appendChild(footerContent);
1625 oFooter.innerHTML = footerContent;
1628 if (this._rendered) {
1629 this._renderFooter();
1632 this.changeFooterEvent.fire(footerContent);
1633 this.changeContentEvent.fire();
1637 * Appends the passed element to the footer. If no footer is present,
1638 * one will be automatically created.
1639 * @method appendToFooter
1640 * @param {HTMLElement | DocumentFragment} element The element to
1641 * append to the footer. In the case of a document fragment, the
1642 * children of the fragment will be appended to the footer
1644 appendToFooter: function (element) {
1646 var oFooter = this.footer || (this.footer = createFooter());
1648 oFooter.appendChild(element);
1650 this.changeFooterEvent.fire(element);
1651 this.changeContentEvent.fire();
1656 * Renders the Module by inserting the elements that are not already
1657 * in the main Module into their correct places. Optionally appends
1658 * the Module to the specified node prior to the render's execution.
1660 * For Modules without existing markup, the appendToNode argument
1661 * is REQUIRED. If this argument is ommitted and the current element is
1662 * not present in the document, the function will return false,
1663 * indicating that the render was a failure.
1666 * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1667 * then the module is rendered as the first child of the body element,
1668 * and not appended to it, to avoid Operation Aborted errors in IE when
1669 * rendering the module before window's load event is fired. You can
1670 * use the appendtodocumentbody configuration property to change this
1671 * to append to document.body if required.
1674 * @param {String} appendToNode The element id to which the Module
1675 * should be appended to prior to rendering <em>OR</em>
1676 * @param {HTMLElement} appendToNode The element to which the Module
1677 * should be appended to prior to rendering
1678 * @param {HTMLElement} moduleElement OPTIONAL. The element that
1679 * represents the actual Standard Module container.
1680 * @return {Boolean} Success or failure of the render
1682 render: function (appendToNode, moduleElement) {
1686 function appendTo(parentNode) {
1687 if (typeof parentNode == "string") {
1688 parentNode = document.getElementById(parentNode);
1692 me._addToParent(parentNode, me.element);
1693 me.appendEvent.fire();
1697 this.beforeRenderEvent.fire();
1699 if (! moduleElement) {
1700 moduleElement = this.element;
1704 appendTo(appendToNode);
1706 // No node was passed in. If the element is not already in the Dom, this fails
1707 if (! Dom.inDocument(this.element)) {
1712 this._renderHeader(moduleElement);
1713 this._renderBody(moduleElement);
1714 this._renderFooter(moduleElement);
1716 this._rendered = true;
1718 this.renderEvent.fire();
1723 * Renders the currently set header into it's proper position under the
1724 * module element. If the module element is not provided, "this.element"
1727 * @method _renderHeader
1729 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1731 _renderHeader: function(moduleElement){
1732 moduleElement = moduleElement || this.element;
1734 // Need to get everything into the DOM if it isn't already
1735 if (this.header && !Dom.inDocument(this.header)) {
1736 // There is a header, but it's not in the DOM yet. Need to add it.
1737 var firstChild = moduleElement.firstChild;
1739 moduleElement.insertBefore(this.header, firstChild);
1741 moduleElement.appendChild(this.header);
1747 * Renders the currently set body into it's proper position under the
1748 * module element. If the module element is not provided, "this.element"
1751 * @method _renderBody
1753 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1755 _renderBody: function(moduleElement){
1756 moduleElement = moduleElement || this.element;
1758 if (this.body && !Dom.inDocument(this.body)) {
1759 // There is a body, but it's not in the DOM yet. Need to add it.
1760 if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1761 moduleElement.insertBefore(this.body, this.footer);
1763 moduleElement.appendChild(this.body);
1769 * Renders the currently set footer into it's proper position under the
1770 * module element. If the module element is not provided, "this.element"
1773 * @method _renderFooter
1775 * @param {HTMLElement} moduleElement Optional. A reference to the module element
1777 _renderFooter: function(moduleElement){
1778 moduleElement = moduleElement || this.element;
1780 if (this.footer && !Dom.inDocument(this.footer)) {
1781 // There is a footer, but it's not in the DOM yet. Need to add it.
1782 moduleElement.appendChild(this.footer);
1787 * Removes the Module element from the DOM and sets all child elements
1791 destroy: function () {
1796 Event.purgeElement(this.element, true);
1797 parent = this.element.parentNode;
1801 parent.removeChild(this.element);
1804 this.element = null;
1809 Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1814 this.destroyEvent.fire();
1818 * Shows the Module element by setting the visible configuration
1819 * property to true. Also fires two events: beforeShowEvent prior to
1820 * the visibility change, and showEvent after.
1824 this.cfg.setProperty("visible", true);
1828 * Hides the Module element by setting the visible configuration
1829 * property to false. Also fires two events: beforeHideEvent prior to
1830 * the visibility change, and hideEvent after.
1834 this.cfg.setProperty("visible", false);
1837 // BUILT-IN EVENT HANDLERS FOR MODULE //
1839 * Default event handler for changing the visibility property of a
1840 * Module. By default, this is achieved by switching the "display" style
1841 * between "block" and "none".
1842 * This method is responsible for firing showEvent and hideEvent.
1843 * @param {String} type The CustomEvent type (usually the property name)
1844 * @param {Object[]} args The CustomEvent arguments. For configuration
1845 * handlers, args[0] will equal the newly applied value for the property.
1846 * @param {Object} obj The scope object. For configuration handlers,
1847 * this will usually equal the owner.
1848 * @method configVisible
1850 configVisible: function (type, args, obj) {
1851 var visible = args[0];
1853 this.beforeShowEvent.fire();
1854 Dom.setStyle(this.element, "display", "block");
1855 this.showEvent.fire();
1857 this.beforeHideEvent.fire();
1858 Dom.setStyle(this.element, "display", "none");
1859 this.hideEvent.fire();
1864 * Default event handler for the "monitorresize" configuration property
1865 * @param {String} type The CustomEvent type (usually the property name)
1866 * @param {Object[]} args The CustomEvent arguments. For configuration
1867 * handlers, args[0] will equal the newly applied value for the property.
1868 * @param {Object} obj The scope object. For configuration handlers,
1869 * this will usually equal the owner.
1870 * @method configMonitorResize
1872 configMonitorResize: function (type, args, obj) {
1873 var monitor = args[0];
1875 this.initResizeMonitor();
1877 Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1878 this.resizeMonitor = null;
1883 * This method is a protected helper, used when constructing the DOM structure for the module
1884 * to account for situations which may cause Operation Aborted errors in IE. It should not
1885 * be used for general DOM construction.
1887 * If the parentNode is not document.body, the element is appended as the last element.
1890 * If the parentNode is document.body the element is added as the first child to help
1891 * prevent Operation Aborted errors in IE.
1894 * @param {parentNode} The HTML element to which the element will be added
1895 * @param {element} The HTML element to be added to parentNode's children
1896 * @method _addToParent
1899 _addToParent: function(parentNode, element) {
1900 if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1901 parentNode.insertBefore(element, parentNode.firstChild);
1903 parentNode.appendChild(element);
1908 * Returns a String representation of the Object.
1910 * @return {String} The string representation of the Module
1912 toString: function () {
1913 return "Module " + this.id;
1917 YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1923 * Overlay is a Module that is absolutely positioned above the page flow. It
1924 * has convenience methods for positioning and sizing, as well as options for
1925 * controlling zIndex and constraining the Overlay's position to the current
1926 * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1927 * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1928 * properly rendered above SELECT elements.
1929 * @namespace YAHOO.widget
1931 * @extends YAHOO.widget.Module
1932 * @param {String} el The element ID representing the Overlay <em>OR</em>
1933 * @param {HTMLElement} el The element representing the Overlay
1934 * @param {Object} userConfig The configuration object literal containing
1935 * the configuration that should be set for this Overlay. See configuration
1936 * documentation for more details.
1939 YAHOO.widget.Overlay = function (el, userConfig) {
1940 YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1943 var Lang = YAHOO.lang,
1944 CustomEvent = YAHOO.util.CustomEvent,
1945 Module = YAHOO.widget.Module,
1946 Event = YAHOO.util.Event,
1947 Dom = YAHOO.util.Dom,
1948 Config = YAHOO.util.Config,
1950 Overlay = YAHOO.widget.Overlay,
1952 _SUBSCRIBE = "subscribe",
1953 _UNSUBSCRIBE = "unsubscribe",
1954 _CONTAINED = "contained",
1959 * Constant representing the name of the Overlay's events
1960 * @property EVENT_TYPES
1966 "BEFORE_MOVE": "beforeMove",
1971 * Constant representing the Overlay's configuration properties
1972 * @property DEFAULT_CONFIG
1981 validator: Lang.isNumber,
1982 suppressEvent: true,
1983 supercedes: ["iframe"]
1988 validator: Lang.isNumber,
1989 suppressEvent: true,
1990 supercedes: ["iframe"]
1995 suppressEvent: true,
1996 supercedes: ["iframe"]
2001 suppressEvent: true,
2002 supercedes: ["iframe"]
2008 supercedes: ["iframe", "visible"]
2013 suppressEvent: true,
2014 supercedes: ["context", "fixedcenter", "iframe"]
2019 suppressEvent: true,
2020 supercedes: ["context", "fixedcenter", "iframe"]
2023 "AUTO_FILL_HEIGHT" : {
2024 key: "autofillheight",
2025 supercedes: ["height"],
2034 "CONSTRAIN_TO_VIEWPORT": {
2035 key: "constraintoviewport",
2037 validator: Lang.isBoolean,
2038 supercedes: ["iframe", "x", "y", "xy"]
2043 value: (UA.ie == 6 ? true : false),
2044 validator: Lang.isBoolean,
2045 supercedes: ["zindex"]
2048 "PREVENT_CONTEXT_OVERLAP": {
2049 key: "preventcontextoverlap",
2051 validator: Lang.isBoolean,
2052 supercedes: ["constraintoviewport"]
2058 * The URL that will be placed in the iframe
2059 * @property YAHOO.widget.Overlay.IFRAME_SRC
2064 Overlay.IFRAME_SRC = "javascript:false;";
2067 * Number representing how much the iframe shim should be offset from each
2068 * side of an Overlay instance, in pixels.
2069 * @property YAHOO.widget.Overlay.IFRAME_SRC
2075 Overlay.IFRAME_OFFSET = 3;
2078 * Number representing the minimum distance an Overlay instance should be
2079 * positioned relative to the boundaries of the browser's viewport, in pixels.
2080 * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2086 Overlay.VIEWPORT_OFFSET = 10;
2089 * Constant representing the top left corner of an element, used for
2090 * configuring the context element alignment
2091 * @property YAHOO.widget.Overlay.TOP_LEFT
2096 Overlay.TOP_LEFT = "tl";
2099 * Constant representing the top right corner of an element, used for
2100 * configuring the context element alignment
2101 * @property YAHOO.widget.Overlay.TOP_RIGHT
2106 Overlay.TOP_RIGHT = "tr";
2109 * Constant representing the top bottom left corner of an element, used for
2110 * configuring the context element alignment
2111 * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2116 Overlay.BOTTOM_LEFT = "bl";
2119 * Constant representing the bottom right corner of an element, used for
2120 * configuring the context element alignment
2121 * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2126 Overlay.BOTTOM_RIGHT = "br";
2128 Overlay.PREVENT_OVERLAP_X = {
2135 Overlay.PREVENT_OVERLAP_Y = {
2143 * Constant representing the default CSS class used for an Overlay
2144 * @property YAHOO.widget.Overlay.CSS_OVERLAY
2149 Overlay.CSS_OVERLAY = "yui-overlay";
2152 * Constant representing the default hidden CSS class used for an Overlay. This class is
2153 * applied to the overlay's outer DIV whenever it's hidden.
2155 * @property YAHOO.widget.Overlay.CSS_HIDDEN
2160 Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2163 * Constant representing the default CSS class used for an Overlay iframe shim.
2165 * @property YAHOO.widget.Overlay.CSS_IFRAME
2170 Overlay.CSS_IFRAME = "yui-overlay-iframe";
2173 * Constant representing the names of the standard module elements
2174 * used in the overlay.
2175 * @property YAHOO.widget.Overlay.STD_MOD_RE
2180 Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2183 * A singleton CustomEvent used for reacting to the DOM event for
2185 * @event YAHOO.widget.Overlay.windowScrollEvent
2187 Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2190 * A singleton CustomEvent used for reacting to the DOM event for
2192 * @event YAHOO.widget.Overlay.windowResizeEvent
2194 Overlay.windowResizeEvent = new CustomEvent("windowResize");
2197 * The DOM event handler used to fire the CustomEvent for window scroll
2198 * @method YAHOO.widget.Overlay.windowScrollHandler
2200 * @param {DOMEvent} e The DOM scroll event
2202 Overlay.windowScrollHandler = function (e) {
2203 var t = Event.getTarget(e);
2205 // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2206 // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2207 // - IE doesn't recognize scroll registered on the document.
2209 // Also, when document view is scrolled, IE doesn't provide a target,
2210 // rest of the browsers set target to window.document, apart from opera
2211 // which sets target to window.
2212 if (!t || t === window || t === window.document) {
2215 if (! window.scrollEnd) {
2216 window.scrollEnd = -1;
2219 clearTimeout(window.scrollEnd);
2221 window.scrollEnd = setTimeout(function () {
2222 Overlay.windowScrollEvent.fire();
2226 Overlay.windowScrollEvent.fire();
2232 * The DOM event handler used to fire the CustomEvent for window resize
2233 * @method YAHOO.widget.Overlay.windowResizeHandler
2235 * @param {DOMEvent} e The DOM resize event
2237 Overlay.windowResizeHandler = function (e) {
2240 if (! window.resizeEnd) {
2241 window.resizeEnd = -1;
2244 clearTimeout(window.resizeEnd);
2246 window.resizeEnd = setTimeout(function () {
2247 Overlay.windowResizeEvent.fire();
2250 Overlay.windowResizeEvent.fire();
2255 * A boolean that indicated whether the window resize and scroll events have
2256 * already been subscribed to.
2257 * @property YAHOO.widget.Overlay._initialized
2261 Overlay._initialized = null;
2263 if (Overlay._initialized === null) {
2264 Event.on(window, "scroll", Overlay.windowScrollHandler);
2265 Event.on(window, "resize", Overlay.windowResizeHandler);
2266 Overlay._initialized = true;
2270 * Internal map of special event types, which are provided
2271 * by the instance. It maps the event type to the custom event
2272 * instance. Contains entries for the "windowScroll", "windowResize" and
2273 * "textResize" static container events.
2275 * @property YAHOO.widget.Overlay._TRIGGER_MAP
2280 Overlay._TRIGGER_MAP = {
2281 "windowScroll" : Overlay.windowScrollEvent,
2282 "windowResize" : Overlay.windowResizeEvent,
2283 "textResize" : Module.textResizeEvent
2286 YAHOO.extend(Overlay, Module, {
2290 * Array of default event types which will trigger
2291 * context alignment for the Overlay class.
2293 * <p>The array is empty by default for Overlay,
2294 * but maybe populated in future releases, so classes extending
2295 * Overlay which need to define their own set of CONTEXT_TRIGGERS
2296 * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2297 * value with their own array of values.
2301 * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2304 * @property CONTEXT_TRIGGERS
2308 CONTEXT_TRIGGERS : [],
2311 * The Overlay initialization method, which is executed for Overlay and
2312 * all of its subclasses. This method is automatically called by the
2313 * constructor, and sets up all DOM references for pre-existing markup,
2314 * and creates required markup if it is not already present.
2316 * @param {String} el The element ID representing the Overlay <em>OR</em>
2317 * @param {HTMLElement} el The element representing the Overlay
2318 * @param {Object} userConfig The configuration object literal
2319 * containing the configuration that should be set for this Overlay.
2320 * See configuration documentation for more details.
2322 init: function (el, userConfig) {
2325 Note that we don't pass the user config in here yet because we
2326 only want it executed once, at the lowest subclass level
2329 Overlay.superclass.init.call(this, el/*, userConfig*/);
2331 this.beforeInitEvent.fire(Overlay);
2333 Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2336 this.cfg.applyConfig(userConfig, true);
2339 if (this.platform == "mac" && UA.gecko) {
2341 if (! Config.alreadySubscribed(this.showEvent,
2342 this.showMacGeckoScrollbars, this)) {
2344 this.showEvent.subscribe(this.showMacGeckoScrollbars,
2349 if (! Config.alreadySubscribed(this.hideEvent,
2350 this.hideMacGeckoScrollbars, this)) {
2352 this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2358 this.initEvent.fire(Overlay);
2362 * Initializes the custom events for Overlay which are fired
2363 * automatically at appropriate times by the Overlay class.
2364 * @method initEvents
2366 initEvents: function () {
2368 Overlay.superclass.initEvents.call(this);
2370 var SIGNATURE = CustomEvent.LIST;
2373 * CustomEvent fired before the Overlay is moved.
2374 * @event beforeMoveEvent
2375 * @param {Number} x x coordinate
2376 * @param {Number} y y coordinate
2378 this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2379 this.beforeMoveEvent.signature = SIGNATURE;
2382 * CustomEvent fired after the Overlay is moved.
2384 * @param {Number} x x coordinate
2385 * @param {Number} y y coordinate
2387 this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2388 this.moveEvent.signature = SIGNATURE;
2393 * Initializes the class's configurable properties which can be changed
2394 * using the Overlay's Config object (cfg).
2395 * @method initDefaultConfig
2397 initDefaultConfig: function () {
2399 Overlay.superclass.initDefaultConfig.call(this);
2403 // Add overlay config properties //
2406 * The absolute x-coordinate position of the Overlay
2411 cfg.addProperty(DEFAULT_CONFIG.X.key, {
2413 handler: this.configX,
2414 validator: DEFAULT_CONFIG.X.validator,
2415 suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2416 supercedes: DEFAULT_CONFIG.X.supercedes
2421 * The absolute y-coordinate position of the Overlay
2426 cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2428 handler: this.configY,
2429 validator: DEFAULT_CONFIG.Y.validator,
2430 suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2431 supercedes: DEFAULT_CONFIG.Y.supercedes
2436 * An array with the absolute x and y positions of the Overlay
2441 cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2442 handler: this.configXY,
2443 suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2444 supercedes: DEFAULT_CONFIG.XY.supercedes
2449 * The array of context arguments for context-sensitive positioning.
2453 * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2454 * the 5 array elements described in detail below:
2458 * <dt>contextElementOrId <String|HTMLElement></dt>
2459 * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2460 * <dt>overlayCorner <String></dt>
2461 * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2462 * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2463 * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2464 * <dt>contextCorner <String></dt>
2465 * <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>
2466 * <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2469 * 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>
2470 * 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.
2471 * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2474 * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2475 * 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).
2478 * <dt>xyOffset <Number[]></dt>
2480 * A 2 element Array specifying the X and Y pixel amounts by which the Overlay should be offset from the aligned corner. e.g. [5,0] offsets the Overlay 5 pixels to the left, <em>after</em> aligning the given context corners.
2481 * NOTE: If using this property and no triggers need to be defined, the arrayOfTriggerEvents property should be set to null to maintain correct array positions for the arguments.
2486 * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2487 * align the Overlay's top left corner to the bottom left corner of the
2488 * context element with id "img1".
2491 * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
2492 * align the Overlay's top left corner to the bottom left corner of the
2493 * context element with id "img1", and then offset it by 5 pixels on the Y axis (providing a 5 pixel gap between the bottom of the context element and top of the overlay).
2496 * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2497 * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2504 cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2505 handler: this.configContext,
2506 suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2507 supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2511 * Determines whether or not the Overlay should be anchored
2512 * to the center of the viewport.
2514 * <p>This property can be set to:</p>
2519 * To enable fixed center positioning
2521 * When enabled, the overlay will
2522 * be positioned in the center of viewport when initially displayed, and
2523 * will remain in the center of the viewport whenever the window is
2524 * scrolled or resized.
2527 * If the overlay is too big for the viewport,
2528 * it's top left corner will be aligned with the top left corner of the viewport.
2533 * To disable fixed center positioning.
2534 * <p>In this case the overlay can still be
2535 * centered as a one-off operation, by invoking the <code>center()</code> method,
2536 * however it will not remain centered when the window is scrolled/resized.
2538 * <dt>"contained"<dt>
2539 * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2540 * <p>However, unlike setting the property to <code>true</code>,
2541 * when the property is set to <code>"contained"</code>, if the overlay is
2542 * too big for the viewport, it will not get automatically centered when the
2543 * user scrolls or resizes the window (until the window is large enough to contain the
2544 * overlay). This is useful in cases where the Overlay has both header and footer
2545 * UI controls which the user may need to access.
2550 * @config fixedcenter
2551 * @type Boolean | String
2554 cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2555 handler: this.configFixedCenter,
2556 value: DEFAULT_CONFIG.FIXED_CENTER.value,
2557 validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2558 supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2562 * CSS width of the Overlay.
2567 cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2568 handler: this.configWidth,
2569 suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2570 supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2574 * CSS height of the Overlay.
2579 cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2580 handler: this.configHeight,
2581 suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2582 supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2586 * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2587 * Supported values are "header", "body", "footer".
2589 * @config autofillheight
2593 cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2594 handler: this.configAutoFillHeight,
2595 value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2596 validator : this._validateAutoFill,
2597 supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2601 * CSS z-index of the Overlay.
2606 cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2607 handler: this.configzIndex,
2608 value: DEFAULT_CONFIG.ZINDEX.value
2612 * True if the Overlay should be prevented from being positioned
2613 * out of the viewport.
2614 * @config constraintoviewport
2618 cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2620 handler: this.configConstrainToViewport,
2621 value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2622 validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2623 supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2629 * @description Boolean indicating whether or not the Overlay should
2630 * have an IFRAME shim; used to prevent SELECT elements from
2631 * poking through an Overlay instance in IE6. When set to "true",
2632 * the iframe shim is created when the Overlay instance is intially
2635 * @default true for IE6 and below, false for all other browsers.
2637 cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2639 handler: this.configIframe,
2640 value: DEFAULT_CONFIG.IFRAME.value,
2641 validator: DEFAULT_CONFIG.IFRAME.validator,
2642 supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2647 * @config preventcontextoverlap
2648 * @description Boolean indicating whether or not the Overlay should overlap its
2649 * context element (defined using the "context" configuration property) when the
2650 * "constraintoviewport" configuration property is set to "true".
2654 cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2655 value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2656 validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2657 supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2662 * Moves the Overlay to the specified position. This function is
2663 * identical to calling this.cfg.setProperty("xy", [x,y]);
2665 * @param {Number} x The Overlay's new x position
2666 * @param {Number} y The Overlay's new y position
2668 moveTo: function (x, y) {
2669 this.cfg.setProperty("xy", [x, y]);
2673 * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2674 * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2675 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2676 * @method hideMacGeckoScrollbars
2678 hideMacGeckoScrollbars: function () {
2679 Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2683 * Adds a CSS class ("show-scrollbars") and removes a CSS class
2684 * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2685 * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2686 * @method showMacGeckoScrollbars
2688 showMacGeckoScrollbars: function () {
2689 Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2693 * Internal implementation to set the visibility of the overlay in the DOM.
2695 * @method _setDomVisibility
2696 * @param {boolean} visible Whether to show or hide the Overlay's outer element
2699 _setDomVisibility : function(show) {
2700 Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2701 var hiddenClass = Overlay.CSS_HIDDEN;
2704 Dom.removeClass(this.element, hiddenClass);
2706 Dom.addClass(this.element, hiddenClass);
2710 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2712 * The default event handler fired when the "visible" property is
2713 * changed. This method is responsible for firing showEvent
2715 * @method configVisible
2716 * @param {String} type The CustomEvent type (usually the property name)
2717 * @param {Object[]} args The CustomEvent arguments. For configuration
2718 * handlers, args[0] will equal the newly applied value for the property.
2719 * @param {Object} obj The scope object. For configuration handlers,
2720 * this will usually equal the owner.
2722 configVisible: function (type, args, obj) {
2724 var visible = args[0],
2725 currentVis = Dom.getStyle(this.element, "visibility"),
2726 effect = this.cfg.getProperty("effect"),
2727 effectInstances = [],
2728 isMacGecko = (this.platform == "mac" && UA.gecko),
2729 alreadySubscribed = Config.alreadySubscribed,
2730 eff, ei, e, i, j, k, h,
2734 if (currentVis == "inherit") {
2735 e = this.element.parentNode;
2737 while (e.nodeType != 9 && e.nodeType != 11) {
2738 currentVis = Dom.getStyle(e, "visibility");
2740 if (currentVis != "inherit") {
2747 if (currentVis == "inherit") {
2748 currentVis = "visible";
2753 if (effect instanceof Array) {
2754 nEffects = effect.length;
2756 for (i = 0; i < nEffects; i++) {
2758 effectInstances[effectInstances.length] =
2759 eff.effect(this, eff.duration);
2763 effectInstances[effectInstances.length] =
2764 effect.effect(this, effect.duration);
2768 if (visible) { // Show
2770 this.showMacGeckoScrollbars();
2773 if (effect) { // Animate in
2774 if (visible) { // Animate in if not showing
2775 if (currentVis != "visible" || currentVis === "") {
2776 this.beforeShowEvent.fire();
2777 nEffectInstances = effectInstances.length;
2779 for (j = 0; j < nEffectInstances; j++) {
2780 ei = effectInstances[j];
2781 if (j === 0 && !alreadySubscribed(
2782 ei.animateInCompleteEvent,
2783 this.showEvent.fire, this.showEvent)) {
2786 Delegate showEvent until end
2787 of animateInComplete
2790 ei.animateInCompleteEvent.subscribe(
2791 this.showEvent.fire, this.showEvent, true);
2798 if (currentVis != "visible" || currentVis === "") {
2799 this.beforeShowEvent.fire();
2801 this._setDomVisibility(true);
2803 this.cfg.refireEvent("iframe");
2804 this.showEvent.fire();
2806 this._setDomVisibility(true);
2812 this.hideMacGeckoScrollbars();
2815 if (effect) { // Animate out if showing
2816 if (currentVis == "visible") {
2817 this.beforeHideEvent.fire();
2819 nEffectInstances = effectInstances.length;
2820 for (k = 0; k < nEffectInstances; k++) {
2821 h = effectInstances[k];
2823 if (k === 0 && !alreadySubscribed(
2824 h.animateOutCompleteEvent, this.hideEvent.fire,
2828 Delegate hideEvent until end
2829 of animateOutComplete
2832 h.animateOutCompleteEvent.subscribe(
2833 this.hideEvent.fire, this.hideEvent, true);
2839 } else if (currentVis === "") {
2840 this._setDomVisibility(false);
2843 } else { // Simple hide
2845 if (currentVis == "visible" || currentVis === "") {
2846 this.beforeHideEvent.fire();
2847 this._setDomVisibility(false);
2848 this.hideEvent.fire();
2850 this._setDomVisibility(false);
2857 * Fixed center event handler used for centering on scroll/resize, but only if
2858 * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2859 * the overlay fits within the viewport.
2861 * @method doCenterOnDOMEvent
2863 doCenterOnDOMEvent: function () {
2865 fc = cfg.getProperty("fixedcenter");
2867 if (cfg.getProperty("visible")) {
2868 if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2875 * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2876 * will fit entirely inside the viewport, in both dimensions - width and height.
2878 * @method fitsInViewport
2879 * @return boolean true if the Overlay will fit, false if not
2881 fitsInViewport : function() {
2882 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2883 element = this.element,
2884 elementWidth = element.offsetWidth,
2885 elementHeight = element.offsetHeight,
2886 viewportWidth = Dom.getViewportWidth(),
2887 viewportHeight = Dom.getViewportHeight();
2889 return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2893 * The default event handler fired when the "fixedcenter" property
2895 * @method configFixedCenter
2896 * @param {String} type The CustomEvent type (usually the property name)
2897 * @param {Object[]} args The CustomEvent arguments. For configuration
2898 * handlers, args[0] will equal the newly applied value for the property.
2899 * @param {Object} obj The scope object. For configuration handlers,
2900 * this will usually equal the owner.
2902 configFixedCenter: function (type, args, obj) {
2905 alreadySubscribed = Config.alreadySubscribed,
2906 windowResizeEvent = Overlay.windowResizeEvent,
2907 windowScrollEvent = Overlay.windowScrollEvent;
2912 if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2913 this.beforeShowEvent.subscribe(this.center);
2916 if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2917 windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2920 if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2921 windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2925 this.beforeShowEvent.unsubscribe(this.center);
2927 windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2928 windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2933 * The default event handler fired when the "height" property is changed.
2934 * @method configHeight
2935 * @param {String} type The CustomEvent type (usually the property name)
2936 * @param {Object[]} args The CustomEvent arguments. For configuration
2937 * handlers, args[0] will equal the newly applied value for the property.
2938 * @param {Object} obj The scope object. For configuration handlers,
2939 * this will usually equal the owner.
2941 configHeight: function (type, args, obj) {
2943 var height = args[0],
2946 Dom.setStyle(el, "height", height);
2947 this.cfg.refireEvent("iframe");
2951 * The default event handler fired when the "autofillheight" property is changed.
2952 * @method configAutoFillHeight
2954 * @param {String} type The CustomEvent type (usually the property name)
2955 * @param {Object[]} args The CustomEvent arguments. For configuration
2956 * handlers, args[0] will equal the newly applied value for the property.
2957 * @param {Object} obj The scope object. For configuration handlers,
2958 * this will usually equal the owner.
2960 configAutoFillHeight: function (type, args, obj) {
2961 var fillEl = args[0],
2963 autoFillHeight = "autofillheight",
2965 currEl = cfg.getProperty(autoFillHeight),
2966 autoFill = this._autoFillOnHeightChange;
2968 cfg.unsubscribeFromConfigEvent(height, autoFill);
2969 Module.textResizeEvent.unsubscribe(autoFill);
2970 this.changeContentEvent.unsubscribe(autoFill);
2972 if (currEl && fillEl !== currEl && this[currEl]) {
2973 Dom.setStyle(this[currEl], height, "");
2977 fillEl = Lang.trim(fillEl.toLowerCase());
2979 cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
2980 Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
2981 this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
2983 cfg.setProperty(autoFillHeight, fillEl, true);
2988 * The default event handler fired when the "width" property is changed.
2989 * @method configWidth
2990 * @param {String} type The CustomEvent type (usually the property name)
2991 * @param {Object[]} args The CustomEvent arguments. For configuration
2992 * handlers, args[0] will equal the newly applied value for the property.
2993 * @param {Object} obj The scope object. For configuration handlers,
2994 * this will usually equal the owner.
2996 configWidth: function (type, args, obj) {
2998 var width = args[0],
3001 Dom.setStyle(el, "width", width);
3002 this.cfg.refireEvent("iframe");
3006 * The default event handler fired when the "zIndex" property is changed.
3007 * @method configzIndex
3008 * @param {String} type The CustomEvent type (usually the property name)
3009 * @param {Object[]} args The CustomEvent arguments. For configuration
3010 * handlers, args[0] will equal the newly applied value for the property.
3011 * @param {Object} obj The scope object. For configuration handlers,
3012 * this will usually equal the owner.
3014 configzIndex: function (type, args, obj) {
3016 var zIndex = args[0],
3020 zIndex = Dom.getStyle(el, "zIndex");
3021 if (! zIndex || isNaN(zIndex)) {
3026 if (this.iframe || this.cfg.getProperty("iframe") === true) {
3032 Dom.setStyle(el, "zIndex", zIndex);
3033 this.cfg.setProperty("zIndex", zIndex, true);
3041 * The default event handler fired when the "xy" property is changed.
3043 * @param {String} type The CustomEvent type (usually the property name)
3044 * @param {Object[]} args The CustomEvent arguments. For configuration
3045 * handlers, args[0] will equal the newly applied value for the property.
3046 * @param {Object} obj The scope object. For configuration handlers,
3047 * this will usually equal the owner.
3049 configXY: function (type, args, obj) {
3055 this.cfg.setProperty("x", x);
3056 this.cfg.setProperty("y", y);
3058 this.beforeMoveEvent.fire([x, y]);
3060 x = this.cfg.getProperty("x");
3061 y = this.cfg.getProperty("y");
3064 this.cfg.refireEvent("iframe");
3065 this.moveEvent.fire([x, y]);
3069 * The default event handler fired when the "x" property is changed.
3071 * @param {String} type The CustomEvent type (usually the property name)
3072 * @param {Object[]} args The CustomEvent arguments. For configuration
3073 * handlers, args[0] will equal the newly applied value for the property.
3074 * @param {Object} obj The scope object. For configuration handlers,
3075 * this will usually equal the owner.
3077 configX: function (type, args, obj) {
3080 y = this.cfg.getProperty("y");
3082 this.cfg.setProperty("x", x, true);
3083 this.cfg.setProperty("y", y, true);
3085 this.beforeMoveEvent.fire([x, y]);
3087 x = this.cfg.getProperty("x");
3088 y = this.cfg.getProperty("y");
3090 Dom.setX(this.element, x, true);
3092 this.cfg.setProperty("xy", [x, y], true);
3094 this.cfg.refireEvent("iframe");
3095 this.moveEvent.fire([x, y]);
3099 * The default event handler fired when the "y" property is changed.
3101 * @param {String} type The CustomEvent type (usually the property name)
3102 * @param {Object[]} args The CustomEvent arguments. For configuration
3103 * handlers, args[0] will equal the newly applied value for the property.
3104 * @param {Object} obj The scope object. For configuration handlers,
3105 * this will usually equal the owner.
3107 configY: function (type, args, obj) {
3109 var x = this.cfg.getProperty("x"),
3112 this.cfg.setProperty("x", x, true);
3113 this.cfg.setProperty("y", y, true);
3115 this.beforeMoveEvent.fire([x, y]);
3117 x = this.cfg.getProperty("x");
3118 y = this.cfg.getProperty("y");
3120 Dom.setY(this.element, y, true);
3122 this.cfg.setProperty("xy", [x, y], true);
3124 this.cfg.refireEvent("iframe");
3125 this.moveEvent.fire([x, y]);
3129 * Shows the iframe shim, if it has been enabled.
3130 * @method showIframe
3132 showIframe: function () {
3134 var oIFrame = this.iframe,
3138 oParentNode = this.element.parentNode;
3140 if (oParentNode != oIFrame.parentNode) {
3141 this._addToParent(oParentNode, oIFrame);
3143 oIFrame.style.display = "block";
3148 * Hides the iframe shim, if it has been enabled.
3149 * @method hideIframe
3151 hideIframe: function () {
3153 this.iframe.style.display = "none";
3158 * Syncronizes the size and position of iframe shim to that of its
3159 * corresponding Overlay instance.
3160 * @method syncIframe
3162 syncIframe: function () {
3164 var oIFrame = this.iframe,
3165 oElement = this.element,
3166 nOffset = Overlay.IFRAME_OFFSET,
3167 nDimensionOffset = (nOffset * 2),
3172 oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3173 oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3175 // Position <iframe>
3176 aXY = this.cfg.getProperty("xy");
3178 if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3179 this.syncPosition();
3180 aXY = this.cfg.getProperty("xy");
3182 Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3187 * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3188 * the Overlay element. The zindex of the iframe is set to be one less
3189 * than the Overlay element's zindex.
3191 * <p>NOTE: This method will not bump up the zindex of the Overlay element
3192 * to ensure that the iframe shim has a non-negative zindex.
3193 * If you require the iframe zindex to be 0 or higher, the zindex of
3194 * the Overlay element should be set to a value greater than 0, before
3195 * this method is called.
3197 * @method stackIframe
3199 stackIframe: function () {
3201 var overlayZ = Dom.getStyle(this.element, "zIndex");
3202 if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3203 Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3209 * The default event handler fired when the "iframe" property is changed.
3210 * @method configIframe
3211 * @param {String} type The CustomEvent type (usually the property name)
3212 * @param {Object[]} args The CustomEvent arguments. For configuration
3213 * handlers, args[0] will equal the newly applied value for the property.
3214 * @param {Object} obj The scope object. For configuration handlers,
3215 * this will usually equal the owner.
3217 configIframe: function (type, args, obj) {
3219 var bIFrame = args[0];
3221 function createIFrame() {
3223 var oIFrame = this.iframe,
3224 oElement = this.element,
3228 if (!m_oIFrameTemplate) {
3229 m_oIFrameTemplate = document.createElement("iframe");
3231 if (this.isSecure) {
3232 m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3236 Set the opacity of the <iframe> to 0 so that it
3237 doesn't modify the opacity of any transparent
3238 elements that may be on top of it (like a shadow).
3241 m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3243 Need to set the "frameBorder" property to 0
3244 supress the default <iframe> border in IE.
3245 Setting the CSS "border" property alone
3248 m_oIFrameTemplate.frameBorder = 0;
3251 m_oIFrameTemplate.style.opacity = "0";
3254 m_oIFrameTemplate.style.position = "absolute";
3255 m_oIFrameTemplate.style.border = "none";
3256 m_oIFrameTemplate.style.margin = "0";
3257 m_oIFrameTemplate.style.padding = "0";
3258 m_oIFrameTemplate.style.display = "none";
3259 m_oIFrameTemplate.tabIndex = -1;
3260 m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3263 oIFrame = m_oIFrameTemplate.cloneNode(false);
3264 oIFrame.id = this.id + "_f";
3265 oParent = oElement.parentNode;
3267 var parentNode = oParent || document.body;
3269 this._addToParent(parentNode, oIFrame);
3270 this.iframe = oIFrame;
3274 Show the <iframe> before positioning it since the "setXY"
3275 method of DOM requires the element be in the document
3281 Syncronize the size and position of the <iframe> to that
3287 // Add event listeners to update the <iframe> when necessary
3288 if (!this._hasIframeEventListeners) {
3289 this.showEvent.subscribe(this.showIframe);
3290 this.hideEvent.subscribe(this.hideIframe);
3291 this.changeContentEvent.subscribe(this.syncIframe);
3293 this._hasIframeEventListeners = true;
3297 function onBeforeShow() {
3298 createIFrame.call(this);
3299 this.beforeShowEvent.unsubscribe(onBeforeShow);
3300 this._iframeDeferred = false;
3303 if (bIFrame) { // <iframe> shim is enabled
3305 if (this.cfg.getProperty("visible")) {
3306 createIFrame.call(this);
3308 if (!this._iframeDeferred) {
3309 this.beforeShowEvent.subscribe(onBeforeShow);
3310 this._iframeDeferred = true;
3314 } else { // <iframe> shim is disabled
3317 if (this._hasIframeEventListeners) {
3318 this.showEvent.unsubscribe(this.showIframe);
3319 this.hideEvent.unsubscribe(this.hideIframe);
3320 this.changeContentEvent.unsubscribe(this.syncIframe);
3322 this._hasIframeEventListeners = false;
3328 * Set's the container's XY value from DOM if not already set.
3330 * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3331 * not already set. The method also refire's the XY config property event, so any
3332 * beforeMove, Move event listeners are invoked.
3334 * @method _primeXYFromDOM
3337 _primeXYFromDOM : function() {
3338 if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3339 // Set CFG XY based on DOM XY
3340 this.syncPosition();
3341 // Account for XY being set silently in syncPosition (no moveTo fired/called)
3342 this.cfg.refireEvent("xy");
3343 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3348 * The default event handler fired when the "constraintoviewport"
3349 * property is changed.
3350 * @method configConstrainToViewport
3351 * @param {String} type The CustomEvent type (usually the property name)
3352 * @param {Object[]} args The CustomEvent arguments. For configuration
3353 * handlers, args[0] will equal the newly applied value for
3355 * @param {Object} obj The scope object. For configuration handlers,
3356 * this will usually equal the owner.
3358 configConstrainToViewport: function (type, args, obj) {
3362 if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3363 this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3365 if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3366 this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3369 this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3370 this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3375 * The default event handler fired when the "context" property
3378 * @method configContext
3379 * @param {String} type The CustomEvent type (usually the property name)
3380 * @param {Object[]} args The CustomEvent arguments. For configuration
3381 * handlers, args[0] will equal the newly applied value for the property.
3382 * @param {Object} obj The scope object. For configuration handlers,
3383 * this will usually equal the owner.
3385 configContext: function (type, args, obj) {
3387 var contextArgs = args[0],
3389 elementMagnetCorner,
3390 contextMagnetCorner,
3393 defTriggers = this.CONTEXT_TRIGGERS;
3397 contextEl = contextArgs[0];
3398 elementMagnetCorner = contextArgs[1];
3399 contextMagnetCorner = contextArgs[2];
3400 triggers = contextArgs[3];
3401 offset = contextArgs[4];
3403 if (defTriggers && defTriggers.length > 0) {
3404 triggers = (triggers || []).concat(defTriggers);
3408 if (typeof contextEl == "string") {
3409 this.cfg.setProperty("context", [
3410 document.getElementById(contextEl),
3411 elementMagnetCorner,
3412 contextMagnetCorner,
3418 if (elementMagnetCorner && contextMagnetCorner) {
3419 this.align(elementMagnetCorner, contextMagnetCorner, offset);
3422 if (this._contextTriggers) {
3423 // Unsubscribe Old Set
3424 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3428 // Subscribe New Set
3429 this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3430 this._contextTriggers = triggers;
3437 * Custom Event handler for context alignment triggers. Invokes the align method
3439 * @method _alignOnTrigger
3442 * @param {String} type The event type (not used by the default implementation)
3443 * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3445 _alignOnTrigger: function(type, args) {
3450 * Helper method to locate the custom event instance for the event name string
3451 * passed in. As a convenience measure, any custom events passed in are returned.
3453 * @method _findTriggerCE
3456 * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3457 * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3459 _findTriggerCE : function(t) {
3461 if (t instanceof CustomEvent) {
3463 } else if (Overlay._TRIGGER_MAP[t]) {
3464 tce = Overlay._TRIGGER_MAP[t];
3470 * Utility method that subscribes or unsubscribes the given
3471 * function from the list of trigger events provided.
3473 * @method _processTriggers
3476 * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3477 * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3478 * subscribed/unsubscribed respectively.
3480 * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3481 * we are subscribing or unsubscribing trigger listeners
3483 * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3484 * Context is always set to the overlay instance, and no additional object argument
3485 * get passed to the subscribed function.
3487 _processTriggers : function(triggers, mode, fn) {
3490 for (var i = 0, l = triggers.length; i < l; ++i) {
3492 tce = this._findTriggerCE(t);
3494 tce[mode](fn, this, true);
3501 // END BUILT-IN PROPERTY EVENT HANDLERS //
3503 * Aligns the Overlay to its context element using the specified corner
3504 * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3507 * @param {String} elementAlign The String representing the corner of
3508 * the Overlay that should be aligned to the context element
3509 * @param {String} contextAlign The corner of the context element
3510 * that the elementAlign corner should stick to.
3511 * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3512 * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
3513 * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3515 align: function (elementAlign, contextAlign, xyOffset) {
3517 var contextArgs = this.cfg.getProperty("context"),
3523 function doAlign(v, h) {
3525 var alignX = null, alignY = null;
3527 switch (elementAlign) {
3529 case Overlay.TOP_LEFT:
3534 case Overlay.TOP_RIGHT:
3535 alignX = h - element.offsetWidth;
3539 case Overlay.BOTTOM_LEFT:
3541 alignY = v - element.offsetHeight;
3544 case Overlay.BOTTOM_RIGHT:
3545 alignX = h - element.offsetWidth;
3546 alignY = v - element.offsetHeight;
3550 if (alignX !== null && alignY !== null) {
3552 alignX += xyOffset[0];
3553 alignY += xyOffset[1];
3555 me.moveTo(alignX, alignY);
3560 context = contextArgs[0];
3561 element = this.element;
3564 if (! elementAlign) {
3565 elementAlign = contextArgs[1];
3568 if (! contextAlign) {
3569 contextAlign = contextArgs[2];
3572 if (!xyOffset && contextArgs[4]) {
3573 xyOffset = contextArgs[4];
3576 if (element && context) {
3577 contextRegion = Dom.getRegion(context);
3579 switch (contextAlign) {
3581 case Overlay.TOP_LEFT:
3582 doAlign(contextRegion.top, contextRegion.left);
3585 case Overlay.TOP_RIGHT:
3586 doAlign(contextRegion.top, contextRegion.right);
3589 case Overlay.BOTTOM_LEFT:
3590 doAlign(contextRegion.bottom, contextRegion.left);
3593 case Overlay.BOTTOM_RIGHT:
3594 doAlign(contextRegion.bottom, contextRegion.right);
3602 * The default event handler executed when the moveEvent is fired, if the
3603 * "constraintoviewport" is set to true.
3604 * @method enforceConstraints
3605 * @param {String} type The CustomEvent type (usually the property name)
3606 * @param {Object[]} args The CustomEvent arguments. For configuration
3607 * handlers, args[0] will equal the newly applied value for the property.
3608 * @param {Object} obj The scope object. For configuration handlers,
3609 * this will usually equal the owner.
3611 enforceConstraints: function (type, args, obj) {
3614 var cXY = this.getConstrainedXY(pos[0], pos[1]);
3615 this.cfg.setProperty("x", cXY[0], true);
3616 this.cfg.setProperty("y", cXY[1], true);
3617 this.cfg.setProperty("xy", cXY, true);
3621 * Shared implementation method for getConstrainedX and getConstrainedY.
3624 * Given a coordinate value, returns the calculated coordinate required to
3625 * position the Overlay if it is to be constrained to the viewport, based on the
3626 * current element size, viewport dimensions, scroll values and preventoverlap
3630 * @method _getConstrainedPos
3632 * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3633 * @param {Number} The coordinate value which needs to be constrained
3634 * @return {Number} The constrained coordinate value
3636 _getConstrainedPos: function(pos, val) {
3638 var overlayEl = this.element,
3640 buffer = Overlay.VIEWPORT_OFFSET,
3644 overlaySize = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3645 viewportSize = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3646 docScroll = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3647 overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3649 context = this.cfg.getProperty("context"),
3651 bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3652 bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3654 minConstraint = docScroll + buffer,
3655 maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3657 constrainedVal = val;
3659 if (val < minConstraint || val > maxConstraint) {
3660 if (bPreventContextOverlap) {
3661 constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3663 if (bOverlayFitsInViewport) {
3664 if (val < minConstraint) {
3665 constrainedVal = minConstraint;
3666 } else if (val > maxConstraint) {
3667 constrainedVal = maxConstraint;
3670 constrainedVal = minConstraint;
3675 return constrainedVal;
3679 * Helper method, used to position the Overlap to prevent overlap with the
3680 * context element (used when preventcontextoverlap is enabled)
3682 * @method _preventOverlap
3684 * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3685 * @param {HTMLElement} contextEl The context element
3686 * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3687 * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3688 * @param {Object} docScroll The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3690 * @return {Number} The new coordinate value which was set to prevent overlap
3692 _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3694 var x = (pos == "x"),
3696 buffer = Overlay.VIEWPORT_OFFSET,
3700 contextElPos = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3701 contextElSize = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3703 minRegionSize = contextElPos - buffer,
3704 maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3708 flip = function () {
3711 if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3712 flippedVal = (contextElPos - overlaySize);
3714 flippedVal = (contextElPos + contextElSize);
3717 overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3722 setPosition = function () {
3724 var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3727 if (overlaySize > displayRegionSize) {
3730 All possible positions and values have been
3731 tried, but none were successful, so fall back
3732 to the original size and position.
3738 position = setPosition();
3747 return this.cfg.getProperty(pos);
3751 * Given x coordinate value, returns the calculated x coordinate required to
3752 * position the Overlay if it is to be constrained to the viewport, based on the
3753 * current element size, viewport dimensions and scroll values.
3755 * @param {Number} x The X coordinate value to be constrained
3756 * @return {Number} The constrained x coordinate
3758 getConstrainedX: function (x) {
3759 return this._getConstrainedPos("x", x);
3763 * Given y coordinate value, returns the calculated y coordinate required to
3764 * position the Overlay if it is to be constrained to the viewport, based on the
3765 * current element size, viewport dimensions and scroll values.
3767 * @param {Number} y The Y coordinate value to be constrained
3768 * @return {Number} The constrained y coordinate
3770 getConstrainedY : function (y) {
3771 return this._getConstrainedPos("y", y);
3775 * Given x, y coordinate values, returns the calculated coordinates required to
3776 * position the Overlay if it is to be constrained to the viewport, based on the
3777 * current element size, viewport dimensions and scroll values.
3779 * @param {Number} x The X coordinate value to be constrained
3780 * @param {Number} y The Y coordinate value to be constrained
3781 * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3783 getConstrainedXY: function(x, y) {
3784 return [this.getConstrainedX(x), this.getConstrainedY(y)];
3788 * Centers the container in the viewport.
3791 center: function () {
3793 var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3794 elementWidth = this.element.offsetWidth,
3795 elementHeight = this.element.offsetHeight,
3796 viewPortWidth = Dom.getViewportWidth(),
3797 viewPortHeight = Dom.getViewportHeight(),
3801 if (elementWidth < viewPortWidth) {
3802 x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3804 x = nViewportOffset + Dom.getDocumentScrollLeft();
3807 if (elementHeight < viewPortHeight) {
3808 y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3810 y = nViewportOffset + Dom.getDocumentScrollTop();
3813 this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3814 this.cfg.refireEvent("iframe");
3817 this.forceContainerRedraw();
3822 * Synchronizes the Panel's "xy", "x", and "y" properties with the
3823 * Panel's position in the DOM. This is primarily used to update
3824 * position information during drag & drop.
3825 * @method syncPosition
3827 syncPosition: function () {
3829 var pos = Dom.getXY(this.element);
3831 this.cfg.setProperty("x", pos[0], true);
3832 this.cfg.setProperty("y", pos[1], true);
3833 this.cfg.setProperty("xy", pos, true);
3838 * Event handler fired when the resize monitor element is resized.
3839 * @method onDomResize
3840 * @param {DOMEvent} e The resize DOM event
3841 * @param {Object} obj The scope object
3843 onDomResize: function (e, obj) {
3847 Overlay.superclass.onDomResize.call(this, e, obj);
3849 setTimeout(function () {
3851 me.cfg.refireEvent("iframe");
3852 me.cfg.refireEvent("context");
3857 * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3859 * @method _getComputedHeight
3861 * @param {HTMLElement} el The element for which the content height needs to be determined
3862 * @return {Number} The content box height of the given element, or null if it could not be determined.
3864 _getComputedHeight : (function() {
3866 if (document.defaultView && document.defaultView.getComputedStyle) {
3867 return function(el) {
3869 if (el.ownerDocument && el.ownerDocument.defaultView) {
3870 var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3872 height = parseInt(computed.height, 10);
3875 return (Lang.isNumber(height)) ? height : null;
3878 return function(el) {
3880 if (el.style.pixelHeight) {
3881 height = el.style.pixelHeight;
3883 return (Lang.isNumber(height)) ? height : null;
3889 * autofillheight validator. Verifies that the autofill value is either null
3890 * or one of the strings : "body", "header" or "footer".
3892 * @method _validateAutoFillHeight
3894 * @param {String} val
3895 * @return true, if valid, false otherwise
3897 _validateAutoFillHeight : function(val) {
3898 return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3902 * The default custom event handler executed when the overlay's height is changed,
3903 * if the autofillheight property has been set.
3905 * @method _autoFillOnHeightChange
3907 * @param {String} type The event type
3908 * @param {Array} args The array of arguments passed to event subscribers
3909 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3910 * out the containers height
3912 _autoFillOnHeightChange : function(type, args, el) {
3913 var height = this.cfg.getProperty("height");
3914 if ((height && height !== "auto") || (height === 0)) {
3915 this.fillHeight(el);
3920 * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3921 * otherwise returns the offsetHeight
3922 * @method _getPreciseHeight
3924 * @param {HTMLElement} el
3925 * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3927 _getPreciseHeight : function(el) {
3928 var height = el.offsetHeight;
3930 if (el.getBoundingClientRect) {
3931 var rect = el.getBoundingClientRect();
3932 height = rect.bottom - rect.top;
3940 * Sets the height on the provided header, body or footer element to
3941 * fill out the height of the container. It determines the height of the
3942 * containers content box, based on it's configured height value, and
3943 * sets the height of the autofillheight element to fill out any
3944 * space remaining after the other standard module element heights
3945 * have been accounted for.
3947 * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
3948 * height has not been set on the container, since for an "auto" height container,
3949 * the heights of the header/body/footer will drive the height of the container.</p>
3951 * @method fillHeight
3952 * @param {HTMLElement} el The element which should be resized to fill out the height
3953 * of the container element.
3955 fillHeight : function(el) {
3957 var container = this.innerElement || this.element,
3958 containerEls = [this.header, this.body, this.footer],
3965 for (var i = 0, l = containerEls.length; i < l; i++) {
3966 containerEl = containerEls[i];
3968 if (el !== containerEl) {
3969 filled += this._getPreciseHeight(containerEl);
3978 if (UA.ie || UA.opera) {
3979 // Need to set height to 0, to allow height to be reduced
3980 Dom.setStyle(el, 'height', 0 + 'px');
3983 total = this._getComputedHeight(container);
3985 // Fallback, if we can't get computed value for content height
3986 if (total === null) {
3987 Dom.addClass(container, "yui-override-padding");
3988 total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
3989 Dom.removeClass(container, "yui-override-padding");
3992 remaining = Math.max(total - filled, 0);
3994 Dom.setStyle(el, "height", remaining + "px");
3996 // Re-adjust height if required, to account for el padding and border
3997 if (el.offsetHeight != remaining) {
3998 remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4000 Dom.setStyle(el, "height", remaining + "px");
4006 * Places the Overlay on top of all other instances of
4007 * YAHOO.widget.Overlay.
4008 * @method bringToTop
4010 bringToTop: function () {
4013 oElement = this.element;
4015 function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4017 var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4018 sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4020 nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4021 nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4023 if (nZIndex1 > nZIndex2) {
4025 } else if (nZIndex1 < nZIndex2) {
4032 function isOverlayElement(p_oElement) {
4034 var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4035 Panel = YAHOO.widget.Panel;
4037 if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4038 if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4039 aOverlays[aOverlays.length] = p_oElement.parentNode;
4041 aOverlays[aOverlays.length] = p_oElement;
4046 Dom.getElementsBy(isOverlayElement, "DIV", document.body);
4048 aOverlays.sort(compareZIndexDesc);
4050 var oTopOverlay = aOverlays[0],
4054 nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4056 if (!isNaN(nTopZIndex)) {
4057 var bRequiresBump = false;
4059 if (oTopOverlay != oElement) {
4060 bRequiresBump = true;
4061 } else if (aOverlays.length > 1) {
4062 var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4063 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4064 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4065 bRequiresBump = true;
4068 if (bRequiresBump) {
4069 this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4076 * Removes the Overlay element from the DOM and sets all child
4080 destroy: function () {
4083 this.iframe.parentNode.removeChild(this.iframe);
4088 Overlay.windowResizeEvent.unsubscribe(
4089 this.doCenterOnDOMEvent, this);
4091 Overlay.windowScrollEvent.unsubscribe(
4092 this.doCenterOnDOMEvent, this);
4094 Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4096 if (this._contextTriggers) {
4097 // Unsubscribe context triggers - to cover context triggers which listen for global
4098 // events such as windowResize and windowScroll. Easier just to unsubscribe all
4099 this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4102 Overlay.superclass.destroy.call(this);
4106 * Can be used to force the container to repaint/redraw it's contents.
4108 * By default applies and then removes a 1px bottom margin through the
4109 * application/removal of a "yui-force-redraw" class.
4112 * It is currently used by Overlay to force a repaint for webkit
4113 * browsers, when centering.
4115 * @method forceContainerRedraw
4117 forceContainerRedraw : function() {
4119 Dom.addClass(c.element, "yui-force-redraw");
4120 setTimeout(function() {
4121 Dom.removeClass(c.element, "yui-force-redraw");
4126 * Returns a String representation of the object.
4128 * @return {String} The string representation of the Overlay.
4130 toString: function () {
4131 return "Overlay " + this.id;
4139 * OverlayManager is used for maintaining the focus status of
4140 * multiple Overlays.
4141 * @namespace YAHOO.widget
4142 * @namespace YAHOO.widget
4143 * @class OverlayManager
4145 * @param {Array} overlays Optional. A collection of Overlays to register
4147 * @param {Object} userConfig The object literal representing the user
4148 * configuration of the OverlayManager
4150 YAHOO.widget.OverlayManager = function (userConfig) {
4151 this.init(userConfig);
4154 var Overlay = YAHOO.widget.Overlay,
4155 Event = YAHOO.util.Event,
4156 Dom = YAHOO.util.Dom,
4157 Config = YAHOO.util.Config,
4158 CustomEvent = YAHOO.util.CustomEvent,
4159 OverlayManager = YAHOO.widget.OverlayManager;
4162 * The CSS class representing a focused Overlay
4163 * @property OverlayManager.CSS_FOCUSED
4168 OverlayManager.CSS_FOCUSED = "focused";
4170 OverlayManager.prototype = {
4173 * The class's constructor function
4174 * @property contructor
4177 constructor: OverlayManager,
4180 * The array of Overlays that are currently registered
4181 * @property overlays
4182 * @type YAHOO.widget.Overlay[]
4187 * Initializes the default configuration of the OverlayManager
4188 * @method initDefaultConfig
4190 initDefaultConfig: function () {
4192 * The collection of registered Overlays in use by
4193 * the OverlayManager
4195 * @type YAHOO.widget.Overlay[]
4198 this.cfg.addProperty("overlays", { suppressEvent: true } );
4201 * The default DOM event that should be used to focus an Overlay
4202 * @config focusevent
4204 * @default "mousedown"
4206 this.cfg.addProperty("focusevent", { value: "mousedown" } );
4210 * Initializes the OverlayManager
4212 * @param {Overlay[]} overlays Optional. A collection of Overlays to
4213 * register with the manager.
4214 * @param {Object} userConfig The object literal representing the user
4215 * configuration of the OverlayManager
4217 init: function (userConfig) {
4220 * The OverlayManager's Config object used for monitoring
4221 * configuration properties.
4225 this.cfg = new Config(this);
4227 this.initDefaultConfig();
4230 this.cfg.applyConfig(userConfig, true);
4232 this.cfg.fireQueue();
4235 * The currently activated Overlay
4236 * @property activeOverlay
4238 * @type YAHOO.widget.Overlay
4240 var activeOverlay = null;
4243 * Returns the currently focused Overlay
4245 * @return {Overlay} The currently focused Overlay
4247 this.getActive = function () {
4248 return activeOverlay;
4252 * Focuses the specified Overlay
4254 * @param {Overlay} overlay The Overlay to focus
4255 * @param {String} overlay The id of the Overlay to focus
4257 this.focus = function (overlay) {
4258 var o = this.find(overlay);
4265 * Removes the specified Overlay from the manager
4267 * @param {Overlay} overlay The Overlay to remove
4268 * @param {String} overlay The id of the Overlay to remove
4270 this.remove = function (overlay) {
4272 var o = this.find(overlay),
4276 if (activeOverlay == o) {
4277 activeOverlay = null;
4280 var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4283 // Set it's zindex so that it's sorted to the end.
4284 originalZ = Dom.getStyle(o.element, "zIndex");
4285 o.cfg.setProperty("zIndex", -1000, true);
4288 this.overlays.sort(this.compareZIndexDesc);
4289 this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4291 o.hideEvent.unsubscribe(o.blur);
4292 o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4293 o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4294 o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4297 Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4298 o.cfg.setProperty("zIndex", originalZ, true);
4299 o.cfg.setProperty("manager", null);
4302 /* _managed Flag for custom or existing. Don't want to remove existing */
4303 if (o.focusEvent._managed) { o.focusEvent = null; }
4304 if (o.blurEvent._managed) { o.blurEvent = null; }
4306 if (o.focus._managed) { o.focus = null; }
4307 if (o.blur._managed) { o.blur = null; }
4312 * Removes focus from all registered Overlays in the manager
4315 this.blurAll = function () {
4317 var nOverlays = this.overlays.length,
4320 if (nOverlays > 0) {
4323 this.overlays[i].blur();
4330 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4333 * @method _manageBlur
4334 * @param {Overlay} overlay The overlay instance which got blurred.
4337 this._manageBlur = function (overlay) {
4338 var changed = false;
4339 if (activeOverlay == overlay) {
4340 Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4341 activeOverlay = null;
4348 * Updates the state of the OverlayManager and overlay, as a result of the overlay
4351 * @method _manageFocus
4352 * @param {Overlay} overlay The overlay instance which got focus.
4355 this._manageFocus = function(overlay) {
4356 var changed = false;
4357 if (activeOverlay != overlay) {
4358 if (activeOverlay) {
4359 activeOverlay.blur();
4361 activeOverlay = overlay;
4362 this.bringToTop(activeOverlay);
4363 Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4369 var overlays = this.cfg.getProperty("overlays");
4371 if (! this.overlays) {
4376 this.register(overlays);
4377 this.overlays.sort(this.compareZIndexDesc);
4382 * @method _onOverlayElementFocus
4383 * @description Event handler for the DOM event that is used to focus
4384 * the Overlay instance as specified by the "focusevent"
4385 * configuration property.
4387 * @param {Event} p_oEvent Object representing the DOM event
4388 * object passed back by the event utility (Event).
4390 _onOverlayElementFocus: function (p_oEvent) {
4392 var oTarget = Event.getTarget(p_oEvent),
4393 oClose = this.close;
4395 if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4403 * @method _onOverlayDestroy
4404 * @description "destroy" event handler for the Overlay.
4406 * @param {String} p_sType String representing the name of the event
4408 * @param {Array} p_aArgs Array of arguments sent when the event
4410 * @param {Overlay} p_oOverlay Object representing the overlay that
4413 _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4414 this.remove(p_oOverlay);
4418 * @method _onOverlayFocusHandler
4420 * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4423 * @param {String} p_sType String representing the name of the event
4425 * @param {Array} p_aArgs Array of arguments sent when the event
4427 * @param {Overlay} p_oOverlay Object representing the overlay that
4430 _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4431 this._manageFocus(p_oOverlay);
4435 * @method _onOverlayBlurHandler
4436 * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4439 * @param {String} p_sType String representing the name of the event
4441 * @param {Array} p_aArgs Array of arguments sent when the event
4443 * @param {Overlay} p_oOverlay Object representing the overlay that
4446 _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4447 this._manageBlur(p_oOverlay);
4451 * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4452 * monitor focus state.
4454 * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4455 * to the existing focusEvent, however if a focusEvent or focus method does not exist
4456 * on the instance, the _bindFocus method will add them, and the focus method will
4457 * update the OverlayManager's state directly.
4459 * @method _bindFocus
4460 * @param {Overlay} overlay The overlay for which focus needs to be managed
4463 _bindFocus : function(overlay) {
4466 if (!overlay.focusEvent) {
4467 overlay.focusEvent = overlay.createEvent("focus");
4468 overlay.focusEvent.signature = CustomEvent.LIST;
4469 overlay.focusEvent._managed = true;
4471 overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4474 if (!overlay.focus) {
4475 Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4476 overlay.focus = function () {
4477 if (mgr._manageFocus(this)) {
4479 if (this.cfg.getProperty("visible") && this.focusFirst) {
4482 this.focusEvent.fire();
4485 overlay.focus._managed = true;
4490 * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4491 * monitor blur state.
4493 * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4494 * to the existing blurEvent, however if a blurEvent or blur method does not exist
4495 * on the instance, the _bindBlur method will add them, and the blur method
4496 * update the OverlayManager's state directly.
4499 * @param {Overlay} overlay The overlay for which blur needs to be managed
4502 _bindBlur : function(overlay) {
4505 if (!overlay.blurEvent) {
4506 overlay.blurEvent = overlay.createEvent("blur");
4507 overlay.blurEvent.signature = CustomEvent.LIST;
4508 overlay.focusEvent._managed = true;
4510 overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4513 if (!overlay.blur) {
4514 overlay.blur = function () {
4515 if (mgr._manageBlur(this)) {
4516 this.blurEvent.fire();
4519 overlay.blur._managed = true;
4522 overlay.hideEvent.subscribe(overlay.blur);
4526 * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4527 * to be removed for the OverlayManager when destroyed.
4529 * @method _bindDestroy
4530 * @param {Overlay} overlay The overlay instance being managed
4533 _bindDestroy : function(overlay) {
4535 overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4539 * Ensures the zIndex configuration property on the managed overlay based instance
4540 * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4542 * @method _syncZIndex
4543 * @param {Overlay} overlay The overlay instance being managed
4546 _syncZIndex : function(overlay) {
4547 var zIndex = Dom.getStyle(overlay.element, "zIndex");
4548 if (!isNaN(zIndex)) {
4549 overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4551 overlay.cfg.setProperty("zIndex", 0);
4556 * Registers an Overlay or an array of Overlays with the manager. Upon
4557 * registration, the Overlay receives functions for focus and blur,
4558 * along with CustomEvents for each.
4561 * @param {Overlay} overlay An Overlay to register with the manager.
4562 * @param {Overlay[]} overlay An array of Overlays to register with
4564 * @return {boolean} true if any Overlays are registered.
4566 register: function (overlay) {
4568 var registered = false,
4572 if (overlay instanceof Overlay) {
4574 overlay.cfg.addProperty("manager", { value: this } );
4576 this._bindFocus(overlay);
4577 this._bindBlur(overlay);
4578 this._bindDestroy(overlay);
4579 this._syncZIndex(overlay);
4581 this.overlays.push(overlay);
4582 this.bringToTop(overlay);
4586 } else if (overlay instanceof Array) {
4588 for (i = 0, n = overlay.length; i < n; i++) {
4589 registered = this.register(overlay[i]) || registered;
4598 * Places the specified Overlay instance on top of all other
4599 * Overlay instances.
4600 * @method bringToTop
4601 * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4603 * @param {String} p_oOverlay String representing the id of an
4606 bringToTop: function (p_oOverlay) {
4608 var oOverlay = this.find(p_oOverlay),
4615 aOverlays = this.overlays;
4616 aOverlays.sort(this.compareZIndexDesc);
4618 oTopOverlay = aOverlays[0];
4621 nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4623 if (!isNaN(nTopZIndex)) {
4625 var bRequiresBump = false;
4627 if (oTopOverlay !== oOverlay) {
4628 bRequiresBump = true;
4629 } else if (aOverlays.length > 1) {
4630 var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4631 // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4632 if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4633 bRequiresBump = true;
4637 if (bRequiresBump) {
4638 oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4641 aOverlays.sort(this.compareZIndexDesc);
4647 * Attempts to locate an Overlay by instance or ID.
4649 * @param {Overlay} overlay An Overlay to locate within the manager
4650 * @param {String} overlay An Overlay id to locate within the manager
4651 * @return {Overlay} The requested Overlay, if found, or null if it
4652 * cannot be located.
4654 find: function (overlay) {
4656 var isInstance = overlay instanceof Overlay,
4657 overlays = this.overlays,
4658 n = overlays.length,
4663 if (isInstance || typeof overlay == "string") {
4664 for (i = n-1; i >= 0; i--) {
4666 if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4677 * Used for sorting the manager's Overlays by z-index.
4678 * @method compareZIndexDesc
4680 * @return {Number} 0, 1, or -1, depending on where the Overlay should
4681 * fall in the stacking order.
4683 compareZIndexDesc: function (o1, o2) {
4685 var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4686 zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4688 if (zIndex1 === null && zIndex2 === null) {
4690 } else if (zIndex1 === null){
4692 } else if (zIndex2 === null) {
4694 } else if (zIndex1 > zIndex2) {
4696 } else if (zIndex1 < zIndex2) {
4704 * Shows all Overlays in the manager.
4707 showAll: function () {
4708 var overlays = this.overlays,
4709 n = overlays.length,
4712 for (i = n - 1; i >= 0; i--) {
4718 * Hides all Overlays in the manager.
4721 hideAll: function () {
4722 var overlays = this.overlays,
4723 n = overlays.length,
4726 for (i = n - 1; i >= 0; i--) {
4732 * Returns a string representation of the object.
4734 * @return {String} The string representation of the OverlayManager
4736 toString: function () {
4737 return "OverlayManager";
4744 * Tooltip is an implementation of Overlay that behaves like an OS tooltip,
4745 * displaying when the user mouses over a particular element, and
4746 * disappearing on mouse out.
4747 * @namespace YAHOO.widget
4749 * @extends YAHOO.widget.Overlay
4751 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4752 * @param {HTMLElement} el The element representing the Tooltip
4753 * @param {Object} userConfig The configuration object literal containing
4754 * the configuration that should be set for this Overlay. See configuration
4755 * documentation for more details.
4757 YAHOO.widget.Tooltip = function (el, userConfig) {
4758 YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4761 var Lang = YAHOO.lang,
4762 Event = YAHOO.util.Event,
4763 CustomEvent = YAHOO.util.CustomEvent,
4764 Dom = YAHOO.util.Dom,
4765 Tooltip = YAHOO.widget.Tooltip,
4767 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
4772 * Constant representing the Tooltip's configuration properties
4773 * @property DEFAULT_CONFIG
4780 "PREVENT_OVERLAP": {
4781 key: "preventoverlap",
4783 validator: Lang.isBoolean,
4784 supercedes: ["x", "y", "xy"]
4790 validator: Lang.isNumber
4793 "AUTO_DISMISS_DELAY": {
4794 key: "autodismissdelay",
4796 validator: Lang.isNumber
4802 validator: Lang.isNumber
4828 * Constant representing the name of the Tooltip's events
4829 * @property EVENT_TYPES
4835 "CONTEXT_MOUSE_OVER": "contextMouseOver",
4836 "CONTEXT_MOUSE_OUT": "contextMouseOut",
4837 "CONTEXT_TRIGGER": "contextTrigger"
4841 * Constant representing the Tooltip CSS class
4842 * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4847 Tooltip.CSS_TOOLTIP = "yui-tt";
4849 function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
4851 var oConfig = this.cfg,
4852 sCurrentWidth = oConfig.getProperty("width");
4854 if (sCurrentWidth == sForcedWidth) {
4855 oConfig.setProperty("width", sOriginalWidth);
4860 changeContent event handler that sets a Tooltip instance's "width"
4861 configuration property to the value of its root HTML
4862 elements's offsetWidth if a specific width has not been set.
4865 function setWidthToOffsetWidth(p_sType, p_aArgs) {
4867 if ("_originalWidth" in this) {
4868 restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
4871 var oBody = document.body,
4873 sOriginalWidth = oConfig.getProperty("width"),
4877 if ((!sOriginalWidth || sOriginalWidth == "auto") &&
4878 (oConfig.getProperty("container") != oBody ||
4879 oConfig.getProperty("x") >= Dom.getViewportWidth() ||
4880 oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4882 oClone = this.element.cloneNode(true);
4883 oClone.style.visibility = "hidden";
4884 oClone.style.top = "0px";
4885 oClone.style.left = "0px";
4887 oBody.appendChild(oClone);
4889 sNewWidth = (oClone.offsetWidth + "px");
4891 oBody.removeChild(oClone);
4894 oConfig.setProperty("width", sNewWidth);
4895 oConfig.refireEvent("xy");
4897 this._originalWidth = sOriginalWidth || "";
4898 this._forcedWidth = sNewWidth;
4902 // "onDOMReady" that renders the ToolTip
4904 function onDOMReady(p_sType, p_aArgs, p_oObject) {
4905 this.render(p_oObject);
4908 // "init" event handler that automatically renders the Tooltip
4911 Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4914 YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
4917 * The Tooltip initialization method. This method is automatically
4918 * called by the constructor. A Tooltip is automatically rendered by
4919 * the init method, and it also is set to be invisible by default,
4920 * and constrained to viewport by default as well.
4922 * @param {String} el The element ID representing the Tooltip <em>OR</em>
4923 * @param {HTMLElement} el The element representing the Tooltip
4924 * @param {Object} userConfig The configuration object literal
4925 * containing the configuration that should be set for this Tooltip.
4926 * See configuration documentation for more details.
4928 init: function (el, userConfig) {
4931 Tooltip.superclass.init.call(this, el);
4933 this.beforeInitEvent.fire(Tooltip);
4935 Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
4938 this.cfg.applyConfig(userConfig, true);
4941 this.cfg.queueProperty("visible", false);
4942 this.cfg.queueProperty("constraintoviewport", true);
4946 this.subscribe("changeContent", setWidthToOffsetWidth);
4947 this.subscribe("init", onInit);
4948 this.subscribe("render", this.onRender);
4950 this.initEvent.fire(Tooltip);
4954 * Initializes the custom events for Tooltip
4955 * @method initEvents
4957 initEvents: function () {
4959 Tooltip.superclass.initEvents.call(this);
4960 var SIGNATURE = CustomEvent.LIST;
4963 * CustomEvent fired when user mouses over a context element. Returning false from
4964 * a subscriber to this event will prevent the tooltip from being displayed for
4965 * the current context element.
4967 * @event contextMouseOverEvent
4968 * @param {HTMLElement} context The context element which the user just moused over
4969 * @param {DOMEvent} e The DOM event object, associated with the mouse over
4971 this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
4972 this.contextMouseOverEvent.signature = SIGNATURE;
4975 * CustomEvent fired when the user mouses out of a context element.
4977 * @event contextMouseOutEvent
4978 * @param {HTMLElement} context The context element which the user just moused out of
4979 * @param {DOMEvent} e The DOM event object, associated with the mouse out
4981 this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
4982 this.contextMouseOutEvent.signature = SIGNATURE;
4985 * CustomEvent fired just before the tooltip is displayed for the current context.
4987 * You can subscribe to this event if you need to set up the text for the
4988 * tooltip based on the context element for which it is about to be displayed.
4990 * <p>This event differs from the beforeShow event in following respects:</p>
4993 * When moving from one context element to another, if the tooltip is not
4994 * hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
4995 * be fired when the tooltip is displayed for the new context since it is already visible.
4996 * However the contextTrigger event is always fired before displaying the tooltip for
5000 * The trigger event provides access to the context element, allowing you to
5001 * set the text of the tooltip based on context element for which the tooltip is
5006 * It is not possible to prevent the tooltip from being displayed
5007 * using this event. You can use the contextMouseOverEvent if you need to prevent
5008 * the tooltip from being displayed.
5010 * @event contextTriggerEvent
5011 * @param {HTMLElement} context The context element for which the tooltip is triggered
5013 this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
5014 this.contextTriggerEvent.signature = SIGNATURE;
5018 * Initializes the class's configurable properties which can be
5019 * changed using the Overlay's Config object (cfg).
5020 * @method initDefaultConfig
5022 initDefaultConfig: function () {
5024 Tooltip.superclass.initDefaultConfig.call(this);
5027 * Specifies whether the Tooltip should be kept from overlapping
5028 * its context element.
5029 * @config preventoverlap
5033 this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
5034 value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
5035 validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
5036 supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
5040 * The number of milliseconds to wait before showing a Tooltip
5046 this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
5047 handler: this.configShowDelay,
5049 validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5053 * The number of milliseconds to wait before automatically
5054 * dismissing a Tooltip after the mouse has been resting on the
5056 * @config autodismissdelay
5060 this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
5061 handler: this.configAutoDismissDelay,
5062 value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
5063 validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
5067 * The number of milliseconds to wait before hiding a Tooltip
5073 this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
5074 handler: this.configHideDelay,
5075 value: DEFAULT_CONFIG.HIDE_DELAY.value,
5076 validator: DEFAULT_CONFIG.HIDE_DELAY.validator
5080 * Specifies the Tooltip's text.
5085 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
5086 handler: this.configText,
5087 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
5091 * Specifies the container element that the Tooltip's markup
5092 * should be rendered into.
5094 * @type HTMLElement/String
5095 * @default document.body
5097 this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
5098 handler: this.configContainer,
5099 value: document.body
5103 * Specifies whether or not the tooltip is disabled. Disabled tooltips
5104 * will not be displayed. If the tooltip is driven by the title attribute
5105 * of the context element, the title attribute will still be removed for
5106 * disabled tooltips, to prevent default tooltip behavior.
5112 this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
5113 handler: this.configContainer,
5114 value: DEFAULT_CONFIG.DISABLED.value,
5115 supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5119 * Specifies the XY offset from the mouse position, where the tooltip should be displayed, specified
5120 * as a 2 element array (e.g. [10, 20]);
5126 this.cfg.addProperty(DEFAULT_CONFIG.XY_OFFSET.key, {
5127 value: DEFAULT_CONFIG.XY_OFFSET.value.concat(),
5128 supressEvent: DEFAULT_CONFIG.XY_OFFSET.suppressEvent
5132 * Specifies the element or elements that the Tooltip should be
5133 * anchored to on mouseover.
5135 * @type HTMLElement[]/String[]
5140 * String representing the width of the Tooltip. <em>Please note:
5141 * </em> As of version 2.3 if either no value or a value of "auto"
5142 * is specified, and the Toolip's "container" configuration property
5143 * is set to something other than <code>document.body</code> or
5144 * its "context" element resides outside the immediately visible
5145 * portion of the document, the width of the Tooltip will be
5146 * calculated based on the offsetWidth of its root HTML and set just
5147 * before it is made visible. The original value will be
5148 * restored when the Tooltip is hidden. This ensures the Tooltip is
5149 * rendered at a usable width. For more information see
5150 * YUILibrary bug #1685496 and YUILibrary
5159 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5162 * The default event handler fired when the "text" property is changed.
5163 * @method configText
5164 * @param {String} type The CustomEvent type (usually the property name)
5165 * @param {Object[]} args The CustomEvent arguments. For configuration
5166 * handlers, args[0] will equal the newly applied value for the property.
5167 * @param {Object} obj The scope object. For configuration handlers,
5168 * this will usually equal the owner.
5170 configText: function (type, args, obj) {
5178 * The default event handler fired when the "container" property
5180 * @method configContainer
5181 * @param {String} type The CustomEvent type (usually the property name)
5182 * @param {Object[]} args The CustomEvent arguments. For
5183 * configuration handlers, args[0] will equal the newly applied value
5185 * @param {Object} obj The scope object. For configuration handlers,
5186 * this will usually equal the owner.
5188 configContainer: function (type, args, obj) {
5189 var container = args[0];
5191 if (typeof container == 'string') {
5192 this.cfg.setProperty("container", document.getElementById(container), true);
5197 * @method _removeEventListeners
5198 * @description Removes all of the DOM event handlers from the HTML
5199 * element(s) that trigger the display of the tooltip.
5202 _removeEventListeners: function () {
5204 var aElements = this._context,
5210 nElements = aElements.length;
5211 if (nElements > 0) {
5214 oElement = aElements[i];
5215 Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
5216 Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
5217 Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
5225 * The default event handler fired when the "context" property
5227 * @method configContext
5228 * @param {String} type The CustomEvent type (usually the property name)
5229 * @param {Object[]} args The CustomEvent arguments. For configuration
5230 * handlers, args[0] will equal the newly applied value for the property.
5231 * @param {Object} obj The scope object. For configuration handlers,
5232 * this will usually equal the owner.
5234 configContext: function (type, args, obj) {
5236 var context = args[0],
5244 // Normalize parameter into an array
5245 if (! (context instanceof Array)) {
5246 if (typeof context == "string") {
5247 this.cfg.setProperty("context", [document.getElementById(context)], true);
5248 } else { // Assuming this is an element
5249 this.cfg.setProperty("context", [context], true);
5251 context = this.cfg.getProperty("context");
5254 // Remove any existing mouseover/mouseout listeners
5255 this._removeEventListeners();
5257 // Add mouseover/mouseout listeners to context elements
5258 this._context = context;
5260 aElements = this._context;
5263 nElements = aElements.length;
5264 if (nElements > 0) {
5267 oElement = aElements[i];
5268 Event.on(oElement, "mouseover", this.onContextMouseOver, this);
5269 Event.on(oElement, "mousemove", this.onContextMouseMove, this);
5270 Event.on(oElement, "mouseout", this.onContextMouseOut, this);
5278 // END BUILT-IN PROPERTY EVENT HANDLERS //
5280 // BEGIN BUILT-IN DOM EVENT HANDLERS //
5283 * The default event handler fired when the user moves the mouse while
5284 * over the context element.
5285 * @method onContextMouseMove
5286 * @param {DOMEvent} e The current DOM event
5287 * @param {Object} obj The object argument
5289 onContextMouseMove: function (e, obj) {
5290 obj.pageX = Event.getPageX(e);
5291 obj.pageY = Event.getPageY(e);
5295 * The default event handler fired when the user mouses over the
5297 * @method onContextMouseOver
5298 * @param {DOMEvent} e The current DOM event
5299 * @param {Object} obj The object argument
5301 onContextMouseOver: function (e, obj) {
5304 if (context.title) {
5305 obj._tempTitle = context.title;
5309 // Fire first, to honor disabled set in the listner
5310 if (obj.fireEvent("contextMouseOver", context, e) !== false
5311 && !obj.cfg.getProperty("disabled")) {
5313 // Stop the tooltip from being hidden (set on last mouseout)
5314 if (obj.hideProcId) {
5315 clearTimeout(obj.hideProcId);
5316 obj.hideProcId = null;
5319 Event.on(context, "mousemove", obj.onContextMouseMove, obj);
5322 * The unique process ID associated with the thread responsible
5323 * for showing the Tooltip.
5326 obj.showProcId = obj.doShow(e, context);
5331 * The default event handler fired when the user mouses out of
5332 * the context element.
5333 * @method onContextMouseOut
5334 * @param {DOMEvent} e The current DOM event
5335 * @param {Object} obj The object argument
5337 onContextMouseOut: function (e, obj) {
5340 if (obj._tempTitle) {
5341 el.title = obj._tempTitle;
5342 obj._tempTitle = null;
5345 if (obj.showProcId) {
5346 clearTimeout(obj.showProcId);
5347 obj.showProcId = null;
5350 if (obj.hideProcId) {
5351 clearTimeout(obj.hideProcId);
5352 obj.hideProcId = null;
5355 obj.fireEvent("contextMouseOut", el, e);
5357 obj.hideProcId = setTimeout(function () {
5359 }, obj.cfg.getProperty("hidedelay"));
5362 // END BUILT-IN DOM EVENT HANDLERS //
5365 * Processes the showing of the Tooltip by setting the timeout delay
5366 * and offset of the Tooltip.
5368 * @param {DOMEvent} e The current DOM event
5369 * @param {HTMLElement} context The current context element
5370 * @return {Number} The process ID of the timeout function associated
5373 doShow: function (e, context) {
5375 var offset = this.cfg.getProperty("xyoffset"),
5376 xOffset = offset[0],
5377 yOffset = offset[1],
5380 if (UA.opera && context.tagName &&
5381 context.tagName.toUpperCase() == "A") {
5385 return setTimeout(function () {
5387 var txt = me.cfg.getProperty("text");
5389 // title does not over-ride text
5390 if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
5391 me.setBody(me._tempTitle);
5393 me.cfg.refireEvent("text");
5396 me.moveTo(me.pageX + xOffset, me.pageY + yOffset);
5398 if (me.cfg.getProperty("preventoverlap")) {
5399 me.preventOverlap(me.pageX, me.pageY);
5402 Event.removeListener(context, "mousemove", me.onContextMouseMove);
5404 me.contextTriggerEvent.fire(context);
5408 me.hideProcId = me.doHide();
5410 }, this.cfg.getProperty("showdelay"));
5414 * Sets the timeout for the auto-dismiss delay, which by default is 5
5415 * seconds, meaning that a tooltip will automatically dismiss itself
5416 * after 5 seconds of being displayed.
5419 doHide: function () {
5424 return setTimeout(function () {
5428 }, this.cfg.getProperty("autodismissdelay"));
5433 * Fired when the Tooltip is moved, this event handler is used to
5434 * prevent the Tooltip from overlapping with its context element.
5435 * @method preventOverlay
5436 * @param {Number} pageX The x coordinate position of the mouse pointer
5437 * @param {Number} pageY The y coordinate position of the mouse pointer
5439 preventOverlap: function (pageX, pageY) {
5441 var height = this.element.offsetHeight,
5442 mousePoint = new YAHOO.util.Point(pageX, pageY),
5443 elementRegion = Dom.getRegion(this.element);
5445 elementRegion.top -= 5;
5446 elementRegion.left -= 5;
5447 elementRegion.right += 5;
5448 elementRegion.bottom += 5;
5451 if (elementRegion.contains(mousePoint)) {
5452 this.cfg.setProperty("y", (pageY - height - 5));
5459 * @description "render" event handler for the Tooltip.
5460 * @param {String} p_sType String representing the name of the event
5462 * @param {Array} p_aArgs Array of arguments sent when the event
5465 onRender: function (p_sType, p_aArgs) {
5467 function sizeShadow() {
5469 var oElement = this.element,
5470 oShadow = this.underlay;
5473 oShadow.style.width = (oElement.offsetWidth + 6) + "px";
5474 oShadow.style.height = (oElement.offsetHeight + 1) + "px";
5479 function addShadowVisibleClass() {
5480 Dom.addClass(this.underlay, "yui-tt-shadow-visible");
5483 this.forceUnderlayRedraw();
5487 function removeShadowVisibleClass() {
5488 Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
5491 function createShadow() {
5493 var oShadow = this.underlay,
5501 oElement = this.element;
5502 Module = YAHOO.widget.Module;
5506 if (!m_oShadowTemplate) {
5507 m_oShadowTemplate = document.createElement("div");
5508 m_oShadowTemplate.className = "yui-tt-shadow";
5511 oShadow = m_oShadowTemplate.cloneNode(false);
5513 oElement.appendChild(oShadow);
5515 this.underlay = oShadow;
5517 // Backward compatibility, even though it's probably
5518 // intended to be "private", it isn't marked as such in the api docs
5519 this._shadow = this.underlay;
5521 addShadowVisibleClass.call(this);
5523 this.subscribe("beforeShow", addShadowVisibleClass);
5524 this.subscribe("hide", removeShadowVisibleClass);
5527 window.setTimeout(function () {
5528 sizeShadow.call(me);
5531 this.cfg.subscribeToConfigEvent("width", sizeShadow);
5532 this.cfg.subscribeToConfigEvent("height", sizeShadow);
5533 this.subscribe("changeContent", sizeShadow);
5535 Module.textResizeEvent.subscribe(sizeShadow, this, true);
5536 this.subscribe("destroy", function () {
5537 Module.textResizeEvent.unsubscribe(sizeShadow, this);
5543 function onBeforeShow() {
5544 createShadow.call(this);
5545 this.unsubscribe("beforeShow", onBeforeShow);
5548 if (this.cfg.getProperty("visible")) {
5549 createShadow.call(this);
5551 this.subscribe("beforeShow", onBeforeShow);
5557 * Forces the underlay element to be repainted, through the application/removal
5558 * of a yui-force-redraw class to the underlay element.
5560 * @method forceUnderlayRedraw
5562 forceUnderlayRedraw : function() {
5564 Dom.addClass(tt.underlay, "yui-force-redraw");
5565 setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
5569 * Removes the Tooltip element from the DOM and sets all child
5573 destroy: function () {
5575 // Remove any existing mouseover/mouseout listeners
5576 this._removeEventListeners();
5578 Tooltip.superclass.destroy.call(this);
5583 * Returns a string representation of the object.
5585 * @return {String} The string representation of the Tooltip
5587 toString: function () {
5588 return "Tooltip " + this.id;
5597 * Panel is an implementation of Overlay that behaves like an OS window,
5598 * with a draggable header and an optional close icon at the top right.
5599 * @namespace YAHOO.widget
5601 * @extends YAHOO.widget.Overlay
5603 * @param {String} el The element ID representing the Panel <em>OR</em>
5604 * @param {HTMLElement} el The element representing the Panel
5605 * @param {Object} userConfig The configuration object literal containing
5606 * the configuration that should be set for this Panel. See configuration
5607 * documentation for more details.
5609 YAHOO.widget.Panel = function (el, userConfig) {
5610 YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5613 var _currentModal = null;
5615 var Lang = YAHOO.lang,
5619 CustomEvent = Util.CustomEvent,
5620 KeyListener = YAHOO.util.KeyListener,
5621 Config = Util.Config,
5622 Overlay = YAHOO.widget.Overlay,
5623 Panel = YAHOO.widget.Panel,
5626 bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
5629 m_oUnderlayTemplate,
5630 m_oCloseIconTemplate,
5633 * Constant representing the name of the Panel's events
5634 * @property EVENT_TYPES
5640 "SHOW_MASK": "showMask",
5641 "HIDE_MASK": "hideMask",
5646 * Constant representing the Panel's configuration properties
5647 * @property DEFAULT_CONFIG
5657 validator: Lang.isBoolean,
5658 supercedes: ["visible"]
5663 value: (Util.DD ? true : false),
5664 validator: Lang.isBoolean,
5665 supercedes: ["visible"]
5671 validator: Lang.isBoolean,
5672 supercedes: ["draggable"]
5678 supercedes: ["visible"]
5684 validator: Lang.isBoolean,
5685 supercedes: ["visible", "zindex"]
5689 key: "keylisteners",
5690 suppressEvent: true,
5691 supercedes: ["visible"]
5696 supercedes: ["close"],
5697 validator: Lang.isObject,
5705 * Constant representing the default CSS class used for a Panel
5706 * @property YAHOO.widget.Panel.CSS_PANEL
5711 Panel.CSS_PANEL = "yui-panel";
5714 * Constant representing the default CSS class used for a Panel's
5715 * wrapping container
5716 * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5721 Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5724 * Constant representing the default set of focusable elements
5725 * on the pagewhich Modal Panels will prevent access to, when
5726 * the modal mask is displayed
5728 * @property YAHOO.widget.Panel.FOCUSABLE
5741 // Private CustomEvent listeners
5744 "beforeRender" event handler that creates an empty header for a Panel
5745 instance if its "draggable" configuration property is set to "true"
5746 and no header has been created.
5749 function createHeader(p_sType, p_aArgs) {
5750 if (!this.header && this.cfg.getProperty("draggable")) {
5751 this.setHeader(" ");
5756 "hide" event handler that sets a Panel instance's "width"
5757 configuration property back to its original value before
5758 "setWidthToOffsetWidth" was called.
5761 function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5763 var sOriginalWidth = p_oObject[0],
5764 sNewWidth = p_oObject[1],
5766 sCurrentWidth = oConfig.getProperty("width");
5768 if (sCurrentWidth == sNewWidth) {
5769 oConfig.setProperty("width", sOriginalWidth);
5772 this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5776 "beforeShow" event handler that sets a Panel instance's "width"
5777 configuration property to the value of its root HTML
5778 elements's offsetWidth
5781 function setWidthToOffsetWidth(p_sType, p_aArgs) {
5790 sOriginalWidth = oConfig.getProperty("width");
5792 if (!sOriginalWidth || sOriginalWidth == "auto") {
5794 sNewWidth = (this.element.offsetWidth + "px");
5796 oConfig.setProperty("width", sNewWidth);
5798 this.subscribe("hide", restoreOriginalWidth,
5799 [(sOriginalWidth || ""), sNewWidth]);
5805 YAHOO.extend(Panel, Overlay, {
5808 * The Overlay initialization method, which is executed for Overlay and
5809 * all of its subclasses. This method is automatically called by the
5810 * constructor, and sets up all DOM references for pre-existing markup,
5811 * and creates required markup if it is not already present.
5813 * @param {String} el The element ID representing the Overlay <em>OR</em>
5814 * @param {HTMLElement} el The element representing the Overlay
5815 * @param {Object} userConfig The configuration object literal
5816 * containing the configuration that should be set for this Overlay.
5817 * See configuration documentation for more details.
5819 init: function (el, userConfig) {
5821 Note that we don't pass the user config in here yet because
5822 we only want it executed once, at the lowest subclass level
5825 Panel.superclass.init.call(this, el/*, userConfig*/);
5827 this.beforeInitEvent.fire(Panel);
5829 Dom.addClass(this.element, Panel.CSS_PANEL);
5831 this.buildWrapper();
5834 this.cfg.applyConfig(userConfig, true);
5837 this.subscribe("showMask", this._addFocusHandlers);
5838 this.subscribe("hideMask", this._removeFocusHandlers);
5839 this.subscribe("beforeRender", createHeader);
5841 this.subscribe("render", function() {
5842 this.setFirstLastFocusable();
5843 this.subscribe("changeContent", this.setFirstLastFocusable);
5846 this.subscribe("show", this.focusFirst);
5848 this.initEvent.fire(Panel);
5852 * @method _onElementFocus
5855 * "focus" event handler for a focuable element. Used to automatically
5856 * blur the element when it receives focus to ensure that a Panel
5857 * instance's modality is not compromised.
5859 * @param {Event} e The DOM event object
5861 _onElementFocus : function(e){
5863 if(_currentModal === this) {
5865 var target = Event.getTarget(e),
5866 doc = document.documentElement,
5867 insideDoc = (target !== doc && target !== window);
5869 // mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on
5870 // the documentElement, when the document scrollbars are clicked on
5871 if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
5873 if (this.firstElement) {
5874 this.firstElement.focus();
5876 if (this._modalFocus) {
5877 this._modalFocus.focus();
5879 this.innerElement.focus();
5883 // Just in case we fail to focus
5885 if (insideDoc && target !== document.body) {
5895 * @method _addFocusHandlers
5898 * "showMask" event handler that adds a "focus" event handler to all
5899 * focusable elements in the document to enforce a Panel instance's
5900 * modality from being compromised.
5902 * @param p_sType {String} Custom event type
5903 * @param p_aArgs {Array} Custom event arguments
5905 _addFocusHandlers: function(p_sType, p_aArgs) {
5906 if (!this.firstElement) {
5907 if (UA.webkit || UA.opera) {
5908 if (!this._modalFocus) {
5909 this._createHiddenFocusElement();
5912 this.innerElement.tabIndex = 0;
5915 this.setTabLoop(this.firstElement, this.lastElement);
5916 Event.onFocus(document.documentElement, this._onElementFocus, this, true);
5917 _currentModal = this;
5921 * Creates a hidden focusable element, used to focus on,
5922 * to enforce modality for browsers in which focus cannot
5923 * be applied to the container box.
5925 * @method _createHiddenFocusElement
5928 _createHiddenFocusElement : function() {
5929 var e = document.createElement("button");
5930 e.style.height = "1px";
5931 e.style.width = "1px";
5932 e.style.position = "absolute";
5933 e.style.left = "-10000em";
5934 e.style.opacity = 0;
5936 this.innerElement.appendChild(e);
5937 this._modalFocus = e;
5941 * @method _removeFocusHandlers
5944 * "hideMask" event handler that removes all "focus" event handlers added
5945 * by the "addFocusEventHandlers" method.
5947 * @param p_sType {String} Event type
5948 * @param p_aArgs {Array} Event Arguments
5950 _removeFocusHandlers: function(p_sType, p_aArgs) {
5951 Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
5953 if (_currentModal == this) {
5954 _currentModal = null;
5959 * Sets focus to the first element in the Panel.
5961 * @method focusFirst
5963 focusFirst: function (type, args, obj) {
5964 var el = this.firstElement;
5966 if (args && args[1]) {
5967 Event.stopEvent(args[1]);
5980 * Sets focus to the last element in the Panel.
5984 focusLast: function (type, args, obj) {
5985 var el = this.lastElement;
5987 if (args && args[1]) {
5988 Event.stopEvent(args[1]);
6001 * Sets up a tab, shift-tab loop between the first and last elements
6002 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
6003 * instance properties, which are reset everytime this method is invoked.
6005 * @method setTabLoop
6006 * @param {HTMLElement} firstElement
6007 * @param {HTMLElement} lastElement
6010 setTabLoop : function(firstElement, lastElement) {
6012 var backTab = this.preventBackTab, tab = this.preventTabOut,
6013 showEvent = this.showEvent, hideEvent = this.hideEvent;
6017 showEvent.unsubscribe(backTab.enable, backTab);
6018 hideEvent.unsubscribe(backTab.disable, backTab);
6019 backTab = this.preventBackTab = null;
6024 showEvent.unsubscribe(tab.enable, tab);
6025 hideEvent.unsubscribe(tab.disable,tab);
6026 tab = this.preventTabOut = null;
6030 this.preventBackTab = new KeyListener(firstElement,
6031 {shift:true, keys:9},
6032 {fn:this.focusLast, scope:this, correctScope:true}
6034 backTab = this.preventBackTab;
6036 showEvent.subscribe(backTab.enable, backTab, true);
6037 hideEvent.subscribe(backTab.disable,backTab, true);
6041 this.preventTabOut = new KeyListener(lastElement,
6042 {shift:false, keys:9},
6043 {fn:this.focusFirst, scope:this, correctScope:true}
6045 tab = this.preventTabOut;
6047 showEvent.subscribe(tab.enable, tab, true);
6048 hideEvent.subscribe(tab.disable,tab, true);
6053 * Returns an array of the currently focusable items which reside within
6054 * Panel. The set of focusable elements the method looks for are defined
6055 * in the Panel.FOCUSABLE static property
6057 * @method getFocusableElements
6058 * @param {HTMLElement} root element to start from.
6060 getFocusableElements : function(root) {
6062 root = root || this.innerElement;
6065 for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
6066 focusable[Panel.FOCUSABLE[i]] = true;
6069 function isFocusable(el) {
6070 if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
6076 // Not looking by Tag, since we want elements in DOM order
6077 return Dom.getElementsBy(isFocusable, null, root);
6081 * Sets the firstElement and lastElement instance properties
6082 * to the first and last focusable elements in the Panel.
6084 * @method setFirstLastFocusable
6086 setFirstLastFocusable : function() {
6088 this.firstElement = null;
6089 this.lastElement = null;
6091 var elements = this.getFocusableElements();
6092 this.focusableElements = elements;
6094 if (elements.length > 0) {
6095 this.firstElement = elements[0];
6096 this.lastElement = elements[elements.length - 1];
6099 if (this.cfg.getProperty("modal")) {
6100 this.setTabLoop(this.firstElement, this.lastElement);
6105 * Initializes the custom events for Module which are fired
6106 * automatically at appropriate times by the Module class.
6108 initEvents: function () {
6109 Panel.superclass.initEvents.call(this);
6111 var SIGNATURE = CustomEvent.LIST;
6114 * CustomEvent fired after the modality mask is shown
6115 * @event showMaskEvent
6117 this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
6118 this.showMaskEvent.signature = SIGNATURE;
6121 * CustomEvent fired after the modality mask is hidden
6122 * @event hideMaskEvent
6124 this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
6125 this.hideMaskEvent.signature = SIGNATURE;
6128 * CustomEvent when the Panel is dragged
6131 this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
6132 this.dragEvent.signature = SIGNATURE;
6136 * Initializes the class's configurable properties which can be changed
6137 * using the Panel's Config object (cfg).
6138 * @method initDefaultConfig
6140 initDefaultConfig: function () {
6141 Panel.superclass.initDefaultConfig.call(this);
6143 // Add panel config properties //
6146 * True if the Panel should display a "close" button
6151 this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
6152 handler: this.configClose,
6153 value: DEFAULT_CONFIG.CLOSE.value,
6154 validator: DEFAULT_CONFIG.CLOSE.validator,
6155 supercedes: DEFAULT_CONFIG.CLOSE.supercedes
6159 * Boolean specifying if the Panel should be draggable. The default
6160 * value is "true" if the Drag and Drop utility is included,
6161 * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
6162 * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
6163 * (Quirks Mode) where Panels that either don't have a value set for
6164 * their "width" configuration property, or their "width"
6165 * configuration property is set to "auto" will only be draggable by
6166 * placing the mouse on the text of the Panel's header element.
6167 * To fix this bug, draggable Panels missing a value for their
6168 * "width" configuration property, or whose "width" configuration
6169 * property is set to "auto" will have it set to the value of
6170 * their root HTML element's offsetWidth before they are made
6171 * visible. The calculated width is then removed when the Panel is
6172 * hidden. <em>This fix is only applied to draggable Panels in IE 6
6173 * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
6174 * more information on this issue see:
6175 * YUILibrary bugs #1726972 and #1589210.
6180 this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
6181 handler: this.configDraggable,
6182 value: (Util.DD) ? true : false,
6183 validator: DEFAULT_CONFIG.DRAGGABLE.validator,
6184 supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
6188 * Boolean specifying if the draggable Panel should be drag only, not interacting with drop
6189 * targets on the page.
6191 * When set to true, draggable Panels will not check to see if they are over drop targets,
6192 * or fire the DragDrop events required to support drop target interaction (onDragEnter,
6193 * onDragOver, onDragOut, onDragDrop etc.).
6194 * If the Panel is not designed to be dropped on any target elements on the page, then this
6195 * flag can be set to true to improve performance.
6198 * When set to false, all drop target related events will be fired.
6201 * The property is set to false by default to maintain backwards compatibility but should be
6202 * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
6208 this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, {
6209 value: DEFAULT_CONFIG.DRAG_ONLY.value,
6210 validator: DEFAULT_CONFIG.DRAG_ONLY.validator,
6211 supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes
6215 * Sets the type of underlay to display for the Panel. Valid values
6216 * are "shadow," "matte," and "none". <strong>PLEASE NOTE:</strong>
6217 * The creation of the underlay element is deferred until the Panel
6218 * is initially made visible. For Gecko-based browsers on Mac
6219 * OS X the underlay elment is always created as it is used as a
6220 * shim to prevent Aqua scrollbars below a Panel instance from poking
6221 * through it (See YUILibrary bug #1723530).
6226 this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
6227 handler: this.configUnderlay,
6228 value: DEFAULT_CONFIG.UNDERLAY.value,
6229 supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
6233 * True if the Panel should be displayed in a modal fashion,
6234 * automatically creating a transparent mask over the document that
6235 * will not be removed until the Panel is dismissed.
6240 this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
6241 handler: this.configModal,
6242 value: DEFAULT_CONFIG.MODAL.value,
6243 validator: DEFAULT_CONFIG.MODAL.validator,
6244 supercedes: DEFAULT_CONFIG.MODAL.supercedes
6248 * A KeyListener (or array of KeyListeners) that will be enabled
6249 * when the Panel is shown, and disabled when the Panel is hidden.
6250 * @config keylisteners
6251 * @type YAHOO.util.KeyListener[]
6254 this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
6255 handler: this.configKeyListeners,
6256 suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
6257 supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
6261 * UI Strings used by the Panel
6265 * @default An object literal with the properties shown below:
6267 * <dt>close</dt><dd><em>String</em> : The string to use for the close icon. Defaults to "Close".</dd>
6270 this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, {
6271 value:DEFAULT_CONFIG.STRINGS.value,
6272 handler:this.configStrings,
6273 validator:DEFAULT_CONFIG.STRINGS.validator,
6274 supercedes:DEFAULT_CONFIG.STRINGS.supercedes
6278 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6281 * The default event handler fired when the "close" property is changed.
6282 * The method controls the appending or hiding of the close icon at the
6283 * top right of the Panel.
6284 * @method configClose
6285 * @param {String} type The CustomEvent type (usually the property name)
6286 * @param {Object[]} args The CustomEvent arguments. For configuration
6287 * handlers, args[0] will equal the newly applied value for the property.
6288 * @param {Object} obj The scope object. For configuration handlers,
6289 * this will usually equal the owner.
6291 configClose: function (type, args, obj) {
6294 oClose = this.close,
6295 strings = this.cfg.getProperty("strings");
6300 if (!m_oCloseIconTemplate) {
6301 m_oCloseIconTemplate = document.createElement("a");
6302 m_oCloseIconTemplate.className = "container-close";
6303 m_oCloseIconTemplate.href = "#";
6306 oClose = m_oCloseIconTemplate.cloneNode(true);
6307 this.innerElement.appendChild(oClose);
6309 oClose.innerHTML = (strings && strings.close) ? strings.close : " ";
6311 Event.on(oClose, "click", this._doClose, this, true);
6313 this.close = oClose;
6316 oClose.style.display = "block";
6321 oClose.style.display = "none";
6328 * Event handler for the close icon
6333 * @param {DOMEvent} e
6335 _doClose : function (e) {
6336 Event.preventDefault(e);
6341 * The default event handler fired when the "draggable" property
6343 * @method configDraggable
6344 * @param {String} type The CustomEvent type (usually the property name)
6345 * @param {Object[]} args The CustomEvent arguments. For configuration
6346 * handlers, args[0] will equal the newly applied value for the property.
6347 * @param {Object} obj The scope object. For configuration handlers,
6348 * this will usually equal the owner.
6350 configDraggable: function (type, args, obj) {
6355 this.cfg.setProperty("draggable", false);
6360 Dom.setStyle(this.header, "cursor", "move");
6361 this.registerDragDrop();
6364 this.subscribe("beforeShow", setWidthToOffsetWidth);
6373 Dom.setStyle(this.header,"cursor","auto");
6376 this.unsubscribe("beforeShow", setWidthToOffsetWidth);
6381 * The default event handler fired when the "underlay" property
6383 * @method configUnderlay
6384 * @param {String} type The CustomEvent type (usually the property name)
6385 * @param {Object[]} args The CustomEvent arguments. For configuration
6386 * handlers, args[0] will equal the newly applied value for the property.
6387 * @param {Object} obj The scope object. For configuration handlers,
6388 * this will usually equal the owner.
6390 configUnderlay: function (type, args, obj) {
6392 var bMacGecko = (this.platform == "mac" && UA.gecko),
6393 sUnderlay = args[0].toLowerCase(),
6394 oUnderlay = this.underlay,
6395 oElement = this.element;
6397 function createUnderlay() {
6399 if (!oUnderlay) { // create if not already in DOM
6401 if (!m_oUnderlayTemplate) {
6402 m_oUnderlayTemplate = document.createElement("div");
6403 m_oUnderlayTemplate.className = "underlay";
6406 oUnderlay = m_oUnderlayTemplate.cloneNode(false);
6407 this.element.appendChild(oUnderlay);
6409 this.underlay = oUnderlay;
6412 this.sizeUnderlay();
6413 this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
6414 this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
6416 this.changeContentEvent.subscribe(this.sizeUnderlay);
6417 YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
6420 if (UA.webkit && UA.webkit < 420) {
6421 this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
6428 function onBeforeShow() {
6429 var bNew = createUnderlay.call(this);
6430 if (!bNew && bIEQuirks) {
6431 this.sizeUnderlay();
6433 this._underlayDeferred = false;
6434 this.beforeShowEvent.unsubscribe(onBeforeShow);
6437 function destroyUnderlay() {
6438 if (this._underlayDeferred) {
6439 this.beforeShowEvent.unsubscribe(onBeforeShow);
6440 this._underlayDeferred = false;
6444 this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
6445 this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
6446 this.changeContentEvent.unsubscribe(this.sizeUnderlay);
6447 this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
6448 YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
6450 this.element.removeChild(oUnderlay);
6452 this.underlay = null;
6456 switch (sUnderlay) {
6458 Dom.removeClass(oElement, "matte");
6459 Dom.addClass(oElement, "shadow");
6463 destroyUnderlay.call(this);
6465 Dom.removeClass(oElement, "shadow");
6466 Dom.addClass(oElement, "matte");
6470 destroyUnderlay.call(this);
6472 Dom.removeClass(oElement, "shadow");
6473 Dom.removeClass(oElement, "matte");
6477 if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
6478 if (this.cfg.getProperty("visible")) {
6479 var bNew = createUnderlay.call(this);
6480 if (!bNew && bIEQuirks) {
6481 this.sizeUnderlay();
6484 if (!this._underlayDeferred) {
6485 this.beforeShowEvent.subscribe(onBeforeShow);
6486 this._underlayDeferred = true;
6493 * The default event handler fired when the "modal" property is
6494 * changed. This handler subscribes or unsubscribes to the show and hide
6495 * events to handle the display or hide of the modality mask.
6496 * @method configModal
6497 * @param {String} type The CustomEvent type (usually the property name)
6498 * @param {Object[]} args The CustomEvent arguments. For configuration
6499 * handlers, args[0] will equal the newly applied value for the property.
6500 * @param {Object} obj The scope object. For configuration handlers,
6501 * this will usually equal the owner.
6503 configModal: function (type, args, obj) {
6505 var modal = args[0];
6507 if (!this._hasModalityEventListeners) {
6509 this.subscribe("beforeShow", this.buildMask);
6510 this.subscribe("beforeShow", this.bringToTop);
6511 this.subscribe("beforeShow", this.showMask);
6512 this.subscribe("hide", this.hideMask);
6514 Overlay.windowResizeEvent.subscribe(this.sizeMask,
6517 this._hasModalityEventListeners = true;
6520 if (this._hasModalityEventListeners) {
6522 if (this.cfg.getProperty("visible")) {
6527 this.unsubscribe("beforeShow", this.buildMask);
6528 this.unsubscribe("beforeShow", this.bringToTop);
6529 this.unsubscribe("beforeShow", this.showMask);
6530 this.unsubscribe("hide", this.hideMask);
6532 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6534 this._hasModalityEventListeners = false;
6540 * Removes the modality mask.
6541 * @method removeMask
6543 removeMask: function () {
6545 var oMask = this.mask,
6550 Hide the mask before destroying it to ensure that DOM
6551 event handlers on focusable elements get removed.
6555 oParentNode = oMask.parentNode;
6557 oParentNode.removeChild(oMask);
6565 * The default event handler fired when the "keylisteners" property
6567 * @method configKeyListeners
6568 * @param {String} type The CustomEvent type (usually the property name)
6569 * @param {Object[]} args The CustomEvent arguments. For configuration
6570 * handlers, args[0] will equal the newly applied value for the property.
6571 * @param {Object} obj The scope object. For configuration handlers,
6572 * this will usually equal the owner.
6574 configKeyListeners: function (type, args, obj) {
6576 var listeners = args[0],
6583 if (listeners instanceof Array) {
6585 nListeners = listeners.length;
6587 for (i = 0; i < nListeners; i++) {
6589 listener = listeners[i];
6591 if (!Config.alreadySubscribed(this.showEvent,
6592 listener.enable, listener)) {
6594 this.showEvent.subscribe(listener.enable,
6599 if (!Config.alreadySubscribed(this.hideEvent,
6600 listener.disable, listener)) {
6602 this.hideEvent.subscribe(listener.disable,
6605 this.destroyEvent.subscribe(listener.disable,
6612 if (!Config.alreadySubscribed(this.showEvent,
6613 listeners.enable, listeners)) {
6615 this.showEvent.subscribe(listeners.enable,
6619 if (!Config.alreadySubscribed(this.hideEvent,
6620 listeners.disable, listeners)) {
6622 this.hideEvent.subscribe(listeners.disable,
6625 this.destroyEvent.subscribe(listeners.disable,
6637 * The default handler for the "strings" property
6638 * @method configStrings
6640 configStrings : function(type, args, obj) {
6641 var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
6642 this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
6646 * The default event handler fired when the "height" property is changed.
6647 * @method configHeight
6648 * @param {String} type The CustomEvent type (usually the property name)
6649 * @param {Object[]} args The CustomEvent arguments. For configuration
6650 * handlers, args[0] will equal the newly applied value for the property.
6651 * @param {Object} obj The scope object. For configuration handlers,
6652 * this will usually equal the owner.
6654 configHeight: function (type, args, obj) {
6655 var height = args[0],
6656 el = this.innerElement;
6658 Dom.setStyle(el, "height", height);
6659 this.cfg.refireEvent("iframe");
6663 * The default custom event handler executed when the Panel's height is changed,
6664 * if the autofillheight property has been set.
6666 * @method _autoFillOnHeightChange
6668 * @param {String} type The event type
6669 * @param {Array} args The array of arguments passed to event subscribers
6670 * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
6671 * out the containers height
6673 _autoFillOnHeightChange : function(type, args, el) {
6674 Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
6677 setTimeout(function() {
6678 panel.sizeUnderlay();
6684 * The default event handler fired when the "width" property is changed.
6685 * @method configWidth
6686 * @param {String} type The CustomEvent type (usually the property name)
6687 * @param {Object[]} args The CustomEvent arguments. For configuration
6688 * handlers, args[0] will equal the newly applied value for the property.
6689 * @param {Object} obj The scope object. For configuration handlers,
6690 * this will usually equal the owner.
6692 configWidth: function (type, args, obj) {
6694 var width = args[0],
6695 el = this.innerElement;
6697 Dom.setStyle(el, "width", width);
6698 this.cfg.refireEvent("iframe");
6703 * The default event handler fired when the "zIndex" property is changed.
6704 * @method configzIndex
6705 * @param {String} type The CustomEvent type (usually the property name)
6706 * @param {Object[]} args The CustomEvent arguments. For configuration
6707 * handlers, args[0] will equal the newly applied value for the property.
6708 * @param {Object} obj The scope object. For configuration handlers,
6709 * this will usually equal the owner.
6711 configzIndex: function (type, args, obj) {
6712 Panel.superclass.configzIndex.call(this, type, args, obj);
6714 if (this.mask || this.cfg.getProperty("modal") === true) {
6715 var panelZ = Dom.getStyle(this.element, "zIndex");
6716 if (!panelZ || isNaN(panelZ)) {
6721 // Recursive call to configzindex (which should be stopped
6722 // from going further because panelZ should no longer === 0)
6723 this.cfg.setProperty("zIndex", 1);
6730 // END BUILT-IN PROPERTY EVENT HANDLERS //
6732 * Builds the wrapping container around the Panel that is used for
6733 * positioning the shadow and matte underlays. The container element is
6734 * assigned to a local instance variable called container, and the
6735 * element is reinserted inside of it.
6736 * @method buildWrapper
6738 buildWrapper: function () {
6740 var elementParent = this.element.parentNode,
6741 originalElement = this.element,
6742 wrapper = document.createElement("div");
6744 wrapper.className = Panel.CSS_PANEL_CONTAINER;
6745 wrapper.id = originalElement.id + "_c";
6747 if (elementParent) {
6748 elementParent.insertBefore(wrapper, originalElement);
6751 wrapper.appendChild(originalElement);
6753 this.element = wrapper;
6754 this.innerElement = originalElement;
6756 Dom.setStyle(this.innerElement, "visibility", "inherit");
6760 * Adjusts the size of the shadow based on the size of the element.
6761 * @method sizeUnderlay
6763 sizeUnderlay: function () {
6764 var oUnderlay = this.underlay,
6768 oElement = this.element;
6769 oUnderlay.style.width = oElement.offsetWidth + "px";
6770 oUnderlay.style.height = oElement.offsetHeight + "px";
6775 * Registers the Panel's header for drag & drop capability.
6776 * @method registerDragDrop
6778 registerDragDrop: function () {
6788 var bDragOnly = (this.cfg.getProperty("dragonly") === true);
6791 * The YAHOO.util.DD instance, used to implement the draggable header for the panel if draggable is enabled
6794 * @type YAHOO.util.DD
6796 this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
6798 if (!this.header.id) {
6799 this.header.id = this.id + "_h";
6802 this.dd.startDrag = function () {
6811 if (YAHOO.env.ua.ie == 6) {
6812 Dom.addClass(me.element,"drag");
6815 if (me.cfg.getProperty("constraintoviewport")) {
6817 var nViewportOffset = Overlay.VIEWPORT_OFFSET;
6819 offsetHeight = me.element.offsetHeight;
6820 offsetWidth = me.element.offsetWidth;
6822 viewPortWidth = Dom.getViewportWidth();
6823 viewPortHeight = Dom.getViewportHeight();
6825 scrollX = Dom.getDocumentScrollLeft();
6826 scrollY = Dom.getDocumentScrollTop();
6828 if (offsetHeight + nViewportOffset < viewPortHeight) {
6829 this.minY = scrollY + nViewportOffset;
6830 this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
6832 this.minY = scrollY + nViewportOffset;
6833 this.maxY = scrollY + nViewportOffset;
6836 if (offsetWidth + nViewportOffset < viewPortWidth) {
6837 this.minX = scrollX + nViewportOffset;
6838 this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
6840 this.minX = scrollX + nViewportOffset;
6841 this.maxX = scrollX + nViewportOffset;
6844 this.constrainX = true;
6845 this.constrainY = true;
6847 this.constrainX = false;
6848 this.constrainY = false;
6851 me.dragEvent.fire("startDrag", arguments);
6854 this.dd.onDrag = function () {
6856 me.cfg.refireEvent("iframe");
6857 if (this.platform == "mac" && YAHOO.env.ua.gecko) {
6858 this.showMacGeckoScrollbars();
6861 me.dragEvent.fire("onDrag", arguments);
6864 this.dd.endDrag = function () {
6866 if (YAHOO.env.ua.ie == 6) {
6867 Dom.removeClass(me.element,"drag");
6870 me.dragEvent.fire("endDrag", arguments);
6871 me.moveEvent.fire(me.cfg.getProperty("xy"));
6875 this.dd.setHandleElId(this.header.id);
6876 this.dd.addInvalidHandleType("INPUT");
6877 this.dd.addInvalidHandleType("SELECT");
6878 this.dd.addInvalidHandleType("TEXTAREA");
6883 * Builds the mask that is laid over the document when the Panel is
6884 * configured to be modal.
6887 buildMask: function () {
6888 var oMask = this.mask;
6890 if (!m_oMaskTemplate) {
6891 m_oMaskTemplate = document.createElement("div");
6892 m_oMaskTemplate.className = "mask";
6893 m_oMaskTemplate.innerHTML = " ";
6895 oMask = m_oMaskTemplate.cloneNode(true);
6896 oMask.id = this.id + "_mask";
6898 document.body.insertBefore(oMask, document.body.firstChild);
6902 if (YAHOO.env.ua.gecko && this.platform == "mac") {
6903 Dom.addClass(this.mask, "block-scrollbars");
6906 // Stack mask based on the element zindex
6912 * Hides the modality mask.
6915 hideMask: function () {
6916 if (this.cfg.getProperty("modal") && this.mask) {
6917 this.mask.style.display = "none";
6918 Dom.removeClass(document.body, "masked");
6919 this.hideMaskEvent.fire();
6924 * Shows the modality mask.
6927 showMask: function () {
6928 if (this.cfg.getProperty("modal") && this.mask) {
6929 Dom.addClass(document.body, "masked");
6931 this.mask.style.display = "block";
6932 this.showMaskEvent.fire();
6937 * Sets the size of the modality mask to cover the entire scrollable
6938 * area of the document
6941 sizeMask: function () {
6944 // Shrink mask first, so it doesn't affect the document size.
6945 var mask = this.mask,
6946 viewWidth = Dom.getViewportWidth(),
6947 viewHeight = Dom.getViewportHeight();
6949 if (mask.offsetHeight > viewHeight) {
6950 mask.style.height = viewHeight + "px";
6953 if (mask.offsetWidth > viewWidth) {
6954 mask.style.width = viewWidth + "px";
6957 // Then size it to the document
6958 mask.style.height = Dom.getDocumentHeight() + "px";
6959 mask.style.width = Dom.getDocumentWidth() + "px";
6964 * Sets the zindex of the mask, if it exists, based on the zindex of
6965 * the Panel element. The zindex of the mask is set to be one less
6966 * than the Panel element's zindex.
6968 * <p>NOTE: This method will not bump up the zindex of the Panel
6969 * to ensure that the mask has a non-negative zindex. If you require the
6970 * mask zindex to be 0 or higher, the zindex of the Panel
6971 * should be set to a value higher than 0, before this method is called.
6975 stackMask: function() {
6977 var panelZ = Dom.getStyle(this.element, "zIndex");
6978 if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
6979 Dom.setStyle(this.mask, "zIndex", panelZ - 1);
6985 * Renders the Panel by inserting the elements that are not already in
6986 * the main Panel into their correct places. Optionally appends the
6987 * Panel to the specified node prior to the render's execution. NOTE:
6988 * For Panels without existing markup, the appendToNode argument is
6989 * REQUIRED. If this argument is ommitted and the current element is
6990 * not present in the document, the function will return false,
6991 * indicating that the render was a failure.
6993 * @param {String} appendToNode The element id to which the Module
6994 * should be appended to prior to rendering <em>OR</em>
6995 * @param {HTMLElement} appendToNode The element to which the Module
6996 * should be appended to prior to rendering
6997 * @return {boolean} Success or failure of the render
6999 render: function (appendToNode) {
7000 return Panel.superclass.render.call(this, appendToNode, this.innerElement);
7004 * Renders the currently set header into it's proper position under the
7005 * module element. If the module element is not provided, "this.innerElement"
7008 * @method _renderHeader
7010 * @param {HTMLElement} moduleElement Optional. A reference to the module element
7012 _renderHeader: function(moduleElement){
7013 moduleElement = moduleElement || this.innerElement;
7014 Panel.superclass._renderHeader.call(this, moduleElement);
7018 * Renders the currently set body into it's proper position under the
7019 * module element. If the module element is not provided, "this.innerElement"
7022 * @method _renderBody
7024 * @param {HTMLElement} moduleElement Optional. A reference to the module element.
7026 _renderBody: function(moduleElement){
7027 moduleElement = moduleElement || this.innerElement;
7028 Panel.superclass._renderBody.call(this, moduleElement);
7032 * Renders the currently set footer into it's proper position under the
7033 * module element. If the module element is not provided, "this.innerElement"
7036 * @method _renderFooter
7038 * @param {HTMLElement} moduleElement Optional. A reference to the module element
7040 _renderFooter: function(moduleElement){
7041 moduleElement = moduleElement || this.innerElement;
7042 Panel.superclass._renderFooter.call(this, moduleElement);
7046 * Removes the Panel element from the DOM and sets all child elements
7050 destroy: function () {
7051 Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
7054 Event.purgeElement(this.close);
7056 Panel.superclass.destroy.call(this);
7060 * Forces the underlay element to be repainted through the application/removal
7061 * of a yui-force-redraw class to the underlay element.
7063 * @method forceUnderlayRedraw
7065 forceUnderlayRedraw : function () {
7066 var u = this.underlay;
7067 Dom.addClass(u, "yui-force-redraw");
7068 setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
7072 * Returns a String representation of the object.
7074 * @return {String} The string representation of the Panel.
7076 toString: function () {
7077 return "Panel " + this.id;
7087 * Dialog is an implementation of Panel that can be used to submit form
7091 * Built-in functionality for buttons with event handlers is included.
7092 * If the optional YUI Button dependancy is included on the page, the buttons
7093 * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
7097 * Forms can be processed in 3 ways -- via an asynchronous Connection utility call,
7098 * a simple form POST or GET, or manually. The YUI Connection utility should be
7099 * included if you're using the default "async" postmethod, but is not required if
7100 * you're using any of the other postmethod values.
7102 * @namespace YAHOO.widget
7104 * @extends YAHOO.widget.Panel
7106 * @param {String} el The element ID representing the Dialog <em>OR</em>
7107 * @param {HTMLElement} el The element representing the Dialog
7108 * @param {Object} userConfig The configuration object literal containing
7109 * the configuration that should be set for this Dialog. See configuration
7110 * documentation for more details.
7112 YAHOO.widget.Dialog = function (el, userConfig) {
7113 YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
7116 var Event = YAHOO.util.Event,
7117 CustomEvent = YAHOO.util.CustomEvent,
7118 Dom = YAHOO.util.Dom,
7119 Dialog = YAHOO.widget.Dialog,
7123 * Constant representing the name of the Dialog's events
7124 * @property EVENT_TYPES
7130 "BEFORE_SUBMIT": "beforeSubmit",
7132 "MANUAL_SUBMIT": "manualSubmit",
7133 "ASYNC_SUBMIT": "asyncSubmit",
7134 "FORM_SUBMIT": "formSubmit",
7139 * Constant representing the Dialog's configuration properties
7140 * @property DEFAULT_CONFIG
7160 supercedes: ["visible"]
7163 "HIDEAFTERSUBMIT" : {
7164 key: "hideaftersubmit",
7171 * Constant representing the default CSS class used for a Dialog
7172 * @property YAHOO.widget.Dialog.CSS_DIALOG
7177 Dialog.CSS_DIALOG = "yui-dialog";
7179 function removeButtonEventHandlers() {
7181 var aButtons = this._aButtons,
7186 if (Lang.isArray(aButtons)) {
7187 nButtons = aButtons.length;
7192 oButton = aButtons[i];
7194 if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
7197 else if (oButton.tagName.toUpperCase() == "BUTTON") {
7198 Event.purgeElement(oButton);
7199 Event.purgeElement(oButton, false);
7207 YAHOO.extend(Dialog, YAHOO.widget.Panel, {
7211 * @description Object reference to the Dialog's
7212 * <code><form></code> element.
7214 * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7215 * level-one-html.html#ID-40002357">HTMLFormElement</a>
7220 * Initializes the class's configurable properties which can be changed
7221 * using the Dialog's Config object (cfg).
7222 * @method initDefaultConfig
7224 initDefaultConfig: function () {
7225 Dialog.superclass.initDefaultConfig.call(this);
7228 * The internally maintained callback object for use with the
7229 * Connection utility. The format of the callback object is
7230 * similar to Connection Manager's callback object and is
7231 * simply passed through to Connection Manager when the async
7233 * @property callback
7239 * The function to execute upon success of the
7240 * Connection submission (when the form does not
7241 * contain a file input element).
7243 * @property callback.success
7249 * The function to execute upon failure of the
7250 * Connection submission
7251 * @property callback.failure
7258 * The function to execute upon success of the
7259 * Connection submission, when the form contains
7260 * a file input element.
7263 * <em>NOTE:</em> Connection manager will not
7264 * invoke the success or failure handlers for the file
7265 * upload use case. This will be the only callback
7269 * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
7270 * Connection Manager documenation on file uploads</a>.
7272 * @property callback.upload
7277 * The arbitraty argument or arguments to pass to the Connection
7278 * callback functions
7279 * @property callback.argument
7286 // Add form dialog config properties //
7288 * The method to use for posting the Dialog's form. Possible values
7289 * are "async", "form", and "manual".
7290 * @config postmethod
7294 this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
7295 handler: this.configPostMethod,
7296 value: DEFAULT_CONFIG.POST_METHOD.value,
7297 validator: function (val) {
7298 if (val != "form" && val != "async" && val != "none" &&
7308 * Any additional post data which needs to be sent when using the
7309 * <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
7310 * The format for the post data string is defined by Connection Manager's
7311 * <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a>
7317 this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
7318 value: DEFAULT_CONFIG.POST_DATA.value
7322 * This property is used to configure whether or not the
7323 * dialog should be automatically hidden after submit.
7325 * @config hideaftersubmit
7329 this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
7330 value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
7334 * Array of object literals, each containing a set of properties
7335 * defining a button to be appended into the Dialog's footer.
7337 * <p>Each button object in the buttons array can have three properties:</p>
7341 * The text that will display on the face of the button. The text can
7342 * include HTML, as long as it is compliant with HTML Button specifications.
7345 * <dd>Can be either:
7347 * <li>A reference to a function that should fire when the
7348 * button is clicked. (In this case scope of this function is
7349 * always its Dialog instance.)</li>
7351 * <li>An object literal representing the code to be
7352 * executed when the button is clicked.
7359 * <strong>fn:</strong> Function, //
7360 * The handler to call when the event fires.
7362 * <strong>obj:</strong> Object, //
7363 * An object to pass back to the handler.
7365 * <strong>scope:</strong> Object //
7366 * The object to use for the scope of the handler.
7373 * <dt>isDefault:</dt>
7375 * An optional boolean value that specifies that a button
7376 * should be highlighted and focused by default.
7380 * <em>NOTE:</em>If the YUI Button Widget is included on the page,
7381 * the buttons created will be instances of YAHOO.widget.Button.
7382 * Otherwise, HTML Buttons (<code><BUTTON></code>) will be
7386 * @type {Array|String}
7389 this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
7390 handler: this.configButtons,
7391 value: DEFAULT_CONFIG.BUTTONS.value,
7392 supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
7398 * Initializes the custom events for Dialog which are fired
7399 * automatically at appropriate times by the Dialog class.
7400 * @method initEvents
7402 initEvents: function () {
7403 Dialog.superclass.initEvents.call(this);
7405 var SIGNATURE = CustomEvent.LIST;
7408 * CustomEvent fired prior to submission
7409 * @event beforeSubmitEvent
7411 this.beforeSubmitEvent =
7412 this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
7413 this.beforeSubmitEvent.signature = SIGNATURE;
7416 * CustomEvent fired after submission
7417 * @event submitEvent
7419 this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
7420 this.submitEvent.signature = SIGNATURE;
7423 * CustomEvent fired for manual submission, before the generic submit event is fired
7424 * @event manualSubmitEvent
7426 this.manualSubmitEvent =
7427 this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
7428 this.manualSubmitEvent.signature = SIGNATURE;
7431 * CustomEvent fired after asynchronous submission, before the generic submit event is fired
7433 * @event asyncSubmitEvent
7434 * @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
7436 this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
7437 this.asyncSubmitEvent.signature = SIGNATURE;
7440 * CustomEvent fired after form-based submission, before the generic submit event is fired
7441 * @event formSubmitEvent
7443 this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
7444 this.formSubmitEvent.signature = SIGNATURE;
7447 * CustomEvent fired after cancel
7448 * @event cancelEvent
7450 this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
7451 this.cancelEvent.signature = SIGNATURE;
7456 * The Dialog initialization method, which is executed for Dialog and
7457 * all of its subclasses. This method is automatically called by the
7458 * constructor, and sets up all DOM references for pre-existing markup,
7459 * and creates required markup if it is not already present.
7462 * @param {String} el The element ID representing the Dialog <em>OR</em>
7463 * @param {HTMLElement} el The element representing the Dialog
7464 * @param {Object} userConfig The configuration object literal
7465 * containing the configuration that should be set for this Dialog.
7466 * See configuration documentation for more details.
7468 init: function (el, userConfig) {
7471 Note that we don't pass the user config in here yet because
7472 we only want it executed once, at the lowest subclass level
7475 Dialog.superclass.init.call(this, el/*, userConfig*/);
7477 this.beforeInitEvent.fire(Dialog);
7479 Dom.addClass(this.element, Dialog.CSS_DIALOG);
7481 this.cfg.setProperty("visible", false);
7484 this.cfg.applyConfig(userConfig, true);
7487 this.showEvent.subscribe(this.focusFirst, this, true);
7488 this.beforeHideEvent.subscribe(this.blurButtons, this, true);
7490 this.subscribe("changeBody", this.registerForm);
7492 this.initEvent.fire(Dialog);
7496 * Submits the Dialog's form depending on the value of the
7497 * "postmethod" configuration property. <strong>Please note:
7498 * </strong> As of version 2.3 this method will automatically handle
7499 * asyncronous file uploads should the Dialog instance's form contain
7500 * <code><input type="file"></code> elements. If a Dialog
7501 * instance will be handling asyncronous file uploads, its
7502 * <code>callback</code> property will need to be setup with a
7503 * <code>upload</code> handler rather than the standard
7504 * <code>success</code> and, or <code>failure</code> handlers. For more
7505 * information, see the <a href="http://developer.yahoo.com/yui/
7506 * connection/#file">Connection Manager documenation on file uploads</a>.
7509 doSubmit: function () {
7511 var Connect = YAHOO.util.Connect,
7513 bUseFileUpload = false,
7514 bUseSecureFileUpload = false,
7520 switch (this.cfg.getProperty("postmethod")) {
7523 aElements = oForm.elements;
7524 nElements = aElements.length;
7526 if (nElements > 0) {
7529 if (aElements[i].type == "file") {
7530 bUseFileUpload = true;
7537 if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
7538 bUseSecureFileUpload = true;
7541 formAttrs = this._getFormAttributes(oForm);
7543 Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
7545 var postData = this.cfg.getProperty("postdata");
7546 var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
7548 this.asyncSubmitEvent.fire(c);
7554 this.formSubmitEvent.fire();
7559 this.manualSubmitEvent.fire();
7565 * Retrieves important attributes (currently method and action) from
7566 * the form element, accounting for any elements which may have the same name
7567 * as the attributes. Defaults to "POST" and "" for method and action respectively
7568 * if the attribute cannot be retrieved.
7570 * @method _getFormAttributes
7572 * @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
7573 * @return {Object} Object literal, with method and action String properties.
7575 _getFormAttributes : function(oForm){
7582 if (oForm.getAttributeNode) {
7583 var action = oForm.getAttributeNode("action");
7584 var method = oForm.getAttributeNode("method");
7587 attrs.action = action.value;
7591 attrs.method = method.value;
7595 attrs.action = oForm.getAttribute("action");
7596 attrs.method = oForm.getAttribute("method");
7600 attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
7601 attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
7607 * Prepares the Dialog's internal FORM object, creating one if one is
7608 * not currently present.
7609 * @method registerForm
7611 registerForm: function() {
7613 var form = this.element.getElementsByTagName("form")[0];
7616 if (this.form == form && Dom.isAncestor(this.element, this.form)) {
7619 Event.purgeElement(this.form);
7625 form = document.createElement("form");
7626 form.name = "frm_" + this.id;
7627 this.body.appendChild(form);
7632 Event.on(form, "submit", this._submitHandler, this, true);
7637 * Internal handler for the form submit event
7639 * @method _submitHandler
7641 * @param {DOMEvent} e The DOM Event object
7643 _submitHandler : function(e) {
7650 * Sets up a tab, shift-tab loop between the first and last elements
7651 * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
7652 * instance properties, which are reset everytime this method is invoked.
7654 * @method setTabLoop
7655 * @param {HTMLElement} firstElement
7656 * @param {HTMLElement} lastElement
7659 setTabLoop : function(firstElement, lastElement) {
7661 firstElement = firstElement || this.firstButton;
7662 lastElement = this.lastButton || lastElement;
7664 Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
7668 * Configures instance properties, pointing to the
7669 * first and last focusable elements in the Dialog's form.
7671 * @method setFirstLastFocusable
7673 setFirstLastFocusable : function() {
7675 Dialog.superclass.setFirstLastFocusable.call(this);
7677 var i, l, el, elements = this.focusableElements;
7679 this.firstFormElement = null;
7680 this.lastFormElement = null;
7682 if (this.form && elements && elements.length > 0) {
7683 l = elements.length;
7685 for (i = 0; i < l; ++i) {
7687 if (this.form === el.form) {
7688 this.firstFormElement = el;
7693 for (i = l-1; i >= 0; --i) {
7695 if (this.form === el.form) {
7696 this.lastFormElement = el;
7703 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7705 * The default event handler fired when the "close" property is
7706 * changed. The method controls the appending or hiding of the close
7707 * icon at the top right of the Dialog.
7708 * @method configClose
7709 * @param {String} type The CustomEvent type (usually the property name)
7710 * @param {Object[]} args The CustomEvent arguments. For
7711 * configuration handlers, args[0] will equal the newly applied value
7713 * @param {Object} obj The scope object. For configuration handlers,
7714 * this will usually equal the owner.
7716 configClose: function (type, args, obj) {
7717 Dialog.superclass.configClose.apply(this, arguments);
7721 * Event handler for the close icon
7726 * @param {DOMEvent} e
7728 _doClose : function(e) {
7729 Event.preventDefault(e);
7734 * The default event handler for the "buttons" configuration property
7735 * @method configButtons
7736 * @param {String} type The CustomEvent type (usually the property name)
7737 * @param {Object[]} args The CustomEvent arguments. For configuration
7738 * handlers, args[0] will equal the newly applied value for the property.
7739 * @param {Object} obj The scope object. For configuration handlers,
7740 * this will usually equal the owner.
7742 configButtons: function (type, args, obj) {
7744 var Button = YAHOO.widget.Button,
7746 oInnerElement = this.innerElement,
7755 removeButtonEventHandlers.call(this);
7757 this._aButtons = null;
7759 if (Lang.isArray(aButtons)) {
7761 oSpan = document.createElement("span");
7762 oSpan.className = "button-group";
7763 nButtons = aButtons.length;
7765 this._aButtons = [];
7766 this.defaultHtmlButton = null;
7768 for (i = 0; i < nButtons; i++) {
7769 oButton = aButtons[i];
7772 oYUIButton = new Button({ label: oButton.text});
7773 oYUIButton.appendTo(oSpan);
7775 oButtonEl = oYUIButton.get("element");
7777 if (oButton.isDefault) {
7778 oYUIButton.addClass("default");
7779 this.defaultHtmlButton = oButtonEl;
7782 if (Lang.isFunction(oButton.handler)) {
7784 oYUIButton.set("onclick", {
7785 fn: oButton.handler,
7790 } else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
7792 oYUIButton.set("onclick", {
7793 fn: oButton.handler.fn,
7794 obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7795 scope: (oButton.handler.scope || this)
7800 this._aButtons[this._aButtons.length] = oYUIButton;
7804 oButtonEl = document.createElement("button");
7805 oButtonEl.setAttribute("type", "button");
7807 if (oButton.isDefault) {
7808 oButtonEl.className = "default";
7809 this.defaultHtmlButton = oButtonEl;
7812 oButtonEl.innerHTML = oButton.text;
7814 if (Lang.isFunction(oButton.handler)) {
7815 Event.on(oButtonEl, "click", oButton.handler, this, true);
7816 } else if (Lang.isObject(oButton.handler) &&
7817 Lang.isFunction(oButton.handler.fn)) {
7819 Event.on(oButtonEl, "click",
7821 ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7822 (oButton.handler.scope || this));
7825 oSpan.appendChild(oButtonEl);
7826 this._aButtons[this._aButtons.length] = oButtonEl;
7829 oButton.htmlButton = oButtonEl;
7832 this.firstButton = oButtonEl;
7835 if (i == (nButtons - 1)) {
7836 this.lastButton = oButtonEl;
7840 this.setFooter(oSpan);
7842 oFooter = this.footer;
7844 if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
7845 oInnerElement.appendChild(oFooter);
7848 this.buttonSpan = oSpan;
7850 } else { // Do cleanup
7851 oSpan = this.buttonSpan;
7852 oFooter = this.footer;
7853 if (oSpan && oFooter) {
7854 oFooter.removeChild(oSpan);
7855 this.buttonSpan = null;
7856 this.firstButton = null;
7857 this.lastButton = null;
7858 this.defaultHtmlButton = null;
7862 this.changeContentEvent.fire();
7866 * @method getButtons
7867 * @description Returns an array containing each of the Dialog's
7868 * buttons, by default an array of HTML <code><BUTTON></code>
7869 * elements. If the Dialog's buttons were created using the
7870 * YAHOO.widget.Button class (via the inclusion of the optional Button
7871 * dependancy on the page), an array of YAHOO.widget.Button instances
7875 getButtons: function () {
7876 return this._aButtons || null;
7881 * Sets focus to the first focusable element in the Dialog's form if found,
7882 * else, the default button if found, else the first button defined via the
7883 * "buttons" configuration property.
7886 * This method is invoked when the Dialog is made visible.
7888 * @method focusFirst
7890 focusFirst: function (type, args, obj) {
7892 var el = this.firstFormElement;
7894 if (args && args[1]) {
7895 Event.stopEvent(args[1]);
7901 } catch(oException) {
7905 if (this.defaultHtmlButton) {
7906 this.focusDefaultButton();
7908 this.focusFirstButton();
7914 * Sets focus to the last element in the Dialog's form or the last
7915 * button defined via the "buttons" configuration property.
7918 focusLast: function (type, args, obj) {
7920 var aButtons = this.cfg.getProperty("buttons"),
7921 el = this.lastFormElement;
7923 if (args && args[1]) {
7924 Event.stopEvent(args[1]);
7927 if (aButtons && Lang.isArray(aButtons)) {
7928 this.focusLastButton();
7933 } catch(oException) {
7941 * Helper method to normalize button references. It either returns the
7942 * YUI Button instance for the given element if found,
7943 * or the passes back the HTMLElement reference if a corresponding YUI Button
7944 * reference is not found or YAHOO.widget.Button does not exist on the page.
7946 * @method _getButton
7948 * @param {HTMLElement} button
7949 * @return {YAHOO.widget.Button|HTMLElement}
7951 _getButton : function(button) {
7952 var Button = YAHOO.widget.Button;
7954 // If we have an HTML button and YUI Button is on the page,
7955 // get the YUI Button reference if available.
7956 if (Button && button && button.nodeName && button.id) {
7957 button = Button.getButton(button.id) || button;
7964 * Sets the focus to the button that is designated as the default via
7965 * the "buttons" configuration property. By default, this method is
7966 * called when the Dialog is made visible.
7967 * @method focusDefaultButton
7969 focusDefaultButton: function () {
7970 var button = this._getButton(this.defaultHtmlButton);
7973 Place the call to the "focus" method inside a try/catch
7974 block to prevent IE from throwing JavaScript errors if
7975 the element is disabled or hidden.
7979 } catch(oException) {
7985 * Blurs all the buttons defined via the "buttons"
7986 * configuration property.
7987 * @method blurButtons
7989 blurButtons: function () {
7991 var aButtons = this.cfg.getProperty("buttons"),
7997 if (aButtons && Lang.isArray(aButtons)) {
7998 nButtons = aButtons.length;
8002 oButton = aButtons[i];
8004 oElement = this._getButton(oButton.htmlButton);
8007 Place the call to the "blur" method inside
8008 a try/catch block to prevent IE from
8009 throwing JavaScript errors if the element
8010 is disabled or hidden.
8014 } catch(oException) {
8025 * Sets the focus to the first button created via the "buttons"
8026 * configuration property.
8027 * @method focusFirstButton
8029 focusFirstButton: function () {
8031 var aButtons = this.cfg.getProperty("buttons"),
8035 if (aButtons && Lang.isArray(aButtons)) {
8036 oButton = aButtons[0];
8038 oElement = this._getButton(oButton.htmlButton);
8041 Place the call to the "focus" method inside a
8042 try/catch block to prevent IE from throwing
8043 JavaScript errors if the element is disabled
8048 } catch(oException) {
8057 * Sets the focus to the last button created via the "buttons"
8058 * configuration property.
8059 * @method focusLastButton
8061 focusLastButton: function () {
8063 var aButtons = this.cfg.getProperty("buttons"),
8068 if (aButtons && Lang.isArray(aButtons)) {
8069 nButtons = aButtons.length;
8071 oButton = aButtons[(nButtons - 1)];
8074 oElement = this._getButton(oButton.htmlButton);
8077 Place the call to the "focus" method inside a
8078 try/catch block to prevent IE from throwing
8079 JavaScript errors if the element is disabled
8085 } catch(oException) {
8095 * The default event handler for the "postmethod" configuration property
8096 * @method configPostMethod
8097 * @param {String} type The CustomEvent type (usually the property name)
8098 * @param {Object[]} args The CustomEvent arguments. For
8099 * configuration handlers, args[0] will equal the newly applied value
8101 * @param {Object} obj The scope object. For configuration handlers,
8102 * this will usually equal the owner.
8104 configPostMethod: function (type, args, obj) {
8105 this.registerForm();
8108 // END BUILT-IN PROPERTY EVENT HANDLERS //
8111 * Built-in function hook for writing a validation function that will
8112 * be checked for a "true" value prior to a submit. This function, as
8113 * implemented by default, always returns true, so it should be
8114 * overridden if validation is necessary.
8117 validate: function () {
8122 * Executes a submit of the Dialog if validation
8123 * is successful. By default the Dialog is hidden
8124 * after submission, but you can set the "hideaftersubmit"
8125 * configuration property to false, to prevent the Dialog
8126 * from being hidden.
8130 submit: function () {
8131 if (this.validate()) {
8132 if (this.beforeSubmitEvent.fire()) {
8134 this.submitEvent.fire();
8136 if (this.cfg.getProperty("hideaftersubmit")) {
8150 * Executes the cancel of the Dialog followed by a hide.
8153 cancel: function () {
8154 this.cancelEvent.fire();
8159 * Returns a JSON-compatible data structure representing the data
8160 * currently contained in the form.
8162 * @return {Object} A JSON object reprsenting the data of the
8165 getData: function () {
8167 var oForm = this.form,
8186 function isFormElement(p_oElement) {
8187 var sTag = p_oElement.tagName.toUpperCase();
8188 return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
8189 sTag == "SELECT") && p_oElement.name == sName);
8194 aElements = oForm.elements;
8195 nTotalElements = aElements.length;
8198 for (i = 0; i < nTotalElements; i++) {
8199 sName = aElements[i].name;
8202 Using "Dom.getElementsBy" to safeguard user from JS
8203 errors that result from giving a form field (or set of
8204 fields) the same name as a native method of a form
8205 (like "submit") or a DOM collection (such as the "item"
8206 method). Originally tried accessing fields via the
8207 "namedItem" method of the "element" collection, but
8208 discovered that it won't return a collection of fields
8212 oElement = Dom.getElementsBy(isFormElement, "*", oForm);
8213 nElements = oElement.length;
8215 if (nElements > 0) {
8216 if (nElements == 1) {
8217 oElement = oElement[0];
8219 sType = oElement.type;
8220 sTagName = oElement.tagName.toUpperCase();
8224 if (sType == "checkbox") {
8225 oData[sName] = oElement.checked;
8226 } else if (sType != "radio") {
8227 oData[sName] = oElement.value;
8232 oData[sName] = oElement.value;
8236 aOptions = oElement.options;
8237 nOptions = aOptions.length;
8240 for (n = 0; n < nOptions; n++) {
8241 oOption = aOptions[n];
8242 if (oOption.selected) {
8243 valueAttr = oOption.attributes.value;
8244 aValues[aValues.length] = (valueAttr && valueAttr.specified) ? oOption.value : oOption.text;
8247 oData[sName] = aValues;
8252 sType = oElement[0].type;
8255 for (n = 0; n < nElements; n++) {
8256 oRadio = oElement[n];
8257 if (oRadio.checked) {
8258 oData[sName] = oRadio.value;
8266 for (n = 0; n < nElements; n++) {
8267 oCheckbox = oElement[n];
8268 if (oCheckbox.checked) {
8269 aValues[aValues.length] = oCheckbox.value;
8272 oData[sName] = aValues;
8284 * Removes the Panel element from the DOM and sets all child elements
8288 destroy: function () {
8289 removeButtonEventHandlers.call(this);
8291 this._aButtons = null;
8293 var aForms = this.element.getElementsByTagName("form"),
8296 if (aForms.length > 0) {
8300 Event.purgeElement(oForm);
8301 if (oForm.parentNode) {
8302 oForm.parentNode.removeChild(oForm);
8307 Dialog.superclass.destroy.call(this);
8311 * Returns a string representation of the object.
8313 * @return {String} The string representation of the Dialog
8315 toString: function () {
8316 return "Dialog " + this.id;
8325 * SimpleDialog is a simple implementation of Dialog that can be used to
8326 * submit a single value. Forms can be processed in 3 ways -- via an
8327 * asynchronous Connection utility call, a simple form POST or GET,
8329 * @namespace YAHOO.widget
8330 * @class SimpleDialog
8331 * @extends YAHOO.widget.Dialog
8333 * @param {String} el The element ID representing the SimpleDialog
8335 * @param {HTMLElement} el The element representing the SimpleDialog
8336 * @param {Object} userConfig The configuration object literal containing
8337 * the configuration that should be set for this SimpleDialog. See
8338 * configuration documentation for more details.
8340 YAHOO.widget.SimpleDialog = function (el, userConfig) {
8342 YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
8347 var Dom = YAHOO.util.Dom,
8348 SimpleDialog = YAHOO.widget.SimpleDialog,
8351 * Constant representing the SimpleDialog's configuration properties
8352 * @property DEFAULT_CONFIG
8368 suppressEvent: true,
8369 supercedes: ["icon"]
8375 * Constant for the standard network icon for a blocking action
8376 * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
8381 SimpleDialog.ICON_BLOCK = "blckicon";
8384 * Constant for the standard network icon for alarm
8385 * @property YAHOO.widget.SimpleDialog.ICON_ALARM
8390 SimpleDialog.ICON_ALARM = "alrticon";
8393 * Constant for the standard network icon for help
8394 * @property YAHOO.widget.SimpleDialog.ICON_HELP
8399 SimpleDialog.ICON_HELP = "hlpicon";
8402 * Constant for the standard network icon for info
8403 * @property YAHOO.widget.SimpleDialog.ICON_INFO
8408 SimpleDialog.ICON_INFO = "infoicon";
8411 * Constant for the standard network icon for warn
8412 * @property YAHOO.widget.SimpleDialog.ICON_WARN
8417 SimpleDialog.ICON_WARN = "warnicon";
8420 * Constant for the standard network icon for a tip
8421 * @property YAHOO.widget.SimpleDialog.ICON_TIP
8426 SimpleDialog.ICON_TIP = "tipicon";
8429 * Constant representing the name of the CSS class applied to the element
8430 * created by the "icon" configuration property.
8431 * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
8436 SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
8439 * Constant representing the default CSS class used for a SimpleDialog
8440 * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
8445 SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
8448 YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
8451 * Initializes the class's configurable properties which can be changed
8452 * using the SimpleDialog's Config object (cfg).
8453 * @method initDefaultConfig
8455 initDefaultConfig: function () {
8457 SimpleDialog.superclass.initDefaultConfig.call(this);
8459 // Add dialog config properties //
8462 * Sets the informational icon for the SimpleDialog
8467 this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
8468 handler: this.configIcon,
8469 value: DEFAULT_CONFIG.ICON.value,
8470 suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
8474 * Sets the text for the SimpleDialog
8479 this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
8480 handler: this.configText,
8481 value: DEFAULT_CONFIG.TEXT.value,
8482 suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
8483 supercedes: DEFAULT_CONFIG.TEXT.supercedes
8490 * The SimpleDialog initialization method, which is executed for
8491 * SimpleDialog and all of its subclasses. This method is automatically
8492 * called by the constructor, and sets up all DOM references for
8493 * pre-existing markup, and creates required markup if it is not
8496 * @param {String} el The element ID representing the SimpleDialog
8498 * @param {HTMLElement} el The element representing the SimpleDialog
8499 * @param {Object} userConfig The configuration object literal
8500 * containing the configuration that should be set for this
8501 * SimpleDialog. See configuration documentation for more details.
8503 init: function (el, userConfig) {
8506 Note that we don't pass the user config in here yet because we
8507 only want it executed once, at the lowest subclass level
8510 SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
8512 this.beforeInitEvent.fire(SimpleDialog);
8514 Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
8516 this.cfg.queueProperty("postmethod", "manual");
8519 this.cfg.applyConfig(userConfig, true);
8522 this.beforeRenderEvent.subscribe(function () {
8528 this.initEvent.fire(SimpleDialog);
8533 * Prepares the SimpleDialog's internal FORM object, creating one if one
8534 * is not currently present, and adding the value hidden field.
8535 * @method registerForm
8537 registerForm: function () {
8539 SimpleDialog.superclass.registerForm.call(this);
8541 this.form.innerHTML += "<input type=\"hidden\" name=\"" +
8542 this.id + "\" value=\"\"/>";
8546 // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
8549 * Fired when the "icon" property is set.
8550 * @method configIcon
8551 * @param {String} type The CustomEvent type (usually the property name)
8552 * @param {Object[]} args The CustomEvent arguments. For configuration
8553 * handlers, args[0] will equal the newly applied value for the property.
8554 * @param {Object} obj The scope object. For configuration handlers,
8555 * this will usually equal the owner.
8557 configIcon: function (type,args,obj) {
8559 var sIcon = args[0],
8561 sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
8566 if (sIcon && sIcon != "none") {
8568 aElements = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
8570 if (aElements.length === 1) {
8572 oIcon = aElements[0];
8573 oIconParent = oIcon.parentNode;
8577 oIconParent.removeChild(oIcon);
8586 if (sIcon.indexOf(".") == -1) {
8588 oIcon = document.createElement("span");
8589 oIcon.className = (sCSSClass + " " + sIcon);
8590 oIcon.innerHTML = " ";
8594 oIcon = document.createElement("img");
8595 oIcon.src = (this.imageRoot + sIcon);
8596 oIcon.className = sCSSClass;
8603 oBody.insertBefore(oIcon, oBody.firstChild);
8612 * Fired when the "text" property is set.
8613 * @method configText
8614 * @param {String} type The CustomEvent type (usually the property name)
8615 * @param {Object[]} args The CustomEvent arguments. For configuration
8616 * handlers, args[0] will equal the newly applied value for the property.
8617 * @param {Object} obj The scope object. For configuration handlers,
8618 * this will usually equal the owner.
8620 configText: function (type,args,obj) {
8624 this.cfg.refireEvent("icon");
8628 // END BUILT-IN PROPERTY EVENT HANDLERS //
8631 * Returns a string representation of the object.
8633 * @return {String} The string representation of the SimpleDialog
8635 toString: function () {
8636 return "SimpleDialog " + this.id;
8641 * Sets the SimpleDialog's body content to the HTML specified.
8642 * If no body is present, one will be automatically created.
8643 * An empty string can be passed to the method to clear the contents of the body.
8645 * <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
8646 * and <a href="#config_icon">icon</a> configuration properties to set the contents
8647 * of it's body element in accordance with the UI design for a SimpleDialog (an
8648 * icon and message text). Calling setBody on the SimpleDialog will not enforce this
8649 * UI design constraint and will replace the entire contents of the SimpleDialog body.
8650 * It should only be used if you wish the replace the default icon/text body structure
8651 * of a SimpleDialog with your own custom markup.</p>
8654 * @param {String} bodyContent The HTML used to set the body.
8655 * As a convenience, non HTMLElement objects can also be passed into
8656 * the method, and will be treated as strings, with the body innerHTML
8657 * set to their default toString implementations.
8659 * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
8661 * @param {DocumentFragment} bodyContent The document fragment
8662 * containing elements which are to be added to the body
8670 * ContainerEffect encapsulates animation transitions that are executed when
8671 * an Overlay is shown or hidden.
8672 * @namespace YAHOO.widget
8673 * @class ContainerEffect
8675 * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
8676 * should be associated with
8677 * @param {Object} attrIn The object literal representing the animation
8678 * arguments to be used for the animate-in transition. The arguments for
8679 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8680 * duration(Number), and method(i.e. Easing.easeIn).
8681 * @param {Object} attrOut The object literal representing the animation
8682 * arguments to be used for the animate-out transition. The arguments for
8683 * this literal are: attributes(object, see YAHOO.util.Anim for description),
8684 * duration(Number), and method(i.e. Easing.easeIn).
8685 * @param {HTMLElement} targetElement Optional. The target element that
8686 * should be animated during the transition. Defaults to overlay.element.
8687 * @param {class} Optional. The animation class to instantiate. Defaults to
8688 * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
8690 YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
8693 animClass = YAHOO.util.Anim;
8697 * The overlay to animate
8699 * @type YAHOO.widget.Overlay
8701 this.overlay = overlay;
8704 * The animation attributes to use when transitioning into view
8708 this.attrIn = attrIn;
8711 * The animation attributes to use when transitioning out of view
8715 this.attrOut = attrOut;
8718 * The target element to be animated
8719 * @property targetElement
8722 this.targetElement = targetElement || overlay.element;
8725 * The animation class to use for animating the overlay
8726 * @property animClass
8729 this.animClass = animClass;
8734 var Dom = YAHOO.util.Dom,
8735 CustomEvent = YAHOO.util.CustomEvent,
8736 ContainerEffect = YAHOO.widget.ContainerEffect;
8740 * A pre-configured ContainerEffect instance that can be used for fading
8741 * an overlay in and out.
8744 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8745 * @param {Number} dur The duration of the animation
8746 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8748 ContainerEffect.FADE = function (overlay, dur) {
8750 var Easing = YAHOO.util.Easing,
8752 attributes: {opacity:{from:0, to:1}},
8754 method: Easing.easeIn
8757 attributes: {opacity:{to:0}},
8759 method: Easing.easeOut
8761 fade = new ContainerEffect(overlay, fin, fout, overlay.element);
8763 fade.handleUnderlayStart = function() {
8764 var underlay = this.overlay.underlay;
8765 if (underlay && YAHOO.env.ua.ie) {
8766 var hasFilters = (underlay.filters && underlay.filters.length > 0);
8768 Dom.addClass(overlay.element, "yui-effect-fade");
8773 fade.handleUnderlayComplete = function() {
8774 var underlay = this.overlay.underlay;
8775 if (underlay && YAHOO.env.ua.ie) {
8776 Dom.removeClass(overlay.element, "yui-effect-fade");
8780 fade.handleStartAnimateIn = function (type, args, obj) {
8781 Dom.addClass(obj.overlay.element, "hide-select");
8783 if (!obj.overlay.underlay) {
8784 obj.overlay.cfg.refireEvent("underlay");
8787 obj.handleUnderlayStart();
8789 obj.overlay._setDomVisibility(true);
8790 Dom.setStyle(obj.overlay.element, "opacity", 0);
8793 fade.handleCompleteAnimateIn = function (type,args,obj) {
8794 Dom.removeClass(obj.overlay.element, "hide-select");
8796 if (obj.overlay.element.style.filter) {
8797 obj.overlay.element.style.filter = null;
8800 obj.handleUnderlayComplete();
8802 obj.overlay.cfg.refireEvent("iframe");
8803 obj.animateInCompleteEvent.fire();
8806 fade.handleStartAnimateOut = function (type, args, obj) {
8807 Dom.addClass(obj.overlay.element, "hide-select");
8808 obj.handleUnderlayStart();
8811 fade.handleCompleteAnimateOut = function (type, args, obj) {
8812 Dom.removeClass(obj.overlay.element, "hide-select");
8813 if (obj.overlay.element.style.filter) {
8814 obj.overlay.element.style.filter = null;
8816 obj.overlay._setDomVisibility(false);
8817 Dom.setStyle(obj.overlay.element, "opacity", 1);
8819 obj.handleUnderlayComplete();
8821 obj.overlay.cfg.refireEvent("iframe");
8822 obj.animateOutCompleteEvent.fire();
8831 * A pre-configured ContainerEffect instance that can be used for sliding an
8832 * overlay in and out.
8835 * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8836 * @param {Number} dur The duration of the animation
8837 * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8839 ContainerEffect.SLIDE = function (overlay, dur) {
8840 var Easing = YAHOO.util.Easing,
8842 x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
8843 y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
8844 clientWidth = Dom.getClientWidth(),
8845 offsetWidth = overlay.element.offsetWidth,
8848 attributes: { points: { to: [x, y] } },
8850 method: Easing.easeIn
8854 attributes: { points: { to: [(clientWidth + 25), y] } },
8856 method: Easing.easeOut
8859 slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
8861 slide.handleStartAnimateIn = function (type,args,obj) {
8862 obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
8863 obj.overlay.element.style.top = y + "px";
8866 slide.handleTweenAnimateIn = function (type, args, obj) {
8868 var pos = Dom.getXY(obj.overlay.element),
8872 if (Dom.getStyle(obj.overlay.element, "visibility") ==
8873 "hidden" && currentX < x) {
8875 obj.overlay._setDomVisibility(true);
8879 obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
8880 obj.overlay.cfg.refireEvent("iframe");
8883 slide.handleCompleteAnimateIn = function (type, args, obj) {
8884 obj.overlay.cfg.setProperty("xy", [x, y], true);
8887 obj.overlay.cfg.refireEvent("iframe");
8888 obj.animateInCompleteEvent.fire();
8891 slide.handleStartAnimateOut = function (type, args, obj) {
8893 var vw = Dom.getViewportWidth(),
8894 pos = Dom.getXY(obj.overlay.element),
8897 obj.animOut.attributes.points.to = [(vw + 25), yso];
8900 slide.handleTweenAnimateOut = function (type, args, obj) {
8902 var pos = Dom.getXY(obj.overlay.element),
8906 obj.overlay.cfg.setProperty("xy", [xto, yto], true);
8907 obj.overlay.cfg.refireEvent("iframe");
8910 slide.handleCompleteAnimateOut = function (type, args, obj) {
8911 obj.overlay._setDomVisibility(false);
8913 obj.overlay.cfg.setProperty("xy", [x, y]);
8914 obj.animateOutCompleteEvent.fire();
8921 ContainerEffect.prototype = {
8924 * Initializes the animation classes and events.
8929 this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
8930 this.beforeAnimateInEvent.signature = CustomEvent.LIST;
8932 this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
8933 this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
8935 this.animateInCompleteEvent = this.createEvent("animateInComplete");
8936 this.animateInCompleteEvent.signature = CustomEvent.LIST;
8938 this.animateOutCompleteEvent =
8939 this.createEvent("animateOutComplete");
8940 this.animateOutCompleteEvent.signature = CustomEvent.LIST;
8942 this.animIn = new this.animClass(this.targetElement,
8943 this.attrIn.attributes, this.attrIn.duration,
8944 this.attrIn.method);
8946 this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
8947 this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
8949 this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
8952 this.animOut = new this.animClass(this.targetElement,
8953 this.attrOut.attributes, this.attrOut.duration,
8954 this.attrOut.method);
8956 this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
8957 this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
8958 this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
8964 * Triggers the in-animation.
8967 animateIn: function () {
8968 this.beforeAnimateInEvent.fire();
8969 this.animIn.animate();
8973 * Triggers the out-animation.
8974 * @method animateOut
8976 animateOut: function () {
8977 this.beforeAnimateOutEvent.fire();
8978 this.animOut.animate();
8982 * The default onStart handler for the in-animation.
8983 * @method handleStartAnimateIn
8984 * @param {String} type The CustomEvent type
8985 * @param {Object[]} args The CustomEvent arguments
8986 * @param {Object} obj The scope object
8988 handleStartAnimateIn: function (type, args, obj) { },
8991 * The default onTween handler for the in-animation.
8992 * @method handleTweenAnimateIn
8993 * @param {String} type The CustomEvent type
8994 * @param {Object[]} args The CustomEvent arguments
8995 * @param {Object} obj The scope object
8997 handleTweenAnimateIn: function (type, args, obj) { },
9000 * The default onComplete handler for the in-animation.
9001 * @method handleCompleteAnimateIn
9002 * @param {String} type The CustomEvent type
9003 * @param {Object[]} args The CustomEvent arguments
9004 * @param {Object} obj The scope object
9006 handleCompleteAnimateIn: function (type, args, obj) { },
9009 * The default onStart handler for the out-animation.
9010 * @method handleStartAnimateOut
9011 * @param {String} type The CustomEvent type
9012 * @param {Object[]} args The CustomEvent arguments
9013 * @param {Object} obj The scope object
9015 handleStartAnimateOut: function (type, args, obj) { },
9018 * The default onTween handler for the out-animation.
9019 * @method handleTweenAnimateOut
9020 * @param {String} type The CustomEvent type
9021 * @param {Object[]} args The CustomEvent arguments
9022 * @param {Object} obj The scope object
9024 handleTweenAnimateOut: function (type, args, obj) { },
9027 * The default onComplete handler for the out-animation.
9028 * @method handleCompleteAnimateOut
9029 * @param {String} type The CustomEvent type
9030 * @param {Object[]} args The CustomEvent arguments
9031 * @param {Object} obj The scope object
9033 handleCompleteAnimateOut: function (type, args, obj) { },
9036 * Returns a string representation of the object.
9038 * @return {String} The string representation of the ContainerEffect
9040 toString: function () {
9041 var output = "ContainerEffect";
9043 output += " [" + this.overlay.toString() + "]";
9049 YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
9052 YAHOO.register("container", YAHOO.widget.Module, {version: "2.8.0r4", build: "2449"});