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) {
26
if (!owner) { YAHOO.log("No owner specified for Config object", "error", "Config"); }
31
var Lang = YAHOO.lang,
32
CustomEvent = YAHOO.util.CustomEvent,
33
Config = YAHOO.util.Config;
37
* Constant representing the CustomEvent type for the config changed event.
38
* @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
43
Config.CONFIG_CHANGED_EVENT = "configChanged";
46
* Constant representing the boolean type string
47
* @property YAHOO.util.Config.BOOLEAN_TYPE
52
Config.BOOLEAN_TYPE = "boolean";
57
* Object reference to the owner of this Config Object
64
* Boolean flag that specifies whether a queue is currently
66
* @property queueInProgress
69
queueInProgress: false,
72
* Maintains the local collection of configuration property objects and
73
* their specified values
81
* Maintains the local collection of configuration property objects as
82
* they were initially applied.
83
* This object is used when resetting a property.
84
* @property initialConfig
91
* Maintains the local, normalized CustomEvent queue
92
* @property eventQueue
99
* Custom Event, notifying subscribers when Config properties are set
100
* (setProperty is called without the silent flag
101
* @event configChangedEvent
103
configChangedEvent: null,
106
* Initializes the configuration Object and all of its local members.
108
* @param {Object} owner The owner Object to which this Config
111
init: function (owner) {
115
this.configChangedEvent =
116
this.createEvent(Config.CONFIG_CHANGED_EVENT);
118
this.configChangedEvent.signature = CustomEvent.LIST;
119
this.queueInProgress = false;
121
this.initialConfig = {};
122
this.eventQueue = [];
127
* Validates that the value passed in is a Boolean.
128
* @method checkBoolean
129
* @param {Object} val The value to validate
130
* @return {Boolean} true, if the value is valid
132
checkBoolean: function (val) {
133
return (typeof val == Config.BOOLEAN_TYPE);
137
* Validates that the value passed in is a number.
138
* @method checkNumber
139
* @param {Object} val The value to validate
140
* @return {Boolean} true, if the value is valid
142
checkNumber: function (val) {
143
return (!isNaN(val));
147
* Fires a configuration property event using the specified value.
150
* @param {String} key The configuration property's name
151
* @param {value} Object The value of the correct type for the property
153
fireEvent: function ( key, value ) {
154
YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
155
var property = this.config[key];
157
if (property && property.event) {
158
property.event.fire(value);
163
* Adds a property to the Config Object's private config hash.
164
* @method addProperty
165
* @param {String} key The configuration property's name
166
* @param {Object} propertyObject The Object containing all of this
167
* property's arguments
169
addProperty: function ( key, propertyObject ) {
170
key = key.toLowerCase();
171
YAHOO.log("Added property: " + key, "info", "Config");
173
this.config[key] = propertyObject;
175
propertyObject.event = this.createEvent(key, { scope: this.owner });
176
propertyObject.event.signature = CustomEvent.LIST;
179
propertyObject.key = key;
181
if (propertyObject.handler) {
182
propertyObject.event.subscribe(propertyObject.handler,
186
this.setProperty(key, propertyObject.value, true);
188
if (! propertyObject.suppressEvent) {
189
this.queueProperty(key, propertyObject.value);
195
* Returns a key-value configuration map of the values currently set in
198
* @return {Object} The current config, represented in a key-value map
200
getConfig: function () {
203
currCfg = this.config,
207
for (prop in currCfg) {
208
if (Lang.hasOwnProperty(currCfg, prop)) {
209
property = currCfg[prop];
210
if (property && property.event) {
211
cfg[prop] = property.value;
220
* Returns the value of specified property.
221
* @method getProperty
222
* @param {String} key The name of the property
223
* @return {Object} The value of the specified property
225
getProperty: function (key) {
226
var property = this.config[key.toLowerCase()];
227
if (property && property.event) {
228
return property.value;
235
* Resets the specified property's value to its initial value.
236
* @method resetProperty
237
* @param {String} key The name of the property
238
* @return {Boolean} True is the property was reset, false if not
240
resetProperty: function (key) {
242
key = key.toLowerCase();
244
var property = this.config[key];
246
if (property && property.event) {
248
if (this.initialConfig[key] &&
249
!Lang.isUndefined(this.initialConfig[key])) {
251
this.setProperty(key, this.initialConfig[key]);
265
* Sets the value of a property. If the silent property is passed as
266
* true, the property's event will not be fired.
267
* @method setProperty
268
* @param {String} key The name of the property
269
* @param {String} value The value to set the property to
270
* @param {Boolean} silent Whether the value should be set silently,
271
* without firing the property event.
272
* @return {Boolean} True, if the set was successful, false if it failed.
274
setProperty: function (key, value, silent) {
278
key = key.toLowerCase();
279
YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
281
if (this.queueInProgress && ! silent) {
282
// Currently running through a queue...
283
this.queueProperty(key,value);
287
property = this.config[key];
288
if (property && property.event) {
289
if (property.validator && !property.validator(value)) {
292
property.value = value;
294
this.fireEvent(key, value);
295
this.configChangedEvent.fire([key, value]);
306
* Sets the value of a property and queues its event to execute. If the
307
* event is already scheduled to execute, it is
308
* moved from its current position to the end of the queue.
309
* @method queueProperty
310
* @param {String} key The name of the property
311
* @param {String} value The value to set the property to
312
* @return {Boolean} true, if the set was successful, false if
315
queueProperty: function (key, value) {
317
key = key.toLowerCase();
318
YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
320
var property = this.config[key],
321
foundDuplicate = false,
336
if (property && property.event) {
338
if (!Lang.isUndefined(value) && property.validator &&
339
!property.validator(value)) { // validator
343
if (!Lang.isUndefined(value)) {
344
property.value = value;
346
value = property.value;
349
foundDuplicate = false;
350
iLen = this.eventQueue.length;
352
for (i = 0; i < iLen; i++) {
353
queueItem = this.eventQueue[i];
356
queueItemKey = queueItem[0];
357
queueItemValue = queueItem[1];
359
if (queueItemKey == key) {
362
found a dupe... push to end of queue, null
363
current item, and break
366
this.eventQueue[i] = null;
368
this.eventQueue.push(
369
[key, (!Lang.isUndefined(value) ?
370
value : queueItemValue)]);
372
foundDuplicate = true;
378
// this is a refire, or a new property in the queue
380
if (! foundDuplicate && !Lang.isUndefined(value)) {
381
this.eventQueue.push([key, value]);
385
if (property.supercedes) {
387
sLen = property.supercedes.length;
389
for (s = 0; s < sLen; s++) {
391
supercedesCheck = property.supercedes[s];
392
qLen = this.eventQueue.length;
394
for (q = 0; q < qLen; q++) {
395
queueItemCheck = this.eventQueue[q];
397
if (queueItemCheck) {
398
queueItemCheckKey = queueItemCheck[0];
399
queueItemCheckValue = queueItemCheck[1];
401
if (queueItemCheckKey ==
402
supercedesCheck.toLowerCase() ) {
404
this.eventQueue.push([queueItemCheckKey,
405
queueItemCheckValue]);
407
this.eventQueue[q] = null;
416
YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
425
* Fires the event for a property using the property's current value.
426
* @method refireEvent
427
* @param {String} key The name of the property
429
refireEvent: function (key) {
431
key = key.toLowerCase();
433
var property = this.config[key];
435
if (property && property.event &&
437
!Lang.isUndefined(property.value)) {
439
if (this.queueInProgress) {
441
this.queueProperty(key);
445
this.fireEvent(key, property.value);
453
* Applies a key-value Object literal to the configuration, replacing
454
* any existing values, and queueing the property events.
455
* Although the values will be set, fireQueue() must be called for their
456
* associated events to execute.
457
* @method applyConfig
458
* @param {Object} userConfig The configuration Object literal
459
* @param {Boolean} init When set to true, the initialConfig will
460
* be set to the userConfig passed in, so that calling a reset will
461
* reset the properties to the passed values.
463
applyConfig: function (userConfig, init) {
470
for (sKey in userConfig) {
471
if (Lang.hasOwnProperty(userConfig, sKey)) {
472
oConfig[sKey.toLowerCase()] = userConfig[sKey];
475
this.initialConfig = oConfig;
478
for (sKey in userConfig) {
479
if (Lang.hasOwnProperty(userConfig, sKey)) {
480
this.queueProperty(sKey, userConfig[sKey]);
486
* Refires the events for all configuration properties using their
490
refresh: function () {
494
for (prop in this.config) {
495
if (Lang.hasOwnProperty(this.config, prop)) {
496
this.refireEvent(prop);
502
* Fires the normalized list of queued property change events
505
fireQueue: function () {
513
this.queueInProgress = true;
514
for (i = 0;i < this.eventQueue.length; i++) {
515
queueItem = this.eventQueue[i];
519
value = queueItem[1];
520
property = this.config[key];
522
property.value = value;
524
// Clear out queue entry, to avoid it being
525
// re-added to the queue by any queueProperty/supercedes
526
// calls which are invoked during fireEvent
527
this.eventQueue[i] = null;
529
this.fireEvent(key,value);
533
this.queueInProgress = false;
534
this.eventQueue = [];
538
* Subscribes an external handler to the change event for any
540
* @method subscribeToConfigEvent
541
* @param {String} key The property name
542
* @param {Function} handler The handler function to use subscribe to
543
* the property's event
544
* @param {Object} obj The Object to use for scoping the event handler
545
* (see CustomEvent documentation)
546
* @param {Boolean} override Optional. If true, will override "this"
547
* within the handler to map to the scope Object passed into the method.
548
* @return {Boolean} True, if the subscription was successful,
551
subscribeToConfigEvent: function (key, handler, obj, override) {
553
var property = this.config[key.toLowerCase()];
555
if (property && property.event) {
556
if (!Config.alreadySubscribed(property.event, handler, obj)) {
557
property.event.subscribe(handler, obj, override);
567
* Unsubscribes an external handler from the change event for any
569
* @method unsubscribeFromConfigEvent
570
* @param {String} key The property name
571
* @param {Function} handler The handler function to use subscribe to
572
* the property's event
573
* @param {Object} obj The Object to use for scoping the event
574
* handler (see CustomEvent documentation)
575
* @return {Boolean} True, if the unsubscription was successful,
578
unsubscribeFromConfigEvent: function (key, handler, obj) {
579
var property = this.config[key.toLowerCase()];
580
if (property && property.event) {
581
return property.event.unsubscribe(handler, obj);
588
* Returns a string representation of the Config object
590
* @return {String} The Config object in string format.
592
toString: function () {
593
var output = "Config";
595
output += " [" + this.owner.toString() + "]";
601
* Returns a string representation of the Config object's current
603
* @method outputEventQueue
604
* @return {String} The string list of CustomEvents currently queued
607
outputEventQueue: function () {
612
nQueue = this.eventQueue.length;
614
for (q = 0; q < nQueue; q++) {
615
queueItem = this.eventQueue[q];
617
output += queueItem[0] + "=" + queueItem[1] + ", ";
624
* Sets all properties to null, unsubscribes all listeners from each
625
* property's change event and all listeners from the configChangedEvent.
628
destroy: function () {
630
var oConfig = this.config,
635
for (sProperty in oConfig) {
637
if (Lang.hasOwnProperty(oConfig, sProperty)) {
639
oProperty = oConfig[sProperty];
641
oProperty.event.unsubscribeAll();
642
oProperty.event = null;
648
this.configChangedEvent.unsubscribeAll();
650
this.configChangedEvent = null;
653
this.initialConfig = null;
654
this.eventQueue = null;
663
* Checks to determine if a particular function/Object pair are already
664
* subscribed to the specified CustomEvent
665
* @method YAHOO.util.Config.alreadySubscribed
667
* @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
669
* @param {Function} fn The function to look for in the subscribers list
670
* @param {Object} obj The execution scope Object for the subscription
671
* @return {Boolean} true, if the function/Object pair is already subscribed
672
* to the CustomEvent passed in
674
Config.alreadySubscribed = function (evt, fn, obj) {
676
var nSubscribers = evt.subscribers.length,
680
if (nSubscribers > 0) {
681
i = nSubscribers - 1;
683
subsc = evt.subscribers[i];
684
if (subsc && subsc.obj == obj && subsc.fn == fn) {
695
YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
702
* The Container family of components is designed to enable developers to
703
* create different kinds of content-containing modules on the web. Module
704
* and Overlay are the most basic containers, and they can be used directly
705
* or extended to build custom containers. Also part of the Container family
706
* are four UI controls that extend Module and Overlay: Tooltip, Panel,
707
* Dialog, and SimpleDialog.
710
* @requires yahoo, dom, event
711
* @optional dragdrop, animation, button
715
* Module is a JavaScript representation of the Standard Module Format.
716
* Standard Module Format is a simple standard for markup containers where
717
* child nodes representing the header, body, and footer of the content are
718
* denoted using the CSS classes "hd", "bd", and "ft" respectively.
719
* Module is the base class for all other classes in the YUI
721
* @namespace YAHOO.widget
724
* @param {String} el The element ID representing the Module <em>OR</em>
725
* @param {HTMLElement} el The element representing the Module
726
* @param {Object} userConfig The configuration Object literal containing
727
* the configuration that should be set for this module. See configuration
728
* documentation for more details.
730
YAHOO.widget.Module = function (el, userConfig) {
732
this.init(el, userConfig);
734
YAHOO.log("No element or element ID specified" +
735
" for Module instantiation", "error");
739
var Dom = YAHOO.util.Dom,
740
Config = YAHOO.util.Config,
741
Event = YAHOO.util.Event,
742
CustomEvent = YAHOO.util.CustomEvent,
743
Module = YAHOO.widget.Module,
752
* Constant representing the name of the Module's events
753
* @property EVENT_TYPES
759
"BEFORE_INIT": "beforeInit",
762
"BEFORE_RENDER": "beforeRender",
764
"CHANGE_HEADER": "changeHeader",
765
"CHANGE_BODY": "changeBody",
766
"CHANGE_FOOTER": "changeFooter",
767
"CHANGE_CONTENT": "changeContent",
768
"DESTORY": "destroy",
769
"BEFORE_SHOW": "beforeShow",
771
"BEFORE_HIDE": "beforeHide",
776
* Constant representing the Module's configuration properties
777
* @property DEFAULT_CONFIG
787
validator: YAHOO.lang.isBoolean
793
supercedes: ["visible"]
797
key: "monitorresize",
801
"APPEND_TO_DOCUMENT_BODY": {
802
key: "appendtodocumentbody",
808
* Constant representing the prefix path to use for non-secure images
809
* @property YAHOO.widget.Module.IMG_ROOT
814
Module.IMG_ROOT = null;
817
* Constant representing the prefix path to use for securely served images
818
* @property YAHOO.widget.Module.IMG_ROOT_SSL
823
Module.IMG_ROOT_SSL = null;
826
* Constant for the default CSS class name that represents a Module
827
* @property YAHOO.widget.Module.CSS_MODULE
832
Module.CSS_MODULE = "yui-module";
835
* Constant representing the module header
836
* @property YAHOO.widget.Module.CSS_HEADER
841
Module.CSS_HEADER = "hd";
844
* Constant representing the module body
845
* @property YAHOO.widget.Module.CSS_BODY
850
Module.CSS_BODY = "bd";
853
* Constant representing the module footer
854
* @property YAHOO.widget.Module.CSS_FOOTER
859
Module.CSS_FOOTER = "ft";
862
* Constant representing the url for the "src" attribute of the iframe
863
* used to monitor changes to the browser's base font size
864
* @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
869
Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
872
* Constant representing the buffer amount (in pixels) to use when positioning
873
* the text resize monitor offscreen. The resize monitor is positioned
874
* offscreen by an amount eqaul to its offsetHeight + the buffer value.
876
* @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
880
// Set to 1, to work around pixel offset in IE8, which increases when zoom is used
881
Module.RESIZE_MONITOR_BUFFER = 1;
884
* Singleton CustomEvent fired when the font size is changed in the browser.
885
* Opera's "zoom" functionality currently does not support text
887
* @event YAHOO.widget.Module.textResizeEvent
889
Module.textResizeEvent = new CustomEvent("textResize");
892
* Helper utility method, which forces a document level
893
* redraw for Opera, which can help remove repaint
894
* irregularities after applying DOM changes.
896
* @method YAHOO.widget.Module.forceDocumentRedraw
899
Module.forceDocumentRedraw = function() {
900
var docEl = document.documentElement;
902
docEl.className += " ";
903
docEl.className = YAHOO.lang.trim(docEl.className);
907
function createModuleTemplate() {
909
if (!m_oModuleTemplate) {
910
m_oModuleTemplate = document.createElement("div");
912
m_oModuleTemplate.innerHTML = ("<div class=\"" +
913
Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
914
Module.CSS_BODY + "\"></div><div class=\"" +
915
Module.CSS_FOOTER + "\"></div>");
917
m_oHeaderTemplate = m_oModuleTemplate.firstChild;
918
m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
919
m_oFooterTemplate = m_oBodyTemplate.nextSibling;
922
return m_oModuleTemplate;
925
function createHeader() {
926
if (!m_oHeaderTemplate) {
927
createModuleTemplate();
929
return (m_oHeaderTemplate.cloneNode(false));
932
function createBody() {
933
if (!m_oBodyTemplate) {
934
createModuleTemplate();
936
return (m_oBodyTemplate.cloneNode(false));
939
function createFooter() {
940
if (!m_oFooterTemplate) {
941
createModuleTemplate();
943
return (m_oFooterTemplate.cloneNode(false));
949
* The class's constructor function
950
* @property contructor
956
* The main module element that contains the header, body, and footer
963
* The header element, denoted with CSS class "hd"
970
* The body element, denoted with CSS class "bd"
977
* The footer element, denoted with CSS class "ft"
984
* The id of the element
991
* A string representing the root path for all images created by
993
* @deprecated It is recommend that any images for a Module be applied
994
* via CSS using the "background-image" property.
995
* @property imageRoot
998
imageRoot: Module.IMG_ROOT,
1001
* Initializes the custom events for Module which are fired
1002
* automatically at appropriate times by the Module class.
1003
* @method initEvents
1005
initEvents: function () {
1007
var SIGNATURE = CustomEvent.LIST;
1010
* CustomEvent fired prior to class initalization.
1011
* @event beforeInitEvent
1012
* @param {class} classRef class reference of the initializing
1013
* class, such as this.beforeInitEvent.fire(Module)
1015
this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1016
this.beforeInitEvent.signature = SIGNATURE;
1019
* CustomEvent fired after class initalization.
1021
* @param {class} classRef class reference of the initializing
1022
* class, such as this.beforeInitEvent.fire(Module)
1024
this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1025
this.initEvent.signature = SIGNATURE;
1028
* CustomEvent fired when the Module is appended to the DOM
1029
* @event appendEvent
1031
this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1032
this.appendEvent.signature = SIGNATURE;
1035
* CustomEvent fired before the Module is rendered
1036
* @event beforeRenderEvent
1038
this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1039
this.beforeRenderEvent.signature = SIGNATURE;
1042
* CustomEvent fired after the Module is rendered
1043
* @event renderEvent
1045
this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1046
this.renderEvent.signature = SIGNATURE;
1049
* CustomEvent fired when the header content of the Module
1051
* @event changeHeaderEvent
1052
* @param {String/HTMLElement} content String/element representing
1053
* the new header content
1055
this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1056
this.changeHeaderEvent.signature = SIGNATURE;
1059
* CustomEvent fired when the body content of the Module is modified
1060
* @event changeBodyEvent
1061
* @param {String/HTMLElement} content String/element representing
1062
* the new body content
1064
this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1065
this.changeBodyEvent.signature = SIGNATURE;
1068
* CustomEvent fired when the footer content of the Module
1070
* @event changeFooterEvent
1071
* @param {String/HTMLElement} content String/element representing
1072
* the new footer content
1074
this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1075
this.changeFooterEvent.signature = SIGNATURE;
1078
* CustomEvent fired when the content of the Module is modified
1079
* @event changeContentEvent
1081
this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1082
this.changeContentEvent.signature = SIGNATURE;
1085
* CustomEvent fired when the Module is destroyed
1086
* @event destroyEvent
1088
this.destroyEvent = this.createEvent(EVENT_TYPES.DESTORY);
1089
this.destroyEvent.signature = SIGNATURE;
1092
* CustomEvent fired before the Module is shown
1093
* @event beforeShowEvent
1095
this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1096
this.beforeShowEvent.signature = SIGNATURE;
1099
* CustomEvent fired after the Module is shown
1102
this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1103
this.showEvent.signature = SIGNATURE;
1106
* CustomEvent fired before the Module is hidden
1107
* @event beforeHideEvent
1109
this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1110
this.beforeHideEvent.signature = SIGNATURE;
1113
* CustomEvent fired after the Module is hidden
1116
this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1117
this.hideEvent.signature = SIGNATURE;
1121
* String representing the current user-agent platform
1122
* @property platform
1125
platform: function () {
1126
var ua = navigator.userAgent.toLowerCase();
1128
if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1130
} else if (ua.indexOf("macintosh") != -1) {
1138
* String representing the user-agent of the browser
1139
* @deprecated Use YAHOO.env.ua
1143
browser: function () {
1144
var ua = navigator.userAgent.toLowerCase();
1146
Check Opera first in case of spoof and check Safari before
1147
Gecko since Safari's user agent string includes "like Gecko"
1149
if (ua.indexOf('opera') != -1) {
1151
} else if (ua.indexOf('msie 7') != -1) {
1153
} else if (ua.indexOf('msie') != -1) {
1155
} else if (ua.indexOf('safari') != -1) {
1157
} else if (ua.indexOf('gecko') != -1) {
1165
* Boolean representing whether or not the current browsing context is
1167
* @property isSecure
1170
isSecure: function () {
1171
if (window.location.href.toLowerCase().indexOf("https") === 0) {
1179
* Initializes the custom events for Module which are fired
1180
* automatically at appropriate times by the Module class.
1182
initDefaultConfig: function () {
1183
// Add properties //
1185
* Specifies whether the Module is visible on the page.
1190
this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1191
handler: this.configVisible,
1192
value: DEFAULT_CONFIG.VISIBLE.value,
1193
validator: DEFAULT_CONFIG.VISIBLE.validator
1198
* Object or array of objects representing the ContainerEffect
1199
* classes that are active for animating the container.
1202
* <strong>NOTE:</strong> Although this configuration
1203
* property is introduced at the Module level, an out of the box
1204
* implementation is not shipped for the Module class so setting
1205
* the proroperty on the Module class has no effect. The Overlay
1206
* class is the first class to provide out of the box ContainerEffect
1213
this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1214
suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1215
supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1219
* Specifies whether to create a special proxy iframe to monitor
1220
* for user font resizing in the document
1221
* @config monitorresize
1225
this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1226
handler: this.configMonitorResize,
1227
value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1231
* Specifies if the module should be rendered as the first child
1232
* of document.body or appended as the last child when render is called
1233
* with document.body as the "appendToNode".
1235
* Appending to the body while the DOM is still being constructed can
1236
* lead to Operation Aborted errors in IE hence this flag is set to
1240
* @config appendtodocumentbody
1244
this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1245
value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1250
* The Module class's initialization method, which is executed for
1251
* Module and all of its subclasses. This method is automatically
1252
* called by the constructor, and sets up all DOM references for
1253
* pre-existing markup, and creates required markup if it is not
1256
* If the element passed in does not have an id, one will be generated
1260
* @param {String} el The element ID representing the Module <em>OR</em>
1261
* @param {HTMLElement} el The element representing the Module
1262
* @param {Object} userConfig The configuration Object literal
1263
* containing the configuration that should be set for this module.
1264
* See configuration documentation for more details.
1266
init: function (el, userConfig) {
1271
this.beforeInitEvent.fire(Module);
1274
* The Module's Config object used for monitoring
1275
* configuration properties.
1277
* @type YAHOO.util.Config
1279
this.cfg = new Config(this);
1281
if (this.isSecure) {
1282
this.imageRoot = Module.IMG_ROOT_SSL;
1285
if (typeof el == "string") {
1287
el = document.getElementById(el);
1289
el = (createModuleTemplate()).cloneNode(false);
1294
this.id = Dom.generateId(el);
1297
child = this.element.firstChild;
1300
var fndHd = false, fndBd = false, fndFt = false;
1302
// We're looking for elements
1303
if (1 == child.nodeType) {
1304
if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1305
this.header = child;
1307
} else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1310
} else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1311
this.footer = child;
1315
} while ((child = child.nextSibling));
1318
this.initDefaultConfig();
1320
Dom.addClass(this.element, Module.CSS_MODULE);
1323
this.cfg.applyConfig(userConfig, true);
1327
Subscribe to the fireQueue() method of Config so that any
1328
queued configuration changes are excecuted upon render of
1332
if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1333
this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1336
this.initEvent.fire(Module);
1340
* Initialize an empty IFRAME that is placed out of the visible area
1341
* that can be used to detect text resize.
1342
* @method initResizeMonitor
1344
initResizeMonitor: function () {
1346
var isGeckoWin = (UA.gecko && this.platform == "windows");
1348
// Help prevent spinning loading icon which
1349
// started with FireFox 2.0.0.8/Win
1351
setTimeout(function(){self._initResizeMonitor();}, 0);
1353
this._initResizeMonitor();
1358
* Create and initialize the text resize monitoring iframe.
1361
* @method _initResizeMonitor
1363
_initResizeMonitor : function() {
1369
function fireTextResize() {
1370
Module.textResizeEvent.fire();
1374
oIFrame = Dom.get("_yuiResizeMonitor");
1376
var supportsCWResize = this._supportsCWResize();
1379
oIFrame = document.createElement("iframe");
1381
if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1382
oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1385
if (!supportsCWResize) {
1386
// Can't monitor on contentWindow, so fire from inside iframe
1387
sHTML = ["<html><head><script ",
1388
"type=\"text/javascript\">",
1389
"window.onresize=function(){window.parent.",
1390
"YAHOO.widget.Module.textResizeEvent.",
1393
"<body></body></html>"].join('');
1395
oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1398
oIFrame.id = "_yuiResizeMonitor";
1399
oIFrame.title = "Text Resize Monitor";
1401
Need to set "position" property before inserting the
1402
iframe into the document or Safari's status bar will
1403
forever indicate the iframe is loading
1404
(See SourceForge bug #1723064)
1406
oIFrame.style.position = "absolute";
1407
oIFrame.style.visibility = "hidden";
1409
var db = document.body,
1412
db.insertBefore(oIFrame, fc);
1414
db.appendChild(oIFrame);
1417
oIFrame.style.width = "2em";
1418
oIFrame.style.height = "2em";
1419
oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1420
oIFrame.style.left = "0";
1421
oIFrame.style.borderWidth = "0";
1422
oIFrame.style.visibility = "visible";
1425
Don't open/close the document for Gecko like we used to, since it
1426
leads to duplicate cookies. (See SourceForge bug #1721755)
1429
oDoc = oIFrame.contentWindow.document;
1435
if (oIFrame && oIFrame.contentWindow) {
1436
Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1438
if (!Module.textResizeInitialized) {
1439
if (supportsCWResize) {
1440
if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1442
This will fail in IE if document.domain has
1443
changed, so we must change the listener to
1444
use the oIFrame element instead
1446
Event.on(oIFrame, "resize", fireTextResize);
1449
Module.textResizeInitialized = true;
1451
this.resizeMonitor = oIFrame;
1457
* Text resize monitor helper method.
1458
* Determines if the browser supports resize events on iframe content windows.
1461
* @method _supportsCWResize
1463
_supportsCWResize : function() {
1465
Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1466
Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1468
We don't want to start sniffing for patch versions, so fire textResize the same
1469
way on all FF2 flavors
1471
var bSupported = true;
1472
if (UA.gecko && UA.gecko <= 1.8) {
1479
* Event handler fired when the resize monitor element is resized.
1480
* @method onDomResize
1481
* @param {DOMEvent} e The DOM resize event
1482
* @param {Object} obj The scope object passed to the handler
1484
onDomResize: function (e, obj) {
1486
var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1488
this.resizeMonitor.style.top = nTop + "px";
1489
this.resizeMonitor.style.left = "0";
1493
* Sets the Module's header content to the string specified, or appends
1494
* the passed element to the header. If no header is present, one will
1495
* be automatically created. An empty string can be passed to the method
1496
* to clear the contents of the header.
1499
* @param {String} headerContent The string used to set the header.
1500
* As a convenience, non HTMLElement objects can also be passed into
1501
* the method, and will be treated as strings, with the header innerHTML
1502
* set to their default toString implementations.
1504
* @param {HTMLElement} headerContent The HTMLElement to append to
1506
* @param {DocumentFragment} headerContent The document fragment
1507
* containing elements which are to be added to the header
1509
setHeader: function (headerContent) {
1510
var oHeader = this.header || (this.header = createHeader());
1512
if (headerContent.nodeName) {
1513
oHeader.innerHTML = "";
1514
oHeader.appendChild(headerContent);
1516
oHeader.innerHTML = headerContent;
1519
this.changeHeaderEvent.fire(headerContent);
1520
this.changeContentEvent.fire();
1525
* Appends the passed element to the header. If no header is present,
1526
* one will be automatically created.
1527
* @method appendToHeader
1528
* @param {HTMLElement | DocumentFragment} element The element to
1529
* append to the header. In the case of a document fragment, the
1530
* children of the fragment will be appended to the header.
1532
appendToHeader: function (element) {
1533
var oHeader = this.header || (this.header = createHeader());
1535
oHeader.appendChild(element);
1537
this.changeHeaderEvent.fire(element);
1538
this.changeContentEvent.fire();
1543
* Sets the Module's body content to the HTML specified.
1545
* If no body is present, one will be automatically created.
1547
* An empty string can be passed to the method to clear the contents of the body.
1549
* @param {String} bodyContent The HTML used to set the body.
1550
* As a convenience, non HTMLElement objects can also be passed into
1551
* the method, and will be treated as strings, with the body innerHTML
1552
* set to their default toString implementations.
1554
* @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1555
* child of the body element.
1557
* @param {DocumentFragment} bodyContent The document fragment
1558
* containing elements which are to be added to the body
1560
setBody: function (bodyContent) {
1561
var oBody = this.body || (this.body = createBody());
1563
if (bodyContent.nodeName) {
1564
oBody.innerHTML = "";
1565
oBody.appendChild(bodyContent);
1567
oBody.innerHTML = bodyContent;
1570
this.changeBodyEvent.fire(bodyContent);
1571
this.changeContentEvent.fire();
1575
* Appends the passed element to the body. If no body is present, one
1576
* will be automatically created.
1577
* @method appendToBody
1578
* @param {HTMLElement | DocumentFragment} element The element to
1579
* append to the body. In the case of a document fragment, the
1580
* children of the fragment will be appended to the body.
1583
appendToBody: function (element) {
1584
var oBody = this.body || (this.body = createBody());
1586
oBody.appendChild(element);
1588
this.changeBodyEvent.fire(element);
1589
this.changeContentEvent.fire();
1594
* Sets the Module's footer content to the HTML specified, or appends
1595
* the passed element to the footer. If no footer is present, one will
1596
* be automatically created. An empty string can be passed to the method
1597
* to clear the contents of the footer.
1599
* @param {String} footerContent The HTML used to set the footer
1600
* As a convenience, non HTMLElement objects can also be passed into
1601
* the method, and will be treated as strings, with the footer innerHTML
1602
* set to their default toString implementations.
1604
* @param {HTMLElement} footerContent The HTMLElement to append to
1607
* @param {DocumentFragment} footerContent The document fragment containing
1608
* elements which are to be added to the footer
1610
setFooter: function (footerContent) {
1612
var oFooter = this.footer || (this.footer = createFooter());
1614
if (footerContent.nodeName) {
1615
oFooter.innerHTML = "";
1616
oFooter.appendChild(footerContent);
1618
oFooter.innerHTML = footerContent;
1621
this.changeFooterEvent.fire(footerContent);
1622
this.changeContentEvent.fire();
1626
* Appends the passed element to the footer. If no footer is present,
1627
* one will be automatically created.
1628
* @method appendToFooter
1629
* @param {HTMLElement | DocumentFragment} element The element to
1630
* append to the footer. In the case of a document fragment, the
1631
* children of the fragment will be appended to the footer
1633
appendToFooter: function (element) {
1635
var oFooter = this.footer || (this.footer = createFooter());
1637
oFooter.appendChild(element);
1639
this.changeFooterEvent.fire(element);
1640
this.changeContentEvent.fire();
1645
* Renders the Module by inserting the elements that are not already
1646
* in the main Module into their correct places. Optionally appends
1647
* the Module to the specified node prior to the render's execution.
1649
* For Modules without existing markup, the appendToNode argument
1650
* is REQUIRED. If this argument is ommitted and the current element is
1651
* not present in the document, the function will return false,
1652
* indicating that the render was a failure.
1655
* NOTE: As of 2.3.1, if the appendToNode is the document's body element
1656
* then the module is rendered as the first child of the body element,
1657
* and not appended to it, to avoid Operation Aborted errors in IE when
1658
* rendering the module before window's load event is fired. You can
1659
* use the appendtodocumentbody configuration property to change this
1660
* to append to document.body if required.
1663
* @param {String} appendToNode The element id to which the Module
1664
* should be appended to prior to rendering <em>OR</em>
1665
* @param {HTMLElement} appendToNode The element to which the Module
1666
* should be appended to prior to rendering
1667
* @param {HTMLElement} moduleElement OPTIONAL. The element that
1668
* represents the actual Standard Module container.
1669
* @return {Boolean} Success or failure of the render
1671
render: function (appendToNode, moduleElement) {
1676
function appendTo(parentNode) {
1677
if (typeof parentNode == "string") {
1678
parentNode = document.getElementById(parentNode);
1682
me._addToParent(parentNode, me.element);
1683
me.appendEvent.fire();
1687
this.beforeRenderEvent.fire();
1689
if (! moduleElement) {
1690
moduleElement = this.element;
1694
appendTo(appendToNode);
1696
// No node was passed in. If the element is not already in the Dom, this fails
1697
if (! Dom.inDocument(this.element)) {
1698
YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
1703
// Need to get everything into the DOM if it isn't already
1704
if (this.header && ! Dom.inDocument(this.header)) {
1705
// There is a header, but it's not in the DOM yet. Need to add it.
1706
firstChild = moduleElement.firstChild;
1708
moduleElement.insertBefore(this.header, firstChild);
1710
moduleElement.appendChild(this.header);
1714
if (this.body && ! Dom.inDocument(this.body)) {
1715
// There is a body, but it's not in the DOM yet. Need to add it.
1716
if (this.footer && Dom.isAncestor(this.moduleElement, this.footer)) {
1717
moduleElement.insertBefore(this.body, this.footer);
1719
moduleElement.appendChild(this.body);
1723
if (this.footer && ! Dom.inDocument(this.footer)) {
1724
// There is a footer, but it's not in the DOM yet. Need to add it.
1725
moduleElement.appendChild(this.footer);
1728
this.renderEvent.fire();
1733
* Removes the Module element from the DOM and sets all child elements
1737
destroy: function () {
1742
Event.purgeElement(this.element, true);
1743
parent = this.element.parentNode;
1747
parent.removeChild(this.element);
1750
this.element = null;
1755
Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1760
this.destroyEvent.fire();
1764
* Shows the Module element by setting the visible configuration
1765
* property to true. Also fires two events: beforeShowEvent prior to
1766
* the visibility change, and showEvent after.
1770
this.cfg.setProperty("visible", true);
1774
* Hides the Module element by setting the visible configuration
1775
* property to false. Also fires two events: beforeHideEvent prior to
1776
* the visibility change, and hideEvent after.
1780
this.cfg.setProperty("visible", false);
1783
// BUILT-IN EVENT HANDLERS FOR MODULE //
1785
* Default event handler for changing the visibility property of a
1786
* Module. By default, this is achieved by switching the "display" style
1787
* between "block" and "none".
1788
* This method is responsible for firing showEvent and hideEvent.
1789
* @param {String} type The CustomEvent type (usually the property name)
1790
* @param {Object[]} args The CustomEvent arguments. For configuration
1791
* handlers, args[0] will equal the newly applied value for the property.
1792
* @param {Object} obj The scope object. For configuration handlers,
1793
* this will usually equal the owner.
1794
* @method configVisible
1796
configVisible: function (type, args, obj) {
1797
var visible = args[0];
1799
this.beforeShowEvent.fire();
1800
Dom.setStyle(this.element, "display", "block");
1801
this.showEvent.fire();
1803
this.beforeHideEvent.fire();
1804
Dom.setStyle(this.element, "display", "none");
1805
this.hideEvent.fire();
1810
* Default event handler for the "monitorresize" configuration property
1811
* @param {String} type The CustomEvent type (usually the property name)
1812
* @param {Object[]} args The CustomEvent arguments. For configuration
1813
* handlers, args[0] will equal the newly applied value for the property.
1814
* @param {Object} obj The scope object. For configuration handlers,
1815
* this will usually equal the owner.
1816
* @method configMonitorResize
1818
configMonitorResize: function (type, args, obj) {
1819
var monitor = args[0];
1821
this.initResizeMonitor();
1823
Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1824
this.resizeMonitor = null;
1829
* This method is a protected helper, used when constructing the DOM structure for the module
1830
* to account for situations which may cause Operation Aborted errors in IE. It should not
1831
* be used for general DOM construction.
1833
* If the parentNode is not document.body, the element is appended as the last element.
1836
* If the parentNode is document.body the element is added as the first child to help
1837
* prevent Operation Aborted errors in IE.
1840
* @param {parentNode} The HTML element to which the element will be added
1841
* @param {element} The HTML element to be added to parentNode's children
1842
* @method _addToParent
1845
_addToParent: function(parentNode, element) {
1846
if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1847
parentNode.insertBefore(element, parentNode.firstChild);
1849
parentNode.appendChild(element);
1854
* Returns a String representation of the Object.
1856
* @return {String} The string representation of the Module
1858
toString: function () {
1859
return "Module " + this.id;
1863
YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1870
* Overlay is a Module that is absolutely positioned above the page flow. It
1871
* has convenience methods for positioning and sizing, as well as options for
1872
* controlling zIndex and constraining the Overlay's position to the current
1873
* visible viewport. Overlay also contains a dynamicly generated IFRAME which
1874
* is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1875
* properly rendered above SELECT elements.
1876
* @namespace YAHOO.widget
1878
* @extends YAHOO.widget.Module
1879
* @param {String} el The element ID representing the Overlay <em>OR</em>
1880
* @param {HTMLElement} el The element representing the Overlay
1881
* @param {Object} userConfig The configuration object literal containing
1882
* the configuration that should be set for this Overlay. See configuration
1883
* documentation for more details.
1886
YAHOO.widget.Overlay = function (el, userConfig) {
1887
YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
1890
var Lang = YAHOO.lang,
1891
CustomEvent = YAHOO.util.CustomEvent,
1892
Module = YAHOO.widget.Module,
1893
Event = YAHOO.util.Event,
1894
Dom = YAHOO.util.Dom,
1895
Config = YAHOO.util.Config,
1897
Overlay = YAHOO.widget.Overlay,
1899
_SUBSCRIBE = "subscribe",
1900
_UNSUBSCRIBE = "unsubscribe",
1901
_CONTAINED = "contained",
1906
* Constant representing the name of the Overlay's events
1907
* @property EVENT_TYPES
1913
"BEFORE_MOVE": "beforeMove",
1918
* Constant representing the Overlay's configuration properties
1919
* @property DEFAULT_CONFIG
1928
validator: Lang.isNumber,
1929
suppressEvent: true,
1930
supercedes: ["iframe"]
1935
validator: Lang.isNumber,
1936
suppressEvent: true,
1937
supercedes: ["iframe"]
1942
suppressEvent: true,
1943
supercedes: ["iframe"]
1948
suppressEvent: true,
1949
supercedes: ["iframe"]
1955
supercedes: ["iframe", "visible"]
1960
suppressEvent: true,
1961
supercedes: ["context", "fixedcenter", "iframe"]
1966
suppressEvent: true,
1967
supercedes: ["context", "fixedcenter", "iframe"]
1970
"AUTO_FILL_HEIGHT" : {
1971
key: "autofillheight",
1972
supercedes: ["height"],
1981
"CONSTRAIN_TO_VIEWPORT": {
1982
key: "constraintoviewport",
1984
validator: Lang.isBoolean,
1985
supercedes: ["iframe", "x", "y", "xy"]
1990
value: (UA.ie == 6 ? true : false),
1991
validator: Lang.isBoolean,
1992
supercedes: ["zindex"]
1995
"PREVENT_CONTEXT_OVERLAP": {
1996
key: "preventcontextoverlap",
1998
validator: Lang.isBoolean,
1999
supercedes: ["constraintoviewport"]
2005
* The URL that will be placed in the iframe
2006
* @property YAHOO.widget.Overlay.IFRAME_SRC
2011
Overlay.IFRAME_SRC = "javascript:false;";
2014
* Number representing how much the iframe shim should be offset from each
2015
* side of an Overlay instance, in pixels.
2016
* @property YAHOO.widget.Overlay.IFRAME_SRC
2022
Overlay.IFRAME_OFFSET = 3;
2025
* Number representing the minimum distance an Overlay instance should be
2026
* positioned relative to the boundaries of the browser's viewport, in pixels.
2027
* @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2033
Overlay.VIEWPORT_OFFSET = 10;
2036
* Constant representing the top left corner of an element, used for
2037
* configuring the context element alignment
2038
* @property YAHOO.widget.Overlay.TOP_LEFT
2043
Overlay.TOP_LEFT = "tl";
2046
* Constant representing the top right corner of an element, used for
2047
* configuring the context element alignment
2048
* @property YAHOO.widget.Overlay.TOP_RIGHT
2053
Overlay.TOP_RIGHT = "tr";
2056
* Constant representing the top bottom left corner of an element, used for
2057
* configuring the context element alignment
2058
* @property YAHOO.widget.Overlay.BOTTOM_LEFT
2063
Overlay.BOTTOM_LEFT = "bl";
2066
* Constant representing the bottom right corner of an element, used for
2067
* configuring the context element alignment
2068
* @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2073
Overlay.BOTTOM_RIGHT = "br";
2076
* Constant representing the default CSS class used for an Overlay
2077
* @property YAHOO.widget.Overlay.CSS_OVERLAY
2082
Overlay.CSS_OVERLAY = "yui-overlay";
2085
* Constant representing the names of the standard module elements
2086
* used in the overlay.
2087
* @property YAHOO.widget.Overlay.STD_MOD_RE
2092
Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2095
* A singleton CustomEvent used for reacting to the DOM event for
2097
* @event YAHOO.widget.Overlay.windowScrollEvent
2099
Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2102
* A singleton CustomEvent used for reacting to the DOM event for
2104
* @event YAHOO.widget.Overlay.windowResizeEvent
2106
Overlay.windowResizeEvent = new CustomEvent("windowResize");
2109
* The DOM event handler used to fire the CustomEvent for window scroll
2110
* @method YAHOO.widget.Overlay.windowScrollHandler
2112
* @param {DOMEvent} e The DOM scroll event
2114
Overlay.windowScrollHandler = function (e) {
2115
var t = Event.getTarget(e);
2117
// - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2118
// - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2119
// - IE doesn't recognize scroll registered on the document.
2121
// Also, when document view is scrolled, IE doesn't provide a target,
2122
// rest of the browsers set target to window.document, apart from opera
2123
// which sets target to window.
2124
if (!t || t === window || t === window.document) {
2127
if (! window.scrollEnd) {
2128
window.scrollEnd = -1;
2131
clearTimeout(window.scrollEnd);
2133
window.scrollEnd = setTimeout(function () {
2134
Overlay.windowScrollEvent.fire();
2138
Overlay.windowScrollEvent.fire();
2144
* The DOM event handler used to fire the CustomEvent for window resize
2145
* @method YAHOO.widget.Overlay.windowResizeHandler
2147
* @param {DOMEvent} e The DOM resize event
2149
Overlay.windowResizeHandler = function (e) {
2152
if (! window.resizeEnd) {
2153
window.resizeEnd = -1;
2156
clearTimeout(window.resizeEnd);
2158
window.resizeEnd = setTimeout(function () {
2159
Overlay.windowResizeEvent.fire();
2162
Overlay.windowResizeEvent.fire();
2167
* A boolean that indicated whether the window resize and scroll events have
2168
* already been subscribed to.
2169
* @property YAHOO.widget.Overlay._initialized
2173
Overlay._initialized = null;
2175
if (Overlay._initialized === null) {
2176
Event.on(window, "scroll", Overlay.windowScrollHandler);
2177
Event.on(window, "resize", Overlay.windowResizeHandler);
2178
Overlay._initialized = true;
2182
* Internal map of special event types, which are provided
2183
* by the instance. It maps the event type to the custom event
2184
* instance. Contains entries for the "windowScroll", "windowResize" and
2185
* "textResize" static container events.
2187
* @property YAHOO.widget.Overlay._TRIGGER_MAP
2192
Overlay._TRIGGER_MAP = {
2193
"windowScroll" : Overlay.windowScrollEvent,
2194
"windowResize" : Overlay.windowResizeEvent,
2195
"textResize" : Module.textResizeEvent
2198
YAHOO.extend(Overlay, Module, {
2202
* Array of default event types which will trigger
2203
* context alignment for the Overlay class.
2205
* <p>The array is empty by default for Overlay,
2206
* but maybe populated in future releases, so classes extending
2207
* Overlay which need to define their own set of CONTEXT_TRIGGERS
2208
* should concatenate their super class's prototype.CONTEXT_TRIGGERS
2209
* value with their own array of values.
2213
* <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2216
* @property CONTEXT_TRIGGERS
2220
CONTEXT_TRIGGERS : [],
2223
* The Overlay initialization method, which is executed for Overlay and
2224
* all of its subclasses. This method is automatically called by the
2225
* constructor, and sets up all DOM references for pre-existing markup,
2226
* and creates required markup if it is not already present.
2228
* @param {String} el The element ID representing the Overlay <em>OR</em>
2229
* @param {HTMLElement} el The element representing the Overlay
2230
* @param {Object} userConfig The configuration object literal
2231
* containing the configuration that should be set for this Overlay.
2232
* See configuration documentation for more details.
2234
init: function (el, userConfig) {
2237
Note that we don't pass the user config in here yet because we
2238
only want it executed once, at the lowest subclass level
2241
Overlay.superclass.init.call(this, el/*, userConfig*/);
2243
this.beforeInitEvent.fire(Overlay);
2245
Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2248
this.cfg.applyConfig(userConfig, true);
2251
if (this.platform == "mac" && UA.gecko) {
2253
if (! Config.alreadySubscribed(this.showEvent,
2254
this.showMacGeckoScrollbars, this)) {
2256
this.showEvent.subscribe(this.showMacGeckoScrollbars,
2261
if (! Config.alreadySubscribed(this.hideEvent,
2262
this.hideMacGeckoScrollbars, this)) {
2264
this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2270
this.initEvent.fire(Overlay);
2274
* Initializes the custom events for Overlay which are fired
2275
* automatically at appropriate times by the Overlay class.
2276
* @method initEvents
2278
initEvents: function () {
2280
Overlay.superclass.initEvents.call(this);
2282
var SIGNATURE = CustomEvent.LIST;
2285
* CustomEvent fired before the Overlay is moved.
2286
* @event beforeMoveEvent
2287
* @param {Number} x x coordinate
2288
* @param {Number} y y coordinate
2290
this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2291
this.beforeMoveEvent.signature = SIGNATURE;
2294
* CustomEvent fired after the Overlay is moved.
2296
* @param {Number} x x coordinate
2297
* @param {Number} y y coordinate
2299
this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2300
this.moveEvent.signature = SIGNATURE;
2305
* Initializes the class's configurable properties which can be changed
2306
* using the Overlay's Config object (cfg).
2307
* @method initDefaultConfig
2309
initDefaultConfig: function () {
2311
Overlay.superclass.initDefaultConfig.call(this);
2315
// Add overlay config properties //
2318
* The absolute x-coordinate position of the Overlay
2323
cfg.addProperty(DEFAULT_CONFIG.X.key, {
2325
handler: this.configX,
2326
validator: DEFAULT_CONFIG.X.validator,
2327
suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2328
supercedes: DEFAULT_CONFIG.X.supercedes
2333
* The absolute y-coordinate position of the Overlay
2338
cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2340
handler: this.configY,
2341
validator: DEFAULT_CONFIG.Y.validator,
2342
suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2343
supercedes: DEFAULT_CONFIG.Y.supercedes
2348
* An array with the absolute x and y positions of the Overlay
2353
cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2354
handler: this.configXY,
2355
suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2356
supercedes: DEFAULT_CONFIG.XY.supercedes
2361
* The array of context arguments for context-sensitive positioning.
2365
* The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional)]</code>, the
2366
* the 4 array elements described in detail below:
2370
* <dt>contextElementOrId <String|HTMLElement></dt>
2371
* <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2372
* <dt>overlayCorner <String></dt>
2373
* <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2374
* corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2375
* "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2376
* <dt>contextCorner <String></dt>
2377
* <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>
2378
* <dt>arrayOfTriggerEvents (optional) <Array[String|CustomEvent]></dt>
2381
* 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>
2382
* 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.
2383
* This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2386
* The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2387
* 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).
2393
* For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2394
* align the Overlay's top left corner to the bottom left corner of the
2395
* context element with id "img1".
2398
* Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"]]</code>,
2399
* will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2406
cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2407
handler: this.configContext,
2408
suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2409
supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2413
* Determines whether or not the Overlay should be anchored
2414
* to the center of the viewport.
2416
* <p>This property can be set to:</p>
2421
* To enable fixed center positioning
2423
* When enabled, the overlay will
2424
* be positioned in the center of viewport when initially displayed, and
2425
* will remain in the center of the viewport whenever the window is
2426
* scrolled or resized.
2429
* If the overlay is too big for the viewport,
2430
* it's top left corner will be aligned with the top left corner of the viewport.
2435
* To disable fixed center positioning.
2436
* <p>In this case the overlay can still be
2437
* centered as a one-off operation, by invoking the <code>center()</code> method,
2438
* however it will not remain centered when the window is scrolled/resized.
2440
* <dt>"contained"<dt>
2441
* <dd>To enable fixed center positioning, as with the <code>true</code> option.
2442
* <p>However, unlike setting the property to <code>true</code>,
2443
* when the property is set to <code>"contained"</code>, if the overlay is
2444
* too big for the viewport, it will not get automatically centered when the
2445
* user scrolls or resizes the window (until the window is large enough to contain the
2446
* overlay). This is useful in cases where the Overlay has both header and footer
2447
* UI controls which the user may need to access.
2452
* @config fixedcenter
2453
* @type Boolean | String
2456
cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2457
handler: this.configFixedCenter,
2458
value: DEFAULT_CONFIG.FIXED_CENTER.value,
2459
validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2460
supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2464
* CSS width of the Overlay.
2469
cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2470
handler: this.configWidth,
2471
suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2472
supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2476
* CSS height of the Overlay.
2481
cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2482
handler: this.configHeight,
2483
suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2484
supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2488
* Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2489
* Supported values are "header", "body", "footer".
2491
* @config autofillheight
2495
cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2496
handler: this.configAutoFillHeight,
2497
value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2498
validator : this._validateAutoFill,
2499
supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2503
* CSS z-index of the Overlay.
2508
cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2509
handler: this.configzIndex,
2510
value: DEFAULT_CONFIG.ZINDEX.value
2514
* True if the Overlay should be prevented from being positioned
2515
* out of the viewport.
2516
* @config constraintoviewport
2520
cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2522
handler: this.configConstrainToViewport,
2523
value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2524
validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2525
supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2531
* @description Boolean indicating whether or not the Overlay should
2532
* have an IFRAME shim; used to prevent SELECT elements from
2533
* poking through an Overlay instance in IE6. When set to "true",
2534
* the iframe shim is created when the Overlay instance is intially
2537
* @default true for IE6 and below, false for all other browsers.
2539
cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2541
handler: this.configIframe,
2542
value: DEFAULT_CONFIG.IFRAME.value,
2543
validator: DEFAULT_CONFIG.IFRAME.validator,
2544
supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2549
* @config preventcontextoverlap
2550
* @description Boolean indicating whether or not the Overlay should overlap its
2551
* context element (defined using the "context" configuration property) when the
2552
* "constraintoviewport" configuration property is set to "true".
2556
cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2558
value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2559
validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2560
supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2567
* Moves the Overlay to the specified position. This function is
2568
* identical to calling this.cfg.setProperty("xy", [x,y]);
2570
* @param {Number} x The Overlay's new x position
2571
* @param {Number} y The Overlay's new y position
2573
moveTo: function (x, y) {
2574
this.cfg.setProperty("xy", [x, y]);
2578
* Adds a CSS class ("hide-scrollbars") and removes a CSS class
2579
* ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2580
* (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2581
* @method hideMacGeckoScrollbars
2583
hideMacGeckoScrollbars: function () {
2584
Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2588
* Adds a CSS class ("show-scrollbars") and removes a CSS class
2589
* ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2590
* (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2591
* @method showMacGeckoScrollbars
2593
showMacGeckoScrollbars: function () {
2594
Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2598
* Internal implementation to set the visibility of the overlay in the DOM.
2600
* @method _setDomVisibility
2601
* @param {boolean} visible Whether to show or hide the Overlay's outer element
2604
_setDomVisibility : function(show) {
2605
Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2608
Dom.removeClass(this.element, "yui-overlay-hidden");
2610
Dom.addClass(this.element, "yui-overlay-hidden");
2614
// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2616
* The default event handler fired when the "visible" property is
2617
* changed. This method is responsible for firing showEvent
2619
* @method configVisible
2620
* @param {String} type The CustomEvent type (usually the property name)
2621
* @param {Object[]} args The CustomEvent arguments. For configuration
2622
* handlers, args[0] will equal the newly applied value for the property.
2623
* @param {Object} obj The scope object. For configuration handlers,
2624
* this will usually equal the owner.
2626
configVisible: function (type, args, obj) {
2628
var visible = args[0],
2629
currentVis = Dom.getStyle(this.element, "visibility"),
2630
effect = this.cfg.getProperty("effect"),
2631
effectInstances = [],
2632
isMacGecko = (this.platform == "mac" && UA.gecko),
2633
alreadySubscribed = Config.alreadySubscribed,
2634
eff, ei, e, i, j, k, h,
2638
if (currentVis == "inherit") {
2639
e = this.element.parentNode;
2641
while (e.nodeType != 9 && e.nodeType != 11) {
2642
currentVis = Dom.getStyle(e, "visibility");
2644
if (currentVis != "inherit") {
2651
if (currentVis == "inherit") {
2652
currentVis = "visible";
2657
if (effect instanceof Array) {
2658
nEffects = effect.length;
2660
for (i = 0; i < nEffects; i++) {
2662
effectInstances[effectInstances.length] =
2663
eff.effect(this, eff.duration);
2667
effectInstances[effectInstances.length] =
2668
effect.effect(this, effect.duration);
2672
if (visible) { // Show
2674
this.showMacGeckoScrollbars();
2677
if (effect) { // Animate in
2678
if (visible) { // Animate in if not showing
2679
if (currentVis != "visible" || currentVis === "") {
2680
this.beforeShowEvent.fire();
2681
nEffectInstances = effectInstances.length;
2683
for (j = 0; j < nEffectInstances; j++) {
2684
ei = effectInstances[j];
2685
if (j === 0 && !alreadySubscribed(
2686
ei.animateInCompleteEvent,
2687
this.showEvent.fire, this.showEvent)) {
2690
Delegate showEvent until end
2691
of animateInComplete
2694
ei.animateInCompleteEvent.subscribe(
2695
this.showEvent.fire, this.showEvent, true);
2702
if (currentVis != "visible" || currentVis === "") {
2703
this.beforeShowEvent.fire();
2705
this._setDomVisibility(true);
2707
this.cfg.refireEvent("iframe");
2708
this.showEvent.fire();
2710
this._setDomVisibility(true);
2716
this.hideMacGeckoScrollbars();
2719
if (effect) { // Animate out if showing
2720
if (currentVis == "visible") {
2721
this.beforeHideEvent.fire();
2723
nEffectInstances = effectInstances.length;
2724
for (k = 0; k < nEffectInstances; k++) {
2725
h = effectInstances[k];
2727
if (k === 0 && !alreadySubscribed(
2728
h.animateOutCompleteEvent, this.hideEvent.fire,
2732
Delegate hideEvent until end
2733
of animateOutComplete
2736
h.animateOutCompleteEvent.subscribe(
2737
this.hideEvent.fire, this.hideEvent, true);
2743
} else if (currentVis === "") {
2744
this._setDomVisibility(false);
2747
} else { // Simple hide
2749
if (currentVis == "visible" || currentVis === "") {
2750
this.beforeHideEvent.fire();
2751
this._setDomVisibility(false);
2752
this.hideEvent.fire();
2754
this._setDomVisibility(false);
2761
* Fixed center event handler used for centering on scroll/resize, but only if
2762
* the overlay is visible and, if "fixedcenter" is set to "contained", only if
2763
* the overlay fits within the viewport.
2765
* @method doCenterOnDOMEvent
2767
doCenterOnDOMEvent: function () {
2769
fc = cfg.getProperty("fixedcenter");
2771
if (cfg.getProperty("visible")) {
2772
if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2779
* Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2780
* will fit entirely inside the viewport, in both dimensions - width and height.
2782
* @method fitsInViewport
2783
* @return boolean true if the Overlay will fit, false if not
2785
fitsInViewport : function() {
2786
var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2787
element = this.element,
2788
elementWidth = element.offsetWidth,
2789
elementHeight = element.offsetHeight,
2790
viewportWidth = Dom.getViewportWidth(),
2791
viewportHeight = Dom.getViewportHeight();
2793
return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2797
* The default event handler fired when the "fixedcenter" property
2799
* @method configFixedCenter
2800
* @param {String} type The CustomEvent type (usually the property name)
2801
* @param {Object[]} args The CustomEvent arguments. For configuration
2802
* handlers, args[0] will equal the newly applied value for the property.
2803
* @param {Object} obj The scope object. For configuration handlers,
2804
* this will usually equal the owner.
2806
configFixedCenter: function (type, args, obj) {
2809
alreadySubscribed = Config.alreadySubscribed,
2810
windowResizeEvent = Overlay.windowResizeEvent,
2811
windowScrollEvent = Overlay.windowScrollEvent;
2816
if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2817
this.beforeShowEvent.subscribe(this.center);
2820
if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2821
windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2824
if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2825
windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2829
this.beforeShowEvent.unsubscribe(this.center);
2831
windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2832
windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2837
* The default event handler fired when the "height" property is changed.
2838
* @method configHeight
2839
* @param {String} type The CustomEvent type (usually the property name)
2840
* @param {Object[]} args The CustomEvent arguments. For configuration
2841
* handlers, args[0] will equal the newly applied value for the property.
2842
* @param {Object} obj The scope object. For configuration handlers,
2843
* this will usually equal the owner.
2845
configHeight: function (type, args, obj) {
2847
var height = args[0],
2850
Dom.setStyle(el, "height", height);
2851
this.cfg.refireEvent("iframe");
2855
* The default event handler fired when the "autofillheight" property is changed.
2856
* @method configAutoFillHeight
2858
* @param {String} type The CustomEvent type (usually the property name)
2859
* @param {Object[]} args The CustomEvent arguments. For configuration
2860
* handlers, args[0] will equal the newly applied value for the property.
2861
* @param {Object} obj The scope object. For configuration handlers,
2862
* this will usually equal the owner.
2864
configAutoFillHeight: function (type, args, obj) {
2865
var fillEl = args[0],
2867
autoFillHeight = "autofillheight",
2869
currEl = cfg.getProperty(autoFillHeight),
2870
autoFill = this._autoFillOnHeightChange;
2872
cfg.unsubscribeFromConfigEvent(height, autoFill);
2873
Module.textResizeEvent.unsubscribe(autoFill);
2874
this.changeContentEvent.unsubscribe(autoFill);
2876
if (currEl && fillEl !== currEl && this[currEl]) {
2877
Dom.setStyle(this[currEl], height, "");
2881
fillEl = Lang.trim(fillEl.toLowerCase());
2883
cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
2884
Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
2885
this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
2887
cfg.setProperty(autoFillHeight, fillEl, true);
2892
* The default event handler fired when the "width" property is changed.
2893
* @method configWidth
2894
* @param {String} type The CustomEvent type (usually the property name)
2895
* @param {Object[]} args The CustomEvent arguments. For configuration
2896
* handlers, args[0] will equal the newly applied value for the property.
2897
* @param {Object} obj The scope object. For configuration handlers,
2898
* this will usually equal the owner.
2900
configWidth: function (type, args, obj) {
2902
var width = args[0],
2905
Dom.setStyle(el, "width", width);
2906
this.cfg.refireEvent("iframe");
2910
* The default event handler fired when the "zIndex" property is changed.
2911
* @method configzIndex
2912
* @param {String} type The CustomEvent type (usually the property name)
2913
* @param {Object[]} args The CustomEvent arguments. For configuration
2914
* handlers, args[0] will equal the newly applied value for the property.
2915
* @param {Object} obj The scope object. For configuration handlers,
2916
* this will usually equal the owner.
2918
configzIndex: function (type, args, obj) {
2920
var zIndex = args[0],
2924
zIndex = Dom.getStyle(el, "zIndex");
2925
if (! zIndex || isNaN(zIndex)) {
2930
if (this.iframe || this.cfg.getProperty("iframe") === true) {
2936
Dom.setStyle(el, "zIndex", zIndex);
2937
this.cfg.setProperty("zIndex", zIndex, true);
2945
* The default event handler fired when the "xy" property is changed.
2947
* @param {String} type The CustomEvent type (usually the property name)
2948
* @param {Object[]} args The CustomEvent arguments. For configuration
2949
* handlers, args[0] will equal the newly applied value for the property.
2950
* @param {Object} obj The scope object. For configuration handlers,
2951
* this will usually equal the owner.
2953
configXY: function (type, args, obj) {
2959
this.cfg.setProperty("x", x);
2960
this.cfg.setProperty("y", y);
2962
this.beforeMoveEvent.fire([x, y]);
2964
x = this.cfg.getProperty("x");
2965
y = this.cfg.getProperty("y");
2967
YAHOO.log(("xy: " + [x, y]), "iframe");
2969
this.cfg.refireEvent("iframe");
2970
this.moveEvent.fire([x, y]);
2974
* The default event handler fired when the "x" property is changed.
2976
* @param {String} type The CustomEvent type (usually the property name)
2977
* @param {Object[]} args The CustomEvent arguments. For configuration
2978
* handlers, args[0] will equal the newly applied value for the property.
2979
* @param {Object} obj The scope object. For configuration handlers,
2980
* this will usually equal the owner.
2982
configX: function (type, args, obj) {
2985
y = this.cfg.getProperty("y");
2987
this.cfg.setProperty("x", x, true);
2988
this.cfg.setProperty("y", y, true);
2990
this.beforeMoveEvent.fire([x, y]);
2992
x = this.cfg.getProperty("x");
2993
y = this.cfg.getProperty("y");
2995
Dom.setX(this.element, x, true);
2997
this.cfg.setProperty("xy", [x, y], true);
2999
this.cfg.refireEvent("iframe");
3000
this.moveEvent.fire([x, y]);
3004
* The default event handler fired when the "y" property is changed.
3006
* @param {String} type The CustomEvent type (usually the property name)
3007
* @param {Object[]} args The CustomEvent arguments. For configuration
3008
* handlers, args[0] will equal the newly applied value for the property.
3009
* @param {Object} obj The scope object. For configuration handlers,
3010
* this will usually equal the owner.
3012
configY: function (type, args, obj) {
3014
var x = this.cfg.getProperty("x"),
3017
this.cfg.setProperty("x", x, true);
3018
this.cfg.setProperty("y", y, true);
3020
this.beforeMoveEvent.fire([x, y]);
3022
x = this.cfg.getProperty("x");
3023
y = this.cfg.getProperty("y");
3025
Dom.setY(this.element, y, true);
3027
this.cfg.setProperty("xy", [x, y], true);
3029
this.cfg.refireEvent("iframe");
3030
this.moveEvent.fire([x, y]);
3034
* Shows the iframe shim, if it has been enabled.
3035
* @method showIframe
3037
showIframe: function () {
3039
var oIFrame = this.iframe,
3043
oParentNode = this.element.parentNode;
3045
if (oParentNode != oIFrame.parentNode) {
3046
this._addToParent(oParentNode, oIFrame);
3048
oIFrame.style.display = "block";
3053
* Hides the iframe shim, if it has been enabled.
3054
* @method hideIframe
3056
hideIframe: function () {
3058
this.iframe.style.display = "none";
3063
* Syncronizes the size and position of iframe shim to that of its
3064
* corresponding Overlay instance.
3065
* @method syncIframe
3067
syncIframe: function () {
3069
var oIFrame = this.iframe,
3070
oElement = this.element,
3071
nOffset = Overlay.IFRAME_OFFSET,
3072
nDimensionOffset = (nOffset * 2),
3077
oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3078
oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3080
// Position <iframe>
3081
aXY = this.cfg.getProperty("xy");
3083
if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3084
this.syncPosition();
3085
aXY = this.cfg.getProperty("xy");
3087
Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3092
* Sets the zindex of the iframe shim, if it exists, based on the zindex of
3093
* the Overlay element. The zindex of the iframe is set to be one less
3094
* than the Overlay element's zindex.
3096
* <p>NOTE: This method will not bump up the zindex of the Overlay element
3097
* to ensure that the iframe shim has a non-negative zindex.
3098
* If you require the iframe zindex to be 0 or higher, the zindex of
3099
* the Overlay element should be set to a value greater than 0, before
3100
* this method is called.
3102
* @method stackIframe
3104
stackIframe: function () {
3106
var overlayZ = Dom.getStyle(this.element, "zIndex");
3107
if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3108
Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3114
* The default event handler fired when the "iframe" property is changed.
3115
* @method configIframe
3116
* @param {String} type The CustomEvent type (usually the property name)
3117
* @param {Object[]} args The CustomEvent arguments. For configuration
3118
* handlers, args[0] will equal the newly applied value for the property.
3119
* @param {Object} obj The scope object. For configuration handlers,
3120
* this will usually equal the owner.
3122
configIframe: function (type, args, obj) {
3124
var bIFrame = args[0];
3126
function createIFrame() {
3128
var oIFrame = this.iframe,
3129
oElement = this.element,
3133
if (!m_oIFrameTemplate) {
3134
m_oIFrameTemplate = document.createElement("iframe");
3136
if (this.isSecure) {
3137
m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3141
Set the opacity of the <iframe> to 0 so that it
3142
doesn't modify the opacity of any transparent
3143
elements that may be on top of it (like a shadow).
3146
m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3148
Need to set the "frameBorder" property to 0
3149
supress the default <iframe> border in IE.
3150
Setting the CSS "border" property alone
3153
m_oIFrameTemplate.frameBorder = 0;
3156
m_oIFrameTemplate.style.opacity = "0";
3159
m_oIFrameTemplate.style.position = "absolute";
3160
m_oIFrameTemplate.style.border = "none";
3161
m_oIFrameTemplate.style.margin = "0";
3162
m_oIFrameTemplate.style.padding = "0";
3163
m_oIFrameTemplate.style.display = "none";
3164
m_oIFrameTemplate.tabIndex = -1;
3167
oIFrame = m_oIFrameTemplate.cloneNode(false);
3168
oParent = oElement.parentNode;
3170
var parentNode = oParent || document.body;
3172
this._addToParent(parentNode, oIFrame);
3173
this.iframe = oIFrame;
3177
Show the <iframe> before positioning it since the "setXY"
3178
method of DOM requires the element be in the document
3184
Syncronize the size and position of the <iframe> to that
3190
// Add event listeners to update the <iframe> when necessary
3191
if (!this._hasIframeEventListeners) {
3192
this.showEvent.subscribe(this.showIframe);
3193
this.hideEvent.subscribe(this.hideIframe);
3194
this.changeContentEvent.subscribe(this.syncIframe);
3196
this._hasIframeEventListeners = true;
3200
function onBeforeShow() {
3201
createIFrame.call(this);
3202
this.beforeShowEvent.unsubscribe(onBeforeShow);
3203
this._iframeDeferred = false;
3206
if (bIFrame) { // <iframe> shim is enabled
3208
if (this.cfg.getProperty("visible")) {
3209
createIFrame.call(this);
3211
if (!this._iframeDeferred) {
3212
this.beforeShowEvent.subscribe(onBeforeShow);
3213
this._iframeDeferred = true;
3217
} else { // <iframe> shim is disabled
3220
if (this._hasIframeEventListeners) {
3221
this.showEvent.unsubscribe(this.showIframe);
3222
this.hideEvent.unsubscribe(this.hideIframe);
3223
this.changeContentEvent.unsubscribe(this.syncIframe);
3225
this._hasIframeEventListeners = false;
3231
* Set's the container's XY value from DOM if not already set.
3233
* Differs from syncPosition, in that the XY value is only sync'd with DOM if
3234
* not already set. The method also refire's the XY config property event, so any
3235
* beforeMove, Move event listeners are invoked.
3237
* @method _primeXYFromDOM
3240
_primeXYFromDOM : function() {
3241
if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3242
// Set CFG XY based on DOM XY
3243
this.syncPosition();
3244
// Account for XY being set silently in syncPosition (no moveTo fired/called)
3245
this.cfg.refireEvent("xy");
3246
this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3251
* The default event handler fired when the "constraintoviewport"
3252
* property is changed.
3253
* @method configConstrainToViewport
3254
* @param {String} type The CustomEvent type (usually the property name)
3255
* @param {Object[]} args The CustomEvent arguments. For configuration
3256
* handlers, args[0] will equal the newly applied value for
3258
* @param {Object} obj The scope object. For configuration handlers,
3259
* this will usually equal the owner.
3261
configConstrainToViewport: function (type, args, obj) {
3265
if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3266
this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3268
if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3269
this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3272
this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3273
this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3278
* The default event handler fired when the "context" property
3281
* @method configContext
3282
* @param {String} type The CustomEvent type (usually the property name)
3283
* @param {Object[]} args The CustomEvent arguments. For configuration
3284
* handlers, args[0] will equal the newly applied value for the property.
3285
* @param {Object} obj The scope object. For configuration handlers,
3286
* this will usually equal the owner.
3288
configContext: function (type, args, obj) {
3290
var contextArgs = args[0],
3292
elementMagnetCorner,
3293
contextMagnetCorner,
3295
defTriggers = this.CONTEXT_TRIGGERS;
3299
contextEl = contextArgs[0];
3300
elementMagnetCorner = contextArgs[1];
3301
contextMagnetCorner = contextArgs[2];
3302
triggers = contextArgs[3];
3304
if (defTriggers && defTriggers.length > 0) {
3305
triggers = (triggers || []).concat(defTriggers);
3309
if (typeof contextEl == "string") {
3310
this.cfg.setProperty("context", [
3311
document.getElementById(contextEl),
3312
elementMagnetCorner,
3313
contextMagnetCorner,
3318
if (elementMagnetCorner && contextMagnetCorner) {
3319
this.align(elementMagnetCorner, contextMagnetCorner);
3322
if (this._contextTriggers) {
3323
// Unsubscribe Old Set
3324
this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3328
// Subscribe New Set
3329
this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3330
this._contextTriggers = triggers;
3337
* Custom Event handler for context alignment triggers. Invokes the align method
3339
* @method _alignOnTrigger
3342
* @param {String} type The event type (not used by the default implementation)
3343
* @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3345
_alignOnTrigger: function(type, args) {
3350
* Helper method to locate the custom event instance for the event name string
3351
* passed in. As a convenience measure, any custom events passed in are returned.
3353
* @method _findTriggerCE
3356
* @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3357
* custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3359
_findTriggerCE : function(t) {
3361
if (t instanceof CustomEvent) {
3363
} else if (Overlay._TRIGGER_MAP[t]) {
3364
tce = Overlay._TRIGGER_MAP[t];
3370
* Utility method that subscribes or unsubscribes the given
3371
* function from the list of trigger events provided.
3373
* @method _processTriggers
3376
* @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3377
* (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3378
* subscribed/unsubscribed respectively.
3380
* @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3381
* we are subscribing or unsubscribing trigger listeners
3383
* @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3384
* Context is always set to the overlay instance, and no additional object argument
3385
* get passed to the subscribed function.
3387
_processTriggers : function(triggers, mode, fn) {
3390
for (var i = 0, l = triggers.length; i < l; ++i) {
3392
tce = this._findTriggerCE(t);
3394
tce[mode](fn, this, true);
3401
// END BUILT-IN PROPERTY EVENT HANDLERS //
3403
* Aligns the Overlay to its context element using the specified corner
3404
* points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3407
* @param {String} elementAlign The String representing the corner of
3408
* the Overlay that should be aligned to the context element
3409
* @param {String} contextAlign The corner of the context element
3410
* that the elementAlign corner should stick to.
3412
align: function (elementAlign, contextAlign) {
3414
var contextArgs = this.cfg.getProperty("context"),
3420
function doAlign(v, h) {
3422
switch (elementAlign) {
3424
case Overlay.TOP_LEFT:
3428
case Overlay.TOP_RIGHT:
3429
me.moveTo((h - element.offsetWidth), v);
3432
case Overlay.BOTTOM_LEFT:
3433
me.moveTo(h, (v - element.offsetHeight));
3436
case Overlay.BOTTOM_RIGHT:
3437
me.moveTo((h - element.offsetWidth),
3438
(v - element.offsetHeight));
3446
context = contextArgs[0];
3447
element = this.element;
3450
if (! elementAlign) {
3451
elementAlign = contextArgs[1];
3454
if (! contextAlign) {
3455
contextAlign = contextArgs[2];
3458
if (element && context) {
3459
contextRegion = Dom.getRegion(context);
3461
switch (contextAlign) {
3463
case Overlay.TOP_LEFT:
3464
doAlign(contextRegion.top, contextRegion.left);
3467
case Overlay.TOP_RIGHT:
3468
doAlign(contextRegion.top, contextRegion.right);
3471
case Overlay.BOTTOM_LEFT:
3472
doAlign(contextRegion.bottom, contextRegion.left);
3475
case Overlay.BOTTOM_RIGHT:
3476
doAlign(contextRegion.bottom, contextRegion.right);
3487
* The default event handler executed when the moveEvent is fired, if the
3488
* "constraintoviewport" is set to true.
3489
* @method enforceConstraints
3490
* @param {String} type The CustomEvent type (usually the property name)
3491
* @param {Object[]} args The CustomEvent arguments. For configuration
3492
* handlers, args[0] will equal the newly applied value for the property.
3493
* @param {Object} obj The scope object. For configuration handlers,
3494
* this will usually equal the owner.
3496
enforceConstraints: function (type, args, obj) {
3499
var cXY = this.getConstrainedXY(pos[0], pos[1]);
3500
this.cfg.setProperty("x", cXY[0], true);
3501
this.cfg.setProperty("y", cXY[1], true);
3502
this.cfg.setProperty("xy", cXY, true);
3507
* Given x coordinate value, returns the calculated x coordinate required to
3508
* position the Overlay if it is to be constrained to the viewport, based on the
3509
* current element size, viewport dimensions and scroll values.
3511
* @param {Number} x The X coordinate value to be constrained
3512
* @return {Number} The constrained x coordinate
3514
getConstrainedX: function (x) {
3516
var oOverlay = this,
3517
oOverlayEl = oOverlay.element,
3518
nOverlayOffsetWidth = oOverlayEl.offsetWidth,
3520
nViewportOffset = Overlay.VIEWPORT_OFFSET,
3521
viewPortWidth = Dom.getViewportWidth(),
3522
scrollX = Dom.getDocumentScrollLeft(),
3524
bCanConstrain = (nOverlayOffsetWidth + nViewportOffset < viewPortWidth),
3526
aContext = this.cfg.getProperty("context"),
3536
leftConstraint = scrollX + nViewportOffset,
3537
rightConstraint = scrollX + viewPortWidth - nOverlayOffsetWidth - nViewportOffset,
3541
oOverlapPositions = {
3551
var flipHorizontal = function () {
3555
if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
3556
nNewX = (nContextElX - nOverlayOffsetWidth);
3559
nNewX = (nContextElX + nContextElWidth);
3563
oOverlay.cfg.setProperty("x", (nNewX + scrollX), true);
3572
Uses the context element's position to calculate the availble width
3573
to the right and left of it to display its corresponding Overlay.
3576
var getDisplayRegionWidth = function () {
3578
// The Overlay is to the right of the context element
3580
if ((oOverlay.cfg.getProperty("x") - scrollX) > nContextElX) {
3581
return (nRightRegionWidth - nViewportOffset);
3583
else { // The Overlay is to the left of the context element
3584
return (nLeftRegionWidth - nViewportOffset);
3591
Positions the Overlay to the left or right of the context element so that it remains
3592
inside the viewport.
3595
var setHorizontalPosition = function () {
3597
var nDisplayRegionWidth = getDisplayRegionWidth(),
3600
if (nOverlayOffsetWidth > nDisplayRegionWidth) {
3605
All possible positions and values have been
3606
tried, but none were successful, so fall back
3607
to the original size and position.
3619
fnReturnVal = setHorizontalPosition();
3629
// Determine if the current value for the Overlay's "x" configuration property will
3630
// result in the Overlay being positioned outside the boundaries of the viewport
3632
if (x < leftConstraint || x > rightConstraint) {
3634
// The current value for the Overlay's "x" configuration property WILL
3635
// result in the Overlay being positioned outside the boundaries of the viewport
3637
if (bCanConstrain) {
3639
// If the "preventcontextoverlap" configuration property is set to "true",
3640
// try to flip the Overlay to both keep it inside the boundaries of the
3641
// viewport AND from overlaping its context element.
3643
if (this.cfg.getProperty("preventcontextoverlap") && aContext &&
3644
oOverlapPositions[(aContext[1] + aContext[2])]) {
3646
oContextEl = aContext[0];
3647
nContextElX = Dom.getX(oContextEl) - scrollX;
3648
nContextElWidth = oContextEl.offsetWidth;
3649
nLeftRegionWidth = nContextElX;
3650
nRightRegionWidth = (viewPortWidth - (nContextElX + nContextElWidth));
3652
setHorizontalPosition();
3654
xNew = this.cfg.getProperty("x");
3659
if (x < leftConstraint) {
3660
xNew = leftConstraint;
3661
} else if (x > rightConstraint) {
3662
xNew = rightConstraint;
3668
// The "x" configuration property cannot be set to a value that will keep
3669
// entire Overlay inside the boundary of the viewport. Therefore, set
3670
// the "x" configuration property to scrollY to keep as much of the
3671
// Overlay inside the viewport as possible.
3672
xNew = nViewportOffset + scrollX;
3683
* Given y coordinate value, returns the calculated y coordinate required to
3684
* position the Overlay if it is to be constrained to the viewport, based on the
3685
* current element size, viewport dimensions and scroll values.
3687
* @param {Number} y The Y coordinate value to be constrained
3688
* @return {Number} The constrained y coordinate
3690
getConstrainedY: function (y) {
3692
var oOverlay = this,
3693
oOverlayEl = oOverlay.element,
3694
nOverlayOffsetHeight = oOverlayEl.offsetHeight,
3696
nViewportOffset = Overlay.VIEWPORT_OFFSET,
3697
viewPortHeight = Dom.getViewportHeight(),
3698
scrollY = Dom.getDocumentScrollTop(),
3700
bCanConstrain = (nOverlayOffsetHeight + nViewportOffset < viewPortHeight),
3702
aContext = this.cfg.getProperty("context"),
3710
nBottomRegionHeight,
3712
topConstraint = scrollY + nViewportOffset,
3713
bottomConstraint = scrollY + viewPortHeight - nOverlayOffsetHeight - nViewportOffset,
3717
oOverlapPositions = {
3725
var flipVertical = function () {
3729
// The Overlay is below the context element, flip it above
3730
if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
3731
nNewY = (nContextElY - nOverlayOffsetHeight);
3733
else { // The Overlay is above the context element, flip it below
3734
nNewY = (nContextElY + nContextElHeight);
3737
oOverlay.cfg.setProperty("y", (nNewY + scrollY), true);
3745
Uses the context element's position to calculate the availble height
3746
above and below it to display its corresponding Overlay.
3749
var getDisplayRegionHeight = function () {
3751
// The Overlay is below the context element
3752
if ((oOverlay.cfg.getProperty("y") - scrollY) > nContextElY) {
3753
return (nBottomRegionHeight - nViewportOffset);
3755
else { // The Overlay is above the context element
3756
return (nTopRegionHeight - nViewportOffset);
3763
Trys to place the Overlay in the best possible position (either above or
3764
below its corresponding context element).
3767
var setVerticalPosition = function () {
3769
var nDisplayRegionHeight = getDisplayRegionHeight(),
3773
if (nOverlayOffsetHeight > nDisplayRegionHeight) {
3778
All possible positions and values for the
3779
"maxheight" configuration property have been
3780
tried, but none were successful, so fall back
3781
to the original size and position.
3793
fnReturnVal = setVerticalPosition();
3804
// Determine if the current value for the Overlay's "y" configuration property will
3805
// result in the Overlay being positioned outside the boundaries of the viewport
3807
if (y < topConstraint || y > bottomConstraint) {
3809
// The current value for the Overlay's "y" configuration property WILL
3810
// result in the Overlay being positioned outside the boundaries of the viewport
3812
if (bCanConstrain) {
3814
// If the "preventcontextoverlap" configuration property is set to "true",
3815
// try to flip the Overlay to both keep it inside the boundaries of the
3816
// viewport AND from overlaping its context element.
3818
if (this.cfg.getProperty("preventcontextoverlap") && aContext &&
3819
oOverlapPositions[(aContext[1] + aContext[2])]) {
3821
oContextEl = aContext[0];
3822
nContextElHeight = oContextEl.offsetHeight;
3823
nContextElY = (Dom.getY(oContextEl) - scrollY);
3825
nTopRegionHeight = nContextElY;
3826
nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
3828
setVerticalPosition();
3830
yNew = oOverlay.cfg.getProperty("y");
3835
if (y < topConstraint) {
3836
yNew = topConstraint;
3837
} else if (y > bottomConstraint) {
3838
yNew = bottomConstraint;
3846
// The "y" configuration property cannot be set to a value that will keep
3847
// entire Overlay inside the boundary of the viewport. Therefore, set
3848
// the "y" configuration property to scrollY to keep as much of the
3849
// Overlay inside the viewport as possible.
3851
yNew = nViewportOffset + scrollY;
3861
* Given x, y coordinate values, returns the calculated coordinates required to
3862
* position the Overlay if it is to be constrained to the viewport, based on the
3863
* current element size, viewport dimensions and scroll values.
3865
* @param {Number} x The X coordinate value to be constrained
3866
* @param {Number} y The Y coordinate value to be constrained
3867
* @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3869
getConstrainedXY: function(x, y) {
3870
return [this.getConstrainedX(x), this.getConstrainedY(y)];
3874
* Centers the container in the viewport.
3877
center: function () {
3879
var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3880
elementWidth = this.element.offsetWidth,
3881
elementHeight = this.element.offsetHeight,
3882
viewPortWidth = Dom.getViewportWidth(),
3883
viewPortHeight = Dom.getViewportHeight(),
3887
if (elementWidth < viewPortWidth) {
3888
x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3890
x = nViewportOffset + Dom.getDocumentScrollLeft();
3893
if (elementHeight < viewPortHeight) {
3894
y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3896
y = nViewportOffset + Dom.getDocumentScrollTop();
3899
this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3900
this.cfg.refireEvent("iframe");
3903
this.forceContainerRedraw();
3908
* Synchronizes the Panel's "xy", "x", and "y" properties with the
3909
* Panel's position in the DOM. This is primarily used to update
3910
* position information during drag & drop.
3911
* @method syncPosition
3913
syncPosition: function () {
3915
var pos = Dom.getXY(this.element);
3917
this.cfg.setProperty("x", pos[0], true);
3918
this.cfg.setProperty("y", pos[1], true);
3919
this.cfg.setProperty("xy", pos, true);
3924
* Event handler fired when the resize monitor element is resized.
3925
* @method onDomResize
3926
* @param {DOMEvent} e The resize DOM event
3927
* @param {Object} obj The scope object
3929
onDomResize: function (e, obj) {
3933
Overlay.superclass.onDomResize.call(this, e, obj);
3935
setTimeout(function () {
3937
me.cfg.refireEvent("iframe");
3938
me.cfg.refireEvent("context");
3943
* Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3945
* @method _getComputedHeight
3947
* @param {HTMLElement} el The element for which the content height needs to be determined
3948
* @return {Number} The content box height of the given element, or null if it could not be determined.
3950
_getComputedHeight : (function() {
3952
if (document.defaultView && document.defaultView.getComputedStyle) {
3953
return function(el) {
3955
if (el.ownerDocument && el.ownerDocument.defaultView) {
3956
var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3958
height = parseInt(computed.height, 10);
3961
return (Lang.isNumber(height)) ? height : null;
3964
return function(el) {
3966
if (el.style.pixelHeight) {
3967
height = el.style.pixelHeight;
3969
return (Lang.isNumber(height)) ? height : null;
3975
* autofillheight validator. Verifies that the autofill value is either null
3976
* or one of the strings : "body", "header" or "footer".
3978
* @method _validateAutoFillHeight
3980
* @param {String} val
3981
* @return true, if valid, false otherwise
3983
_validateAutoFillHeight : function(val) {
3984
return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3988
* The default custom event handler executed when the overlay's height is changed,
3989
* if the autofillheight property has been set.
3991
* @method _autoFillOnHeightChange
3993
* @param {String} type The event type
3994
* @param {Array} args The array of arguments passed to event subscribers
3995
* @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3996
* out the containers height
3998
_autoFillOnHeightChange : function(type, args, el) {
3999
var height = this.cfg.getProperty("height");
4000
if ((height && height !== "auto") || (height === 0)) {
4001
this.fillHeight(el);
4006
* Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
4007
* otherwise returns the offsetHeight
4008
* @method _getPreciseHeight
4010
* @param {HTMLElement} el
4011
* @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
4013
_getPreciseHeight : function(el) {
4014
var height = el.offsetHeight;
4016
if (el.getBoundingClientRect) {
4017
var rect = el.getBoundingClientRect();
4018
height = rect.bottom - rect.top;
4026
* Sets the height on the provided header, body or footer element to
4027
* fill out the height of the container. It determines the height of the
4028
* containers content box, based on it's configured height value, and
4029
* sets the height of the autofillheight element to fill out any
4030
* space remaining after the other standard module element heights
4031
* have been accounted for.
4033
* <p><strong>NOTE:</strong> This method is not designed to work if an explicit
4034
* height has not been set on the container, since for an "auto" height container,
4035
* the heights of the header/body/footer will drive the height of the container.</p>
4037
* @method fillHeight
4038
* @param {HTMLElement} el The element which should be resized to fill out the height
4039
* of the container element.
4041
fillHeight : function(el) {
4043
var container = this.innerElement || this.element,
4044
containerEls = [this.header, this.body, this.footer],
4051
for (var i = 0, l = containerEls.length; i < l; i++) {
4052
containerEl = containerEls[i];
4054
if (el !== containerEl) {
4055
filled += this._getPreciseHeight(containerEl);
4064
if (UA.ie || UA.opera) {
4065
// Need to set height to 0, to allow height to be reduced
4066
Dom.setStyle(el, 'height', 0 + 'px');
4069
total = this._getComputedHeight(container);
4071
// Fallback, if we can't get computed value for content height
4072
if (total === null) {
4073
Dom.addClass(container, "yui-override-padding");
4074
total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4075
Dom.removeClass(container, "yui-override-padding");
4078
remaining = Math.max(total - filled, 0);
4080
Dom.setStyle(el, "height", remaining + "px");
4082
// Re-adjust height if required, to account for el padding and border
4083
if (el.offsetHeight != remaining) {
4084
remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4086
Dom.setStyle(el, "height", remaining + "px");
4092
* Places the Overlay on top of all other instances of
4093
* YAHOO.widget.Overlay.
4094
* @method bringToTop
4096
bringToTop: function () {
4099
oElement = this.element;
4101
function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4103
var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4104
sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4106
nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4107
nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4109
if (nZIndex1 > nZIndex2) {
4111
} else if (nZIndex1 < nZIndex2) {
4118
function isOverlayElement(p_oElement) {
4120
var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4121
Panel = YAHOO.widget.Panel;
4123
if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4124
if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4125
aOverlays[aOverlays.length] = p_oElement.parentNode;
4127
aOverlays[aOverlays.length] = p_oElement;
4132
Dom.getElementsBy(isOverlayElement, "DIV", document.body);
4134
aOverlays.sort(compareZIndexDesc);
4136
var oTopOverlay = aOverlays[0],
4140
nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4142
if (!isNaN(nTopZIndex)) {
4143
var bRequiresBump = false;
4145
if (oTopOverlay != oElement) {
4146
bRequiresBump = true;
4147
} else if (aOverlays.length > 1) {
4148
var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4149
// Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4150
if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4151
bRequiresBump = true;
4154
if (bRequiresBump) {
4155
this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4162
* Removes the Overlay element from the DOM and sets all child
4166
destroy: function () {
4169
this.iframe.parentNode.removeChild(this.iframe);
4174
Overlay.windowResizeEvent.unsubscribe(
4175
this.doCenterOnDOMEvent, this);
4177
Overlay.windowScrollEvent.unsubscribe(
4178
this.doCenterOnDOMEvent, this);
4180
Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4182
Overlay.superclass.destroy.call(this);
4186
* Can be used to force the container to repaint/redraw it's contents.
4188
* By default applies and then removes a 1px bottom margin through the
4189
* application/removal of a "yui-force-redraw" class.
4192
* It is currently used by Overlay to force a repaint for webkit
4193
* browsers, when centering.
4195
* @method forceContainerRedraw
4197
forceContainerRedraw : function() {
4199
Dom.addClass(c.element, "yui-force-redraw");
4200
setTimeout(function() {
4201
Dom.removeClass(c.element, "yui-force-redraw");
4206
* Returns a String representation of the object.
4208
* @return {String} The string representation of the Overlay.
4210
toString: function () {
4211
return "Overlay " + this.id;
4220
* OverlayManager is used for maintaining the focus status of
4221
* multiple Overlays.
4222
* @namespace YAHOO.widget
4223
* @namespace YAHOO.widget
4224
* @class OverlayManager
4226
* @param {Array} overlays Optional. A collection of Overlays to register
4228
* @param {Object} userConfig The object literal representing the user
4229
* configuration of the OverlayManager
4231
YAHOO.widget.OverlayManager = function (userConfig) {
4232
this.init(userConfig);
4235
var Overlay = YAHOO.widget.Overlay,
4236
Event = YAHOO.util.Event,
4237
Dom = YAHOO.util.Dom,
4238
Config = YAHOO.util.Config,
4239
CustomEvent = YAHOO.util.CustomEvent,
4240
OverlayManager = YAHOO.widget.OverlayManager;
4243
* The CSS class representing a focused Overlay
4244
* @property OverlayManager.CSS_FOCUSED
4249
OverlayManager.CSS_FOCUSED = "focused";
4251
OverlayManager.prototype = {
4254
* The class's constructor function
4255
* @property contructor
4258
constructor: OverlayManager,
4261
* The array of Overlays that are currently registered
4262
* @property overlays
4263
* @type YAHOO.widget.Overlay[]
4268
* Initializes the default configuration of the OverlayManager
4269
* @method initDefaultConfig
4271
initDefaultConfig: function () {
4273
* The collection of registered Overlays in use by
4274
* the OverlayManager
4276
* @type YAHOO.widget.Overlay[]
4279
this.cfg.addProperty("overlays", { suppressEvent: true } );
4282
* The default DOM event that should be used to focus an Overlay
4283
* @config focusevent
4285
* @default "mousedown"
4287
this.cfg.addProperty("focusevent", { value: "mousedown" } );
4291
* Initializes the OverlayManager
4293
* @param {Overlay[]} overlays Optional. A collection of Overlays to
4294
* register with the manager.
4295
* @param {Object} userConfig The object literal representing the user
4296
* configuration of the OverlayManager
4298
init: function (userConfig) {
4301
* The OverlayManager's Config object used for monitoring
4302
* configuration properties.
4306
this.cfg = new Config(this);
4308
this.initDefaultConfig();
4311
this.cfg.applyConfig(userConfig, true);
4313
this.cfg.fireQueue();
4316
* The currently activated Overlay
4317
* @property activeOverlay
4319
* @type YAHOO.widget.Overlay
4321
var activeOverlay = null;
4324
* Returns the currently focused Overlay
4326
* @return {Overlay} The currently focused Overlay
4328
this.getActive = function () {
4329
return activeOverlay;
4333
* Focuses the specified Overlay
4335
* @param {Overlay} overlay The Overlay to focus
4336
* @param {String} overlay The id of the Overlay to focus
4338
this.focus = function (overlay) {
4339
var o = this.find(overlay);
4346
* Removes the specified Overlay from the manager
4348
* @param {Overlay} overlay The Overlay to remove
4349
* @param {String} overlay The id of the Overlay to remove
4351
this.remove = function (overlay) {
4353
var o = this.find(overlay),
4357
if (activeOverlay == o) {
4358
activeOverlay = null;
4361
var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4364
// Set it's zindex so that it's sorted to the end.
4365
originalZ = Dom.getStyle(o.element, "zIndex");
4366
o.cfg.setProperty("zIndex", -1000, true);
4369
this.overlays.sort(this.compareZIndexDesc);
4370
this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4372
o.hideEvent.unsubscribe(o.blur);
4373
o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4374
o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4375
o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4378
Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4379
o.cfg.setProperty("zIndex", originalZ, true);
4380
o.cfg.setProperty("manager", null);
4383
/* _managed Flag for custom or existing. Don't want to remove existing */
4384
if (o.focusEvent._managed) { o.focusEvent = null; }
4385
if (o.blurEvent._managed) { o.blurEvent = null; }
4387
if (o.focus._managed) { o.focus = null; }
4388
if (o.blur._managed) { o.blur = null; }
4393
* Removes focus from all registered Overlays in the manager
4396
this.blurAll = function () {
4398
var nOverlays = this.overlays.length,
4401
if (nOverlays > 0) {
4404
this.overlays[i].blur();
4411
* Updates the state of the OverlayManager and overlay, as a result of the overlay
4414
* @method _manageBlur
4415
* @param {Overlay} overlay The overlay instance which got blurred.
4418
this._manageBlur = function (overlay) {
4419
var changed = false;
4420
if (activeOverlay == overlay) {
4421
Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4422
activeOverlay = null;
4429
* Updates the state of the OverlayManager and overlay, as a result of the overlay
4432
* @method _manageFocus
4433
* @param {Overlay} overlay The overlay instance which got focus.
4436
this._manageFocus = function(overlay) {
4437
var changed = false;
4438
if (activeOverlay != overlay) {
4439
if (activeOverlay) {
4440
activeOverlay.blur();
4442
activeOverlay = overlay;
4443
this.bringToTop(activeOverlay);
4444
Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4450
var overlays = this.cfg.getProperty("overlays");
4452
if (! this.overlays) {
4457
this.register(overlays);
4458
this.overlays.sort(this.compareZIndexDesc);
4463
* @method _onOverlayElementFocus
4464
* @description Event handler for the DOM event that is used to focus
4465
* the Overlay instance as specified by the "focusevent"
4466
* configuration property.
4468
* @param {Event} p_oEvent Object representing the DOM event
4469
* object passed back by the event utility (Event).
4471
_onOverlayElementFocus: function (p_oEvent) {
4473
var oTarget = Event.getTarget(p_oEvent),
4474
oClose = this.close;
4476
if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4484
* @method _onOverlayDestroy
4485
* @description "destroy" event handler for the Overlay.
4487
* @param {String} p_sType String representing the name of the event
4489
* @param {Array} p_aArgs Array of arguments sent when the event
4491
* @param {Overlay} p_oOverlay Object representing the overlay that
4494
_onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4495
this.remove(p_oOverlay);
4499
* @method _onOverlayFocusHandler
4501
* focusEvent Handler, used to delegate to _manageFocus with the
4502
* correct arguments.
4505
* @param {String} p_sType String representing the name of the event
4507
* @param {Array} p_aArgs Array of arguments sent when the event
4509
* @param {Overlay} p_oOverlay Object representing the overlay that
4512
_onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4513
this._manageFocus(p_oOverlay);
4517
* @method _onOverlayBlurHandler
4519
* blurEvent Handler, used to delegate to _manageBlur with the
4520
* correct arguments.
4523
* @param {String} p_sType String representing the name of the event
4525
* @param {Array} p_aArgs Array of arguments sent when the event
4527
* @param {Overlay} p_oOverlay Object representing the overlay that
4530
_onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4531
this._manageBlur(p_oOverlay);
4535
* Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4536
* monitor focus state.
4538
* If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4539
* to the existing focusEvent, however if a focusEvent or focus method does not exist
4540
* on the instance, the _bindFocus method will add them, and the focus method will
4541
* update the OverlayManager's state directly.
4543
* @method _bindFocus
4544
* @param {Overlay} overlay The overlay for which focus needs to be managed
4547
_bindFocus : function(overlay) {
4550
if (!overlay.focusEvent) {
4551
overlay.focusEvent = overlay.createEvent("focus");
4552
overlay.focusEvent.signature = CustomEvent.LIST;
4553
overlay.focusEvent._managed = true;
4555
overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4558
if (!overlay.focus) {
4559
Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4560
overlay.focus = function () {
4561
if (mgr._manageFocus(this)) {
4563
if (this.cfg.getProperty("visible") && this.focusFirst) {
4566
this.focusEvent.fire();
4569
overlay.focus._managed = true;
4574
* Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4575
* monitor blur state.
4577
* If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4578
* to the existing blurEvent, however if a blurEvent or blur method does not exist
4579
* on the instance, the _bindBlur method will add them, and the blur method
4580
* update the OverlayManager's state directly.
4583
* @param {Overlay} overlay The overlay for which blur needs to be managed
4586
_bindBlur : function(overlay) {
4589
if (!overlay.blurEvent) {
4590
overlay.blurEvent = overlay.createEvent("blur");
4591
overlay.blurEvent.signature = CustomEvent.LIST;
4592
overlay.focusEvent._managed = true;
4594
overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4597
if (!overlay.blur) {
4598
overlay.blur = function () {
4599
if (mgr._manageBlur(this)) {
4600
this.blurEvent.fire();
4603
overlay.blur._managed = true;
4606
overlay.hideEvent.subscribe(overlay.blur);
4610
* Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4611
* to be removed for the OverlayManager when destroyed.
4613
* @method _bindDestroy
4614
* @param {Overlay} overlay The overlay instance being managed
4617
_bindDestroy : function(overlay) {
4619
overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4623
* Ensures the zIndex configuration property on the managed overlay based instance
4624
* is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4626
* @method _syncZIndex
4627
* @param {Overlay} overlay The overlay instance being managed
4630
_syncZIndex : function(overlay) {
4631
var zIndex = Dom.getStyle(overlay.element, "zIndex");
4632
if (!isNaN(zIndex)) {
4633
overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4635
overlay.cfg.setProperty("zIndex", 0);
4640
* Registers an Overlay or an array of Overlays with the manager. Upon
4641
* registration, the Overlay receives functions for focus and blur,
4642
* along with CustomEvents for each.
4645
* @param {Overlay} overlay An Overlay to register with the manager.
4646
* @param {Overlay[]} overlay An array of Overlays to register with
4648
* @return {boolean} true if any Overlays are registered.
4650
register: function (overlay) {
4652
var registered = false,
4656
if (overlay instanceof Overlay) {
4658
overlay.cfg.addProperty("manager", { value: this } );
4660
this._bindFocus(overlay);
4661
this._bindBlur(overlay);
4662
this._bindDestroy(overlay);
4663
this._syncZIndex(overlay);
4665
this.overlays.push(overlay);
4666
this.bringToTop(overlay);
4670
} else if (overlay instanceof Array) {
4672
for (i = 0, n = overlay.length; i < n; i++) {
4673
registered = this.register(overlay[i]) || registered;
4682
* Places the specified Overlay instance on top of all other
4683
* Overlay instances.
4684
* @method bringToTop
4685
* @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4687
* @param {String} p_oOverlay String representing the id of an
4690
bringToTop: function (p_oOverlay) {
4692
var oOverlay = this.find(p_oOverlay),
4699
aOverlays = this.overlays;
4700
aOverlays.sort(this.compareZIndexDesc);
4702
oTopOverlay = aOverlays[0];
4705
nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4707
if (!isNaN(nTopZIndex)) {
4709
var bRequiresBump = false;
4711
if (oTopOverlay !== oOverlay) {
4712
bRequiresBump = true;
4713
} else if (aOverlays.length > 1) {
4714
var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4715
// Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4716
if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4717
bRequiresBump = true;
4721
if (bRequiresBump) {
4722
oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4725
aOverlays.sort(this.compareZIndexDesc);
4731
* Attempts to locate an Overlay by instance or ID.
4733
* @param {Overlay} overlay An Overlay to locate within the manager
4734
* @param {String} overlay An Overlay id to locate within the manager
4735
* @return {Overlay} The requested Overlay, if found, or null if it
4736
* cannot be located.
4738
find: function (overlay) {
4740
var isInstance = overlay instanceof Overlay,
4741
overlays = this.overlays,
4742
n = overlays.length,
4747
if (isInstance || typeof overlay == "string") {
4748
for (i = n-1; i >= 0; i--) {
4750
if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4761
* Used for sorting the manager's Overlays by z-index.
4762
* @method compareZIndexDesc
4764
* @return {Number} 0, 1, or -1, depending on where the Overlay should
4765
* fall in the stacking order.
4767
compareZIndexDesc: function (o1, o2) {
4769
var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4770
zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4772
if (zIndex1 === null && zIndex2 === null) {
4774
} else if (zIndex1 === null){
4776
} else if (zIndex2 === null) {
4778
} else if (zIndex1 > zIndex2) {
4780
} else if (zIndex1 < zIndex2) {
4788
* Shows all Overlays in the manager.
4791
showAll: function () {
4792
var overlays = this.overlays,
4793
n = overlays.length,
4796
for (i = n - 1; i >= 0; i--) {
4802
* Hides all Overlays in the manager.
4805
hideAll: function () {
4806
var overlays = this.overlays,
4807
n = overlays.length,
4810
for (i = n - 1; i >= 0; i--) {
4816
* Returns a string representation of the object.
4818
* @return {String} The string representation of the OverlayManager
4820
toString: function () {
4821
return "OverlayManager";
4829
* Tooltip is an implementation of Overlay that behaves like an OS tooltip,
4830
* displaying when the user mouses over a particular element, and
4831
* disappearing on mouse out.
4832
* @namespace YAHOO.widget
4834
* @extends YAHOO.widget.Overlay
4836
* @param {String} el The element ID representing the Tooltip <em>OR</em>
4837
* @param {HTMLElement} el The element representing the Tooltip
4838
* @param {Object} userConfig The configuration object literal containing
4839
* the configuration that should be set for this Overlay. See configuration
4840
* documentation for more details.
4842
YAHOO.widget.Tooltip = function (el, userConfig) {
4843
YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4846
var Lang = YAHOO.lang,
4847
Event = YAHOO.util.Event,
4848
CustomEvent = YAHOO.util.CustomEvent,
4849
Dom = YAHOO.util.Dom,
4850
Tooltip = YAHOO.widget.Tooltip,
4852
bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
4857
* Constant representing the Tooltip's configuration properties
4858
* @property DEFAULT_CONFIG
4865
"PREVENT_OVERLAP": {
4866
key: "preventoverlap",
4868
validator: Lang.isBoolean,
4869
supercedes: ["x", "y", "xy"]
4875
validator: Lang.isNumber
4878
"AUTO_DISMISS_DELAY": {
4879
key: "autodismissdelay",
4881
validator: Lang.isNumber
4887
validator: Lang.isNumber
4907
* Constant representing the name of the Tooltip's events
4908
* @property EVENT_TYPES
4914
"CONTEXT_MOUSE_OVER": "contextMouseOver",
4915
"CONTEXT_MOUSE_OUT": "contextMouseOut",
4916
"CONTEXT_TRIGGER": "contextTrigger"
4920
* Constant representing the Tooltip CSS class
4921
* @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4926
Tooltip.CSS_TOOLTIP = "yui-tt";
4928
function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
4930
var oConfig = this.cfg,
4931
sCurrentWidth = oConfig.getProperty("width");
4933
if (sCurrentWidth == sForcedWidth) {
4934
oConfig.setProperty("width", sOriginalWidth);
4939
changeContent event handler that sets a Tooltip instance's "width"
4940
configuration property to the value of its root HTML
4941
elements's offsetWidth if a specific width has not been set.
4944
function setWidthToOffsetWidth(p_sType, p_aArgs) {
4946
if ("_originalWidth" in this) {
4947
restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
4950
var oBody = document.body,
4952
sOriginalWidth = oConfig.getProperty("width"),
4956
if ((!sOriginalWidth || sOriginalWidth == "auto") &&
4957
(oConfig.getProperty("container") != oBody ||
4958
oConfig.getProperty("x") >= Dom.getViewportWidth() ||
4959
oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4961
oClone = this.element.cloneNode(true);
4962
oClone.style.visibility = "hidden";
4963
oClone.style.top = "0px";
4964
oClone.style.left = "0px";
4966
oBody.appendChild(oClone);
4968
sNewWidth = (oClone.offsetWidth + "px");
4970
oBody.removeChild(oClone);
4973
oConfig.setProperty("width", sNewWidth);
4974
oConfig.refireEvent("xy");
4976
this._originalWidth = sOriginalWidth || "";
4977
this._forcedWidth = sNewWidth;
4981
// "onDOMReady" that renders the ToolTip
4983
function onDOMReady(p_sType, p_aArgs, p_oObject) {
4984
this.render(p_oObject);
4987
// "init" event handler that automatically renders the Tooltip
4990
Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4993
YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
4996
* The Tooltip initialization method. This method is automatically
4997
* called by the constructor. A Tooltip is automatically rendered by
4998
* the init method, and it also is set to be invisible by default,
4999
* and constrained to viewport by default as well.
5001
* @param {String} el The element ID representing the Tooltip <em>OR</em>
5002
* @param {HTMLElement} el The element representing the Tooltip
5003
* @param {Object} userConfig The configuration object literal
5004
* containing the configuration that should be set for this Tooltip.
5005
* See configuration documentation for more details.
5007
init: function (el, userConfig) {
5009
this.logger = new YAHOO.widget.LogWriter(this.toString());
5011
Tooltip.superclass.init.call(this, el);
5013
this.beforeInitEvent.fire(Tooltip);
5015
Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
5018
this.cfg.applyConfig(userConfig, true);
5021
this.cfg.queueProperty("visible", false);
5022
this.cfg.queueProperty("constraintoviewport", true);
5026
this.subscribe("changeContent", setWidthToOffsetWidth);
5027
this.subscribe("init", onInit);
5028
this.subscribe("render", this.onRender);
5030
this.initEvent.fire(Tooltip);
5034
* Initializes the custom events for Tooltip
5035
* @method initEvents
5037
initEvents: function () {
5039
Tooltip.superclass.initEvents.call(this);
5040
var SIGNATURE = CustomEvent.LIST;
5043
* CustomEvent fired when user mouses over a context element. Returning false from
5044
* a subscriber to this event will prevent the tooltip from being displayed for
5045
* the current context element.
5047
* @event contextMouseOverEvent
5048
* @param {HTMLElement} context The context element which the user just moused over
5049
* @param {DOMEvent} e The DOM event object, associated with the mouse over
5051
this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
5052
this.contextMouseOverEvent.signature = SIGNATURE;
5055
* CustomEvent fired when the user mouses out of a context element.
5057
* @event contextMouseOutEvent
5058
* @param {HTMLElement} context The context element which the user just moused out of
5059
* @param {DOMEvent} e The DOM event object, associated with the mouse out
5061
this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
5062
this.contextMouseOutEvent.signature = SIGNATURE;
5065
* CustomEvent fired just before the tooltip is displayed for the current context.
5067
* You can subscribe to this event if you need to set up the text for the
5068
* tooltip based on the context element for which it is about to be displayed.
5070
* <p>This event differs from the beforeShow event in following respects:</p>
5073
* When moving from one context element to another, if the tooltip is not
5074
* hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
5075
* be fired when the tooltip is displayed for the new context since it is already visible.
5076
* However the contextTrigger event is always fired before displaying the tooltip for
5080
* The trigger event provides access to the context element, allowing you to
5081
* set the text of the tooltip based on context element for which the tooltip is
5086
* It is not possible to prevent the tooltip from being displayed
5087
* using this event. You can use the contextMouseOverEvent if you need to prevent
5088
* the tooltip from being displayed.
5090
* @event contextTriggerEvent
5091
* @param {HTMLElement} context The context element for which the tooltip is triggered
5093
this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
5094
this.contextTriggerEvent.signature = SIGNATURE;
5098
* Initializes the class's configurable properties which can be
5099
* changed using the Overlay's Config object (cfg).
5100
* @method initDefaultConfig
5102
initDefaultConfig: function () {
5104
Tooltip.superclass.initDefaultConfig.call(this);
5107
* Specifies whether the Tooltip should be kept from overlapping
5108
* its context element.
5109
* @config preventoverlap
5113
this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
5114
value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
5115
validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
5116
supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
5120
* The number of milliseconds to wait before showing a Tooltip
5126
this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
5127
handler: this.configShowDelay,
5129
validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5133
* The number of milliseconds to wait before automatically
5134
* dismissing a Tooltip after the mouse has been resting on the
5136
* @config autodismissdelay
5140
this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
5141
handler: this.configAutoDismissDelay,
5142
value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
5143
validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
5147
* The number of milliseconds to wait before hiding a Tooltip
5153
this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
5154
handler: this.configHideDelay,
5155
value: DEFAULT_CONFIG.HIDE_DELAY.value,
5156
validator: DEFAULT_CONFIG.HIDE_DELAY.validator
5160
* Specifies the Tooltip's text.
5165
this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
5166
handler: this.configText,
5167
suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
5171
* Specifies the container element that the Tooltip's markup
5172
* should be rendered into.
5174
* @type HTMLElement/String
5175
* @default document.body
5177
this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
5178
handler: this.configContainer,
5179
value: document.body
5183
* Specifies whether or not the tooltip is disabled. Disabled tooltips
5184
* will not be displayed. If the tooltip is driven by the title attribute
5185
* of the context element, the title attribute will still be removed for
5186
* disabled tooltips, to prevent default tooltip behavior.
5192
this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
5193
handler: this.configContainer,
5194
value: DEFAULT_CONFIG.DISABLED.value,
5195
supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5199
* Specifies the element or elements that the Tooltip should be
5200
* anchored to on mouseover.
5202
* @type HTMLElement[]/String[]
5207
* String representing the width of the Tooltip. <em>Please note:
5208
* </em> As of version 2.3 if either no value or a value of "auto"
5209
* is specified, and the Toolip's "container" configuration property
5210
* is set to something other than <code>document.body</code> or
5211
* its "context" element resides outside the immediately visible
5212
* portion of the document, the width of the Tooltip will be
5213
* calculated based on the offsetWidth of its root HTML and set just
5214
* before it is made visible. The original value will be
5215
* restored when the Tooltip is hidden. This ensures the Tooltip is
5216
* rendered at a usable width. For more information see
5217
* SourceForge bug #1685496 and SourceForge
5226
// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5229
* The default event handler fired when the "text" property is changed.
5230
* @method configText
5231
* @param {String} type The CustomEvent type (usually the property name)
5232
* @param {Object[]} args The CustomEvent arguments. For configuration
5233
* handlers, args[0] will equal the newly applied value for the property.
5234
* @param {Object} obj The scope object. For configuration handlers,
5235
* this will usually equal the owner.
5237
configText: function (type, args, obj) {
5245
* The default event handler fired when the "container" property
5247
* @method configContainer
5248
* @param {String} type The CustomEvent type (usually the property name)
5249
* @param {Object[]} args The CustomEvent arguments. For
5250
* configuration handlers, args[0] will equal the newly applied value
5252
* @param {Object} obj The scope object. For configuration handlers,
5253
* this will usually equal the owner.
5255
configContainer: function (type, args, obj) {
5256
var container = args[0];
5258
if (typeof container == 'string') {
5259
this.cfg.setProperty("container", document.getElementById(container), true);
5264
* @method _removeEventListeners
5265
* @description Removes all of the DOM event handlers from the HTML
5266
* element(s) that trigger the display of the tooltip.
5269
_removeEventListeners: function () {
5271
var aElements = this._context,
5277
nElements = aElements.length;
5278
if (nElements > 0) {
5281
oElement = aElements[i];
5282
Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
5283
Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
5284
Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
5292
* The default event handler fired when the "context" property
5294
* @method configContext
5295
* @param {String} type The CustomEvent type (usually the property name)
5296
* @param {Object[]} args The CustomEvent arguments. For configuration
5297
* handlers, args[0] will equal the newly applied value for the property.
5298
* @param {Object} obj The scope object. For configuration handlers,
5299
* this will usually equal the owner.
5301
configContext: function (type, args, obj) {
5303
var context = args[0],
5311
// Normalize parameter into an array
5312
if (! (context instanceof Array)) {
5313
if (typeof context == "string") {
5314
this.cfg.setProperty("context", [document.getElementById(context)], true);
5315
} else { // Assuming this is an element
5316
this.cfg.setProperty("context", [context], true);
5318
context = this.cfg.getProperty("context");
5321
// Remove any existing mouseover/mouseout listeners
5322
this._removeEventListeners();
5324
// Add mouseover/mouseout listeners to context elements
5325
this._context = context;
5327
aElements = this._context;
5330
nElements = aElements.length;
5331
if (nElements > 0) {
5334
oElement = aElements[i];
5335
Event.on(oElement, "mouseover", this.onContextMouseOver, this);
5336
Event.on(oElement, "mousemove", this.onContextMouseMove, this);
5337
Event.on(oElement, "mouseout", this.onContextMouseOut, this);
5345
// END BUILT-IN PROPERTY EVENT HANDLERS //
5347
// BEGIN BUILT-IN DOM EVENT HANDLERS //
5350
* The default event handler fired when the user moves the mouse while
5351
* over the context element.
5352
* @method onContextMouseMove
5353
* @param {DOMEvent} e The current DOM event
5354
* @param {Object} obj The object argument
5356
onContextMouseMove: function (e, obj) {
5357
obj.pageX = Event.getPageX(e);
5358
obj.pageY = Event.getPageY(e);
5362
* The default event handler fired when the user mouses over the
5364
* @method onContextMouseOver
5365
* @param {DOMEvent} e The current DOM event
5366
* @param {Object} obj The object argument
5368
onContextMouseOver: function (e, obj) {
5371
if (context.title) {
5372
obj._tempTitle = context.title;
5376
// Fire first, to honor disabled set in the listner
5377
if (obj.fireEvent("contextMouseOver", context, e) !== false
5378
&& !obj.cfg.getProperty("disabled")) {
5380
// Stop the tooltip from being hidden (set on last mouseout)
5381
if (obj.hideProcId) {
5382
clearTimeout(obj.hideProcId);
5383
obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
5384
obj.hideProcId = null;
5387
Event.on(context, "mousemove", obj.onContextMouseMove, obj);
5390
* The unique process ID associated with the thread responsible
5391
* for showing the Tooltip.
5394
obj.showProcId = obj.doShow(e, context);
5395
obj.logger.log("Setting show tooltip timeout: " + obj.showProcId, "time");
5400
* The default event handler fired when the user mouses out of
5401
* the context element.
5402
* @method onContextMouseOut
5403
* @param {DOMEvent} e The current DOM event
5404
* @param {Object} obj The object argument
5406
onContextMouseOut: function (e, obj) {
5409
if (obj._tempTitle) {
5410
el.title = obj._tempTitle;
5411
obj._tempTitle = null;
5414
if (obj.showProcId) {
5415
clearTimeout(obj.showProcId);
5416
obj.logger.log("Clearing show timer: " + obj.showProcId, "time");
5417
obj.showProcId = null;
5420
if (obj.hideProcId) {
5421
clearTimeout(obj.hideProcId);
5422
obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
5423
obj.hideProcId = null;
5426
obj.fireEvent("contextMouseOut", el, e);
5428
obj.hideProcId = setTimeout(function () {
5430
}, obj.cfg.getProperty("hidedelay"));
5433
// END BUILT-IN DOM EVENT HANDLERS //
5436
* Processes the showing of the Tooltip by setting the timeout delay
5437
* and offset of the Tooltip.
5439
* @param {DOMEvent} e The current DOM event
5440
* @param {HTMLElement} context The current context element
5441
* @return {Number} The process ID of the timeout function associated
5444
doShow: function (e, context) {
5449
if (UA.opera && context.tagName &&
5450
context.tagName.toUpperCase() == "A") {
5454
return setTimeout(function () {
5456
var txt = me.cfg.getProperty("text");
5458
// title does not over-ride text
5459
if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
5460
me.setBody(me._tempTitle);
5462
me.cfg.refireEvent("text");
5465
me.logger.log("Show tooltip", "time");
5466
me.moveTo(me.pageX, me.pageY + yOffset);
5468
if (me.cfg.getProperty("preventoverlap")) {
5469
me.preventOverlap(me.pageX, me.pageY);
5472
Event.removeListener(context, "mousemove", me.onContextMouseMove);
5474
me.contextTriggerEvent.fire(context);
5478
me.hideProcId = me.doHide();
5479
me.logger.log("Hide tooltip time active: " + me.hideProcId, "time");
5481
}, this.cfg.getProperty("showdelay"));
5485
* Sets the timeout for the auto-dismiss delay, which by default is 5
5486
* seconds, meaning that a tooltip will automatically dismiss itself
5487
* after 5 seconds of being displayed.
5490
doHide: function () {
5494
me.logger.log("Setting hide tooltip timeout", "time");
5496
return setTimeout(function () {
5498
me.logger.log("Hide tooltip", "time");
5501
}, this.cfg.getProperty("autodismissdelay"));
5506
* Fired when the Tooltip is moved, this event handler is used to
5507
* prevent the Tooltip from overlapping with its context element.
5508
* @method preventOverlay
5509
* @param {Number} pageX The x coordinate position of the mouse pointer
5510
* @param {Number} pageY The y coordinate position of the mouse pointer
5512
preventOverlap: function (pageX, pageY) {
5514
var height = this.element.offsetHeight,
5515
mousePoint = new YAHOO.util.Point(pageX, pageY),
5516
elementRegion = Dom.getRegion(this.element);
5518
elementRegion.top -= 5;
5519
elementRegion.left -= 5;
5520
elementRegion.right += 5;
5521
elementRegion.bottom += 5;
5523
this.logger.log("context " + elementRegion, "ttip");
5524
this.logger.log("mouse " + mousePoint, "ttip");
5526
if (elementRegion.contains(mousePoint)) {
5527
this.logger.log("OVERLAP", "warn");
5528
this.cfg.setProperty("y", (pageY - height - 5));
5535
* @description "render" event handler for the Tooltip.
5536
* @param {String} p_sType String representing the name of the event
5538
* @param {Array} p_aArgs Array of arguments sent when the event
5541
onRender: function (p_sType, p_aArgs) {
5543
function sizeShadow() {
5545
var oElement = this.element,
5546
oShadow = this.underlay;
5549
oShadow.style.width = (oElement.offsetWidth + 6) + "px";
5550
oShadow.style.height = (oElement.offsetHeight + 1) + "px";
5555
function addShadowVisibleClass() {
5556
Dom.addClass(this.underlay, "yui-tt-shadow-visible");
5559
this.forceUnderlayRedraw();
5563
function removeShadowVisibleClass() {
5564
Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
5567
function createShadow() {
5569
var oShadow = this.underlay,
5577
oElement = this.element;
5578
Module = YAHOO.widget.Module;
5582
if (!m_oShadowTemplate) {
5583
m_oShadowTemplate = document.createElement("div");
5584
m_oShadowTemplate.className = "yui-tt-shadow";
5587
oShadow = m_oShadowTemplate.cloneNode(false);
5589
oElement.appendChild(oShadow);
5591
this.underlay = oShadow;
5593
// Backward compatibility, even though it's probably
5594
// intended to be "private", it isn't marked as such in the api docs
5595
this._shadow = this.underlay;
5597
addShadowVisibleClass.call(this);
5599
this.subscribe("beforeShow", addShadowVisibleClass);
5600
this.subscribe("hide", removeShadowVisibleClass);
5603
window.setTimeout(function () {
5604
sizeShadow.call(me);
5607
this.cfg.subscribeToConfigEvent("width", sizeShadow);
5608
this.cfg.subscribeToConfigEvent("height", sizeShadow);
5609
this.subscribe("changeContent", sizeShadow);
5611
Module.textResizeEvent.subscribe(sizeShadow, this, true);
5612
this.subscribe("destroy", function () {
5613
Module.textResizeEvent.unsubscribe(sizeShadow, this);
5619
function onBeforeShow() {
5620
createShadow.call(this);
5621
this.unsubscribe("beforeShow", onBeforeShow);
5624
if (this.cfg.getProperty("visible")) {
5625
createShadow.call(this);
5627
this.subscribe("beforeShow", onBeforeShow);
5633
* Forces the underlay element to be repainted, through the application/removal
5634
* of a yui-force-redraw class to the underlay element.
5636
* @method forceUnderlayRedraw
5638
forceUnderlayRedraw : function() {
5640
Dom.addClass(tt.underlay, "yui-force-redraw");
5641
setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
5645
* Removes the Tooltip element from the DOM and sets all child
5649
destroy: function () {
5651
// Remove any existing mouseover/mouseout listeners
5652
this._removeEventListeners();
5654
Tooltip.superclass.destroy.call(this);
5659
* Returns a string representation of the object.
5661
* @return {String} The string representation of the Tooltip
5663
toString: function () {
5664
return "Tooltip " + this.id;
5674
* Panel is an implementation of Overlay that behaves like an OS window,
5675
* with a draggable header and an optional close icon at the top right.
5676
* @namespace YAHOO.widget
5678
* @extends YAHOO.widget.Overlay
5680
* @param {String} el The element ID representing the Panel <em>OR</em>
5681
* @param {HTMLElement} el The element representing the Panel
5682
* @param {Object} userConfig The configuration object literal containing
5683
* the configuration that should be set for this Panel. See configuration
5684
* documentation for more details.
5686
YAHOO.widget.Panel = function (el, userConfig) {
5687
YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5690
var _currentModal = null;
5692
var Lang = YAHOO.lang,
5696
CustomEvent = Util.CustomEvent,
5697
KeyListener = YAHOO.util.KeyListener,
5698
Config = Util.Config,
5699
Overlay = YAHOO.widget.Overlay,
5700
Panel = YAHOO.widget.Panel,
5703
bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
5706
m_oUnderlayTemplate,
5707
m_oCloseIconTemplate,
5710
* Constant representing the name of the Panel's events
5711
* @property EVENT_TYPES
5717
"SHOW_MASK": "showMask",
5718
"HIDE_MASK": "hideMask",
5723
* Constant representing the Panel's configuration properties
5724
* @property DEFAULT_CONFIG
5734
validator: Lang.isBoolean,
5735
supercedes: ["visible"]
5740
value: (Util.DD ? true : false),
5741
validator: Lang.isBoolean,
5742
supercedes: ["visible"]
5748
validator: Lang.isBoolean,
5749
supercedes: ["draggable"]
5755
supercedes: ["visible"]
5761
validator: Lang.isBoolean,
5762
supercedes: ["visible", "zindex"]
5766
key: "keylisteners",
5767
suppressEvent: true,
5768
supercedes: ["visible"]
5773
supercedes: ["close"],
5774
validator: Lang.isObject,
5782
* Constant representing the default CSS class used for a Panel
5783
* @property YAHOO.widget.Panel.CSS_PANEL
5788
Panel.CSS_PANEL = "yui-panel";
5791
* Constant representing the default CSS class used for a Panel's
5792
* wrapping container
5793
* @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5798
Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5801
* Constant representing the default set of focusable elements
5802
* on the pagewhich Modal Panels will prevent access to, when
5803
* the modal mask is displayed
5805
* @property YAHOO.widget.Panel.FOCUSABLE
5818
// Private CustomEvent listeners
5821
"beforeRender" event handler that creates an empty header for a Panel
5822
instance if its "draggable" configuration property is set to "true"
5823
and no header has been created.
5826
function createHeader(p_sType, p_aArgs) {
5827
if (!this.header && this.cfg.getProperty("draggable")) {
5828
this.setHeader(" ");
5833
"hide" event handler that sets a Panel instance's "width"
5834
configuration property back to its original value before
5835
"setWidthToOffsetWidth" was called.
5838
function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5840
var sOriginalWidth = p_oObject[0],
5841
sNewWidth = p_oObject[1],
5843
sCurrentWidth = oConfig.getProperty("width");
5845
if (sCurrentWidth == sNewWidth) {
5846
oConfig.setProperty("width", sOriginalWidth);
5849
this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5853
"beforeShow" event handler that sets a Panel instance's "width"
5854
configuration property to the value of its root HTML
5855
elements's offsetWidth
5858
function setWidthToOffsetWidth(p_sType, p_aArgs) {
5867
sOriginalWidth = oConfig.getProperty("width");
5869
if (!sOriginalWidth || sOriginalWidth == "auto") {
5871
sNewWidth = (this.element.offsetWidth + "px");
5873
oConfig.setProperty("width", sNewWidth);
5875
this.subscribe("hide", restoreOriginalWidth,
5876
[(sOriginalWidth || ""), sNewWidth]);
5882
YAHOO.extend(Panel, Overlay, {
5885
* The Overlay initialization method, which is executed for Overlay and
5886
* all of its subclasses. This method is automatically called by the
5887
* constructor, and sets up all DOM references for pre-existing markup,
5888
* and creates required markup if it is not already present.
5890
* @param {String} el The element ID representing the Overlay <em>OR</em>
5891
* @param {HTMLElement} el The element representing the Overlay
5892
* @param {Object} userConfig The configuration object literal
5893
* containing the configuration that should be set for this Overlay.
5894
* See configuration documentation for more details.
5896
init: function (el, userConfig) {
5898
Note that we don't pass the user config in here yet because
5899
we only want it executed once, at the lowest subclass level
5902
Panel.superclass.init.call(this, el/*, userConfig*/);
5904
this.beforeInitEvent.fire(Panel);
5906
Dom.addClass(this.element, Panel.CSS_PANEL);
5908
this.buildWrapper();
5911
this.cfg.applyConfig(userConfig, true);
5914
this.subscribe("showMask", this._addFocusHandlers);
5915
this.subscribe("hideMask", this._removeFocusHandlers);
5916
this.subscribe("beforeRender", createHeader);
5918
this.subscribe("render", function() {
5919
this.setFirstLastFocusable();
5920
this.subscribe("changeContent", this.setFirstLastFocusable);
5923
this.subscribe("show", this.focusFirst);
5925
this.initEvent.fire(Panel);
5929
* @method _onElementFocus
5932
* "focus" event handler for a focuable element. Used to automatically
5933
* blur the element when it receives focus to ensure that a Panel
5934
* instance's modality is not compromised.
5936
* @param {Event} e The DOM event object
5938
_onElementFocus : function(e){
5940
if(_currentModal === this) {
5942
var target = Event.getTarget(e),
5943
doc = document.documentElement,
5944
insideDoc = (target !== doc && target !== window);
5946
// mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on
5947
// the documentElement, when the document scrollbars are clicked on
5948
if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
5950
if (this.firstElement) {
5951
this.firstElement.focus();
5953
if (this._modalFocus) {
5954
this._modalFocus.focus();
5956
this.innerElement.focus();
5960
// Just in case we fail to focus
5962
if (insideDoc && target !== document.body) {
5972
* @method _addFocusHandlers
5975
* "showMask" event handler that adds a "focus" event handler to all
5976
* focusable elements in the document to enforce a Panel instance's
5977
* modality from being compromised.
5979
* @param p_sType {String} Custom event type
5980
* @param p_aArgs {Array} Custom event arguments
5982
_addFocusHandlers: function(p_sType, p_aArgs) {
5983
if (!this.firstElement) {
5984
if (UA.webkit || UA.opera) {
5985
if (!this._modalFocus) {
5986
this._createHiddenFocusElement();
5989
this.innerElement.tabIndex = 0;
5992
this.setTabLoop(this.firstElement, this.lastElement);
5993
Event.onFocus(document.documentElement, this._onElementFocus, this, true);
5994
_currentModal = this;
5998
* Creates a hidden focusable element, used to focus on,
5999
* to enforce modality for browsers in which focus cannot
6000
* be applied to the container box.
6002
* @method _createHiddenFocusElement
6005
_createHiddenFocusElement : function() {
6006
var e = document.createElement("button");
6007
e.style.height = "1px";
6008
e.style.width = "1px";
6009
e.style.position = "absolute";
6010
e.style.left = "-10000em";
6011
e.style.opacity = 0;
6013
this.innerElement.appendChild(e);
6014
this._modalFocus = e;
6018
* @method _removeFocusHandlers
6021
* "hideMask" event handler that removes all "focus" event handlers added
6022
* by the "addFocusEventHandlers" method.
6024
* @param p_sType {String} Event type
6025
* @param p_aArgs {Array} Event Arguments
6027
_removeFocusHandlers: function(p_sType, p_aArgs) {
6028
Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
6030
if (_currentModal == this) {
6031
_currentModal = null;
6036
* Sets focus to the first element in the Panel.
6038
* @method focusFirst
6040
focusFirst: function (type, args, obj) {
6041
var el = this.firstElement;
6043
if (args && args[1]) {
6044
Event.stopEvent(args[1]);
6057
* Sets focus to the last element in the Panel.
6061
focusLast: function (type, args, obj) {
6062
var el = this.lastElement;
6064
if (args && args[1]) {
6065
Event.stopEvent(args[1]);
6078
* Sets up a tab, shift-tab loop between the first and last elements
6079
* provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
6080
* instance properties, which are reset everytime this method is invoked.
6082
* @method setTabLoop
6083
* @param {HTMLElement} firstElement
6084
* @param {HTMLElement} lastElement
6087
setTabLoop : function(firstElement, lastElement) {
6089
var backTab = this.preventBackTab, tab = this.preventTabOut,
6090
showEvent = this.showEvent, hideEvent = this.hideEvent;
6094
showEvent.unsubscribe(backTab.enable, backTab);
6095
hideEvent.unsubscribe(backTab.disable, backTab);
6096
backTab = this.preventBackTab = null;
6101
showEvent.unsubscribe(tab.enable, tab);
6102
hideEvent.unsubscribe(tab.disable,tab);
6103
tab = this.preventTabOut = null;
6107
this.preventBackTab = new KeyListener(firstElement,
6108
{shift:true, keys:9},
6109
{fn:this.focusLast, scope:this, correctScope:true}
6111
backTab = this.preventBackTab;
6113
showEvent.subscribe(backTab.enable, backTab, true);
6114
hideEvent.subscribe(backTab.disable,backTab, true);
6118
this.preventTabOut = new KeyListener(lastElement,
6119
{shift:false, keys:9},
6120
{fn:this.focusFirst, scope:this, correctScope:true}
6122
tab = this.preventTabOut;
6124
showEvent.subscribe(tab.enable, tab, true);
6125
hideEvent.subscribe(tab.disable,tab, true);
6130
* Returns an array of the currently focusable items which reside within
6131
* Panel. The set of focusable elements the method looks for are defined
6132
* in the Panel.FOCUSABLE static property
6134
* @method getFocusableElements
6135
* @param {HTMLElement} root element to start from.
6137
getFocusableElements : function(root) {
6139
root = root || this.innerElement;
6142
for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
6143
focusable[Panel.FOCUSABLE[i]] = true;
6146
function isFocusable(el) {
6147
if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
6153
// Not looking by Tag, since we want elements in DOM order
6154
return Dom.getElementsBy(isFocusable, null, root);
6158
* Sets the firstElement and lastElement instance properties
6159
* to the first and last focusable elements in the Panel.
6161
* @method setFirstLastFocusable
6163
setFirstLastFocusable : function() {
6165
this.firstElement = null;
6166
this.lastElement = null;
6168
var elements = this.getFocusableElements();
6169
this.focusableElements = elements;
6171
if (elements.length > 0) {
6172
this.firstElement = elements[0];
6173
this.lastElement = elements[elements.length - 1];
6176
if (this.cfg.getProperty("modal")) {
6177
this.setTabLoop(this.firstElement, this.lastElement);
6182
* Initializes the custom events for Module which are fired
6183
* automatically at appropriate times by the Module class.
6185
initEvents: function () {
6186
Panel.superclass.initEvents.call(this);
6188
var SIGNATURE = CustomEvent.LIST;
6191
* CustomEvent fired after the modality mask is shown
6192
* @event showMaskEvent
6194
this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
6195
this.showMaskEvent.signature = SIGNATURE;
6198
* CustomEvent fired after the modality mask is hidden
6199
* @event hideMaskEvent
6201
this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
6202
this.hideMaskEvent.signature = SIGNATURE;
6205
* CustomEvent when the Panel is dragged
6208
this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
6209
this.dragEvent.signature = SIGNATURE;
6213
* Initializes the class's configurable properties which can be changed
6214
* using the Panel's Config object (cfg).
6215
* @method initDefaultConfig
6217
initDefaultConfig: function () {
6218
Panel.superclass.initDefaultConfig.call(this);
6220
// Add panel config properties //
6223
* True if the Panel should display a "close" button
6228
this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
6229
handler: this.configClose,
6230
value: DEFAULT_CONFIG.CLOSE.value,
6231
validator: DEFAULT_CONFIG.CLOSE.validator,
6232
supercedes: DEFAULT_CONFIG.CLOSE.supercedes
6236
* Boolean specifying if the Panel should be draggable. The default
6237
* value is "true" if the Drag and Drop utility is included,
6238
* otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
6239
* known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
6240
* (Quirks Mode) where Panels that either don't have a value set for
6241
* their "width" configuration property, or their "width"
6242
* configuration property is set to "auto" will only be draggable by
6243
* placing the mouse on the text of the Panel's header element.
6244
* To fix this bug, draggable Panels missing a value for their
6245
* "width" configuration property, or whose "width" configuration
6246
* property is set to "auto" will have it set to the value of
6247
* their root HTML element's offsetWidth before they are made
6248
* visible. The calculated width is then removed when the Panel is
6249
* hidden. <em>This fix is only applied to draggable Panels in IE 6
6250
* (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
6251
* more information on this issue see:
6252
* SourceForge bugs #1726972 and #1589210.
6257
this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
6258
handler: this.configDraggable,
6259
value: (Util.DD) ? true : false,
6260
validator: DEFAULT_CONFIG.DRAGGABLE.validator,
6261
supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
6265
* Boolean specifying if the draggable Panel should be drag only, not interacting with drop
6266
* targets on the page.
6268
* When set to true, draggable Panels will not check to see if they are over drop targets,
6269
* or fire the DragDrop events required to support drop target interaction (onDragEnter,
6270
* onDragOver, onDragOut, onDragDrop etc.).
6271
* If the Panel is not designed to be dropped on any target elements on the page, then this
6272
* flag can be set to true to improve performance.
6275
* When set to false, all drop target related events will be fired.
6278
* The property is set to false by default to maintain backwards compatibility but should be
6279
* set to true if drop target interaction is not required for the Panel, to improve performance.</p>
6285
this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, {
6286
value: DEFAULT_CONFIG.DRAG_ONLY.value,
6287
validator: DEFAULT_CONFIG.DRAG_ONLY.validator,
6288
supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes
6292
* Sets the type of underlay to display for the Panel. Valid values
6293
* are "shadow," "matte," and "none". <strong>PLEASE NOTE:</strong>
6294
* The creation of the underlay element is deferred until the Panel
6295
* is initially made visible. For Gecko-based browsers on Mac
6296
* OS X the underlay elment is always created as it is used as a
6297
* shim to prevent Aqua scrollbars below a Panel instance from poking
6298
* through it (See SourceForge bug #836476).
6303
this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
6304
handler: this.configUnderlay,
6305
value: DEFAULT_CONFIG.UNDERLAY.value,
6306
supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
6310
* True if the Panel should be displayed in a modal fashion,
6311
* automatically creating a transparent mask over the document that
6312
* will not be removed until the Panel is dismissed.
6317
this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
6318
handler: this.configModal,
6319
value: DEFAULT_CONFIG.MODAL.value,
6320
validator: DEFAULT_CONFIG.MODAL.validator,
6321
supercedes: DEFAULT_CONFIG.MODAL.supercedes
6325
* A KeyListener (or array of KeyListeners) that will be enabled
6326
* when the Panel is shown, and disabled when the Panel is hidden.
6327
* @config keylisteners
6328
* @type YAHOO.util.KeyListener[]
6331
this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
6332
handler: this.configKeyListeners,
6333
suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
6334
supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
6338
* UI Strings used by the Panel
6342
* @default An object literal with the properties shown below:
6344
* <dt>close</dt><dd><em>String</em> : The string to use for the close icon. Defaults to "Close".</dd>
6347
this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, {
6348
value:DEFAULT_CONFIG.STRINGS.value,
6349
handler:this.configStrings,
6350
validator:DEFAULT_CONFIG.STRINGS.validator,
6351
supercedes:DEFAULT_CONFIG.STRINGS.supercedes
6355
// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6358
* The default event handler fired when the "close" property is changed.
6359
* The method controls the appending or hiding of the close icon at the
6360
* top right of the Panel.
6361
* @method configClose
6362
* @param {String} type The CustomEvent type (usually the property name)
6363
* @param {Object[]} args The CustomEvent arguments. For configuration
6364
* handlers, args[0] will equal the newly applied value for the property.
6365
* @param {Object} obj The scope object. For configuration handlers,
6366
* this will usually equal the owner.
6368
configClose: function (type, args, obj) {
6371
oClose = this.close,
6372
strings = this.cfg.getProperty("strings");
6377
if (!m_oCloseIconTemplate) {
6378
m_oCloseIconTemplate = document.createElement("a");
6379
m_oCloseIconTemplate.className = "container-close";
6380
m_oCloseIconTemplate.href = "#";
6383
oClose = m_oCloseIconTemplate.cloneNode(true);
6384
this.innerElement.appendChild(oClose);
6386
oClose.innerHTML = (strings && strings.close) ? strings.close : " ";
6388
Event.on(oClose, "click", this._doClose, this, true);
6390
this.close = oClose;
6393
oClose.style.display = "block";
6398
oClose.style.display = "none";
6405
* Event handler for the close icon
6410
* @param {DOMEvent} e
6412
_doClose : function (e) {
6413
Event.preventDefault(e);
6418
* The default event handler fired when the "draggable" property
6420
* @method configDraggable
6421
* @param {String} type The CustomEvent type (usually the property name)
6422
* @param {Object[]} args The CustomEvent arguments. For configuration
6423
* handlers, args[0] will equal the newly applied value for the property.
6424
* @param {Object} obj The scope object. For configuration handlers,
6425
* this will usually equal the owner.
6427
configDraggable: function (type, args, obj) {
6432
YAHOO.log("DD dependency not met.", "error");
6433
this.cfg.setProperty("draggable", false);
6438
Dom.setStyle(this.header, "cursor", "move");
6439
this.registerDragDrop();
6442
this.subscribe("beforeShow", setWidthToOffsetWidth);
6451
Dom.setStyle(this.header,"cursor","auto");
6454
this.unsubscribe("beforeShow", setWidthToOffsetWidth);
6459
* The default event handler fired when the "underlay" property
6461
* @method configUnderlay
6462
* @param {String} type The CustomEvent type (usually the property name)
6463
* @param {Object[]} args The CustomEvent arguments. For configuration
6464
* handlers, args[0] will equal the newly applied value for the property.
6465
* @param {Object} obj The scope object. For configuration handlers,
6466
* this will usually equal the owner.
6468
configUnderlay: function (type, args, obj) {
6470
var bMacGecko = (this.platform == "mac" && UA.gecko),
6471
sUnderlay = args[0].toLowerCase(),
6472
oUnderlay = this.underlay,
6473
oElement = this.element;
6475
function createUnderlay() {
6477
if (!oUnderlay) { // create if not already in DOM
6479
if (!m_oUnderlayTemplate) {
6480
m_oUnderlayTemplate = document.createElement("div");
6481
m_oUnderlayTemplate.className = "underlay";
6484
oUnderlay = m_oUnderlayTemplate.cloneNode(false);
6485
this.element.appendChild(oUnderlay);
6487
this.underlay = oUnderlay;
6490
this.sizeUnderlay();
6491
this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
6492
this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
6494
this.changeContentEvent.subscribe(this.sizeUnderlay);
6495
YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
6498
if (UA.webkit && UA.webkit < 420) {
6499
this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
6506
function onBeforeShow() {
6507
var bNew = createUnderlay.call(this);
6508
if (!bNew && bIEQuirks) {
6509
this.sizeUnderlay();
6511
this._underlayDeferred = false;
6512
this.beforeShowEvent.unsubscribe(onBeforeShow);
6515
function destroyUnderlay() {
6516
if (this._underlayDeferred) {
6517
this.beforeShowEvent.unsubscribe(onBeforeShow);
6518
this._underlayDeferred = false;
6522
this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
6523
this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
6524
this.changeContentEvent.unsubscribe(this.sizeUnderlay);
6525
this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
6526
YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
6528
this.element.removeChild(oUnderlay);
6530
this.underlay = null;
6534
switch (sUnderlay) {
6536
Dom.removeClass(oElement, "matte");
6537
Dom.addClass(oElement, "shadow");
6541
destroyUnderlay.call(this);
6543
Dom.removeClass(oElement, "shadow");
6544
Dom.addClass(oElement, "matte");
6548
destroyUnderlay.call(this);
6550
Dom.removeClass(oElement, "shadow");
6551
Dom.removeClass(oElement, "matte");
6555
if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
6556
if (this.cfg.getProperty("visible")) {
6557
var bNew = createUnderlay.call(this);
6558
if (!bNew && bIEQuirks) {
6559
this.sizeUnderlay();
6562
if (!this._underlayDeferred) {
6563
this.beforeShowEvent.subscribe(onBeforeShow);
6564
this._underlayDeferred = true;
6571
* The default event handler fired when the "modal" property is
6572
* changed. This handler subscribes or unsubscribes to the show and hide
6573
* events to handle the display or hide of the modality mask.
6574
* @method configModal
6575
* @param {String} type The CustomEvent type (usually the property name)
6576
* @param {Object[]} args The CustomEvent arguments. For configuration
6577
* handlers, args[0] will equal the newly applied value for the property.
6578
* @param {Object} obj The scope object. For configuration handlers,
6579
* this will usually equal the owner.
6581
configModal: function (type, args, obj) {
6583
var modal = args[0];
6585
if (!this._hasModalityEventListeners) {
6587
this.subscribe("beforeShow", this.buildMask);
6588
this.subscribe("beforeShow", this.bringToTop);
6589
this.subscribe("beforeShow", this.showMask);
6590
this.subscribe("hide", this.hideMask);
6592
Overlay.windowResizeEvent.subscribe(this.sizeMask,
6595
this._hasModalityEventListeners = true;
6598
if (this._hasModalityEventListeners) {
6600
if (this.cfg.getProperty("visible")) {
6605
this.unsubscribe("beforeShow", this.buildMask);
6606
this.unsubscribe("beforeShow", this.bringToTop);
6607
this.unsubscribe("beforeShow", this.showMask);
6608
this.unsubscribe("hide", this.hideMask);
6610
Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6612
this._hasModalityEventListeners = false;
6618
* Removes the modality mask.
6619
* @method removeMask
6621
removeMask: function () {
6623
var oMask = this.mask,
6628
Hide the mask before destroying it to ensure that DOM
6629
event handlers on focusable elements get removed.
6633
oParentNode = oMask.parentNode;
6635
oParentNode.removeChild(oMask);
6643
* The default event handler fired when the "keylisteners" property
6645
* @method configKeyListeners
6646
* @param {String} type The CustomEvent type (usually the property name)
6647
* @param {Object[]} args The CustomEvent arguments. For configuration
6648
* handlers, args[0] will equal the newly applied value for the property.
6649
* @param {Object} obj The scope object. For configuration handlers,
6650
* this will usually equal the owner.
6652
configKeyListeners: function (type, args, obj) {
6654
var listeners = args[0],
6661
if (listeners instanceof Array) {
6663
nListeners = listeners.length;
6665
for (i = 0; i < nListeners; i++) {
6667
listener = listeners[i];
6669
if (!Config.alreadySubscribed(this.showEvent,
6670
listener.enable, listener)) {
6672
this.showEvent.subscribe(listener.enable,
6677
if (!Config.alreadySubscribed(this.hideEvent,
6678
listener.disable, listener)) {
6680
this.hideEvent.subscribe(listener.disable,
6683
this.destroyEvent.subscribe(listener.disable,
6690
if (!Config.alreadySubscribed(this.showEvent,
6691
listeners.enable, listeners)) {
6693
this.showEvent.subscribe(listeners.enable,
6697
if (!Config.alreadySubscribed(this.hideEvent,
6698
listeners.disable, listeners)) {
6700
this.hideEvent.subscribe(listeners.disable,
6703
this.destroyEvent.subscribe(listeners.disable,
6715
* The default handler for the "strings" property
6716
* @method configStrings
6718
configStrings : function(type, args, obj) {
6719
var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
6720
this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
6724
* The default event handler fired when the "height" property is changed.
6725
* @method configHeight
6726
* @param {String} type The CustomEvent type (usually the property name)
6727
* @param {Object[]} args The CustomEvent arguments. For configuration
6728
* handlers, args[0] will equal the newly applied value for the property.
6729
* @param {Object} obj The scope object. For configuration handlers,
6730
* this will usually equal the owner.
6732
configHeight: function (type, args, obj) {
6733
var height = args[0],
6734
el = this.innerElement;
6736
Dom.setStyle(el, "height", height);
6737
this.cfg.refireEvent("iframe");
6741
* The default custom event handler executed when the Panel's height is changed,
6742
* if the autofillheight property has been set.
6744
* @method _autoFillOnHeightChange
6746
* @param {String} type The event type
6747
* @param {Array} args The array of arguments passed to event subscribers
6748
* @param {HTMLElement} el The header, body or footer element which is to be resized to fill
6749
* out the containers height
6751
_autoFillOnHeightChange : function(type, args, el) {
6752
Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
6755
setTimeout(function() {
6756
panel.sizeUnderlay();
6762
* The default event handler fired when the "width" property is changed.
6763
* @method configWidth
6764
* @param {String} type The CustomEvent type (usually the property name)
6765
* @param {Object[]} args The CustomEvent arguments. For configuration
6766
* handlers, args[0] will equal the newly applied value for the property.
6767
* @param {Object} obj The scope object. For configuration handlers,
6768
* this will usually equal the owner.
6770
configWidth: function (type, args, obj) {
6772
var width = args[0],
6773
el = this.innerElement;
6775
Dom.setStyle(el, "width", width);
6776
this.cfg.refireEvent("iframe");
6781
* The default event handler fired when the "zIndex" property is changed.
6782
* @method configzIndex
6783
* @param {String} type The CustomEvent type (usually the property name)
6784
* @param {Object[]} args The CustomEvent arguments. For configuration
6785
* handlers, args[0] will equal the newly applied value for the property.
6786
* @param {Object} obj The scope object. For configuration handlers,
6787
* this will usually equal the owner.
6789
configzIndex: function (type, args, obj) {
6790
Panel.superclass.configzIndex.call(this, type, args, obj);
6792
if (this.mask || this.cfg.getProperty("modal") === true) {
6793
var panelZ = Dom.getStyle(this.element, "zIndex");
6794
if (!panelZ || isNaN(panelZ)) {
6799
// Recursive call to configzindex (which should be stopped
6800
// from going further because panelZ should no longer === 0)
6801
this.cfg.setProperty("zIndex", 1);
6808
// END BUILT-IN PROPERTY EVENT HANDLERS //
6810
* Builds the wrapping container around the Panel that is used for
6811
* positioning the shadow and matte underlays. The container element is
6812
* assigned to a local instance variable called container, and the
6813
* element is reinserted inside of it.
6814
* @method buildWrapper
6816
buildWrapper: function () {
6818
var elementParent = this.element.parentNode,
6819
originalElement = this.element,
6820
wrapper = document.createElement("div");
6822
wrapper.className = Panel.CSS_PANEL_CONTAINER;
6823
wrapper.id = originalElement.id + "_c";
6825
if (elementParent) {
6826
elementParent.insertBefore(wrapper, originalElement);
6829
wrapper.appendChild(originalElement);
6831
this.element = wrapper;
6832
this.innerElement = originalElement;
6834
Dom.setStyle(this.innerElement, "visibility", "inherit");
6838
* Adjusts the size of the shadow based on the size of the element.
6839
* @method sizeUnderlay
6841
sizeUnderlay: function () {
6842
var oUnderlay = this.underlay,
6846
oElement = this.element;
6847
oUnderlay.style.width = oElement.offsetWidth + "px";
6848
oUnderlay.style.height = oElement.offsetHeight + "px";
6853
* Registers the Panel's header for drag & drop capability.
6854
* @method registerDragDrop
6856
registerDragDrop: function () {
6863
YAHOO.log("DD dependency not met.", "error");
6867
var bDragOnly = (this.cfg.getProperty("dragonly") === true);
6868
this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
6870
if (!this.header.id) {
6871
this.header.id = this.id + "_h";
6874
this.dd.startDrag = function () {
6883
if (YAHOO.env.ua.ie == 6) {
6884
Dom.addClass(me.element,"drag");
6887
if (me.cfg.getProperty("constraintoviewport")) {
6889
var nViewportOffset = Overlay.VIEWPORT_OFFSET;
6891
offsetHeight = me.element.offsetHeight;
6892
offsetWidth = me.element.offsetWidth;
6894
viewPortWidth = Dom.getViewportWidth();
6895
viewPortHeight = Dom.getViewportHeight();
6897
scrollX = Dom.getDocumentScrollLeft();
6898
scrollY = Dom.getDocumentScrollTop();
6900
if (offsetHeight + nViewportOffset < viewPortHeight) {
6901
this.minY = scrollY + nViewportOffset;
6902
this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
6904
this.minY = scrollY + nViewportOffset;
6905
this.maxY = scrollY + nViewportOffset;
6908
if (offsetWidth + nViewportOffset < viewPortWidth) {
6909
this.minX = scrollX + nViewportOffset;
6910
this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
6912
this.minX = scrollX + nViewportOffset;
6913
this.maxX = scrollX + nViewportOffset;
6916
this.constrainX = true;
6917
this.constrainY = true;
6919
this.constrainX = false;
6920
this.constrainY = false;
6923
me.dragEvent.fire("startDrag", arguments);
6926
this.dd.onDrag = function () {
6928
me.cfg.refireEvent("iframe");
6929
if (this.platform == "mac" && YAHOO.env.ua.gecko) {
6930
this.showMacGeckoScrollbars();
6933
me.dragEvent.fire("onDrag", arguments);
6936
this.dd.endDrag = function () {
6938
if (YAHOO.env.ua.ie == 6) {
6939
Dom.removeClass(me.element,"drag");
6942
me.dragEvent.fire("endDrag", arguments);
6943
me.moveEvent.fire(me.cfg.getProperty("xy"));
6947
this.dd.setHandleElId(this.header.id);
6948
this.dd.addInvalidHandleType("INPUT");
6949
this.dd.addInvalidHandleType("SELECT");
6950
this.dd.addInvalidHandleType("TEXTAREA");
6955
* Builds the mask that is laid over the document when the Panel is
6956
* configured to be modal.
6959
buildMask: function () {
6960
var oMask = this.mask;
6962
if (!m_oMaskTemplate) {
6963
m_oMaskTemplate = document.createElement("div");
6964
m_oMaskTemplate.className = "mask";
6965
m_oMaskTemplate.innerHTML = " ";
6967
oMask = m_oMaskTemplate.cloneNode(true);
6968
oMask.id = this.id + "_mask";
6970
document.body.insertBefore(oMask, document.body.firstChild);
6974
if (YAHOO.env.ua.gecko && this.platform == "mac") {
6975
Dom.addClass(this.mask, "block-scrollbars");
6978
// Stack mask based on the element zindex
6984
* Hides the modality mask.
6987
hideMask: function () {
6988
if (this.cfg.getProperty("modal") && this.mask) {
6989
this.mask.style.display = "none";
6990
Dom.removeClass(document.body, "masked");
6991
this.hideMaskEvent.fire();
6996
* Shows the modality mask.
6999
showMask: function () {
7000
if (this.cfg.getProperty("modal") && this.mask) {
7001
Dom.addClass(document.body, "masked");
7003
this.mask.style.display = "block";
7004
this.showMaskEvent.fire();
7009
* Sets the size of the modality mask to cover the entire scrollable
7010
* area of the document
7013
sizeMask: function () {
7016
// Shrink mask first, so it doesn't affect the document size.
7017
var mask = this.mask,
7018
viewWidth = Dom.getViewportWidth(),
7019
viewHeight = Dom.getViewportHeight();
7021
if (mask.offsetHeight > viewHeight) {
7022
mask.style.height = viewHeight + "px";
7025
if (mask.offsetWidth > viewWidth) {
7026
mask.style.width = viewWidth + "px";
7029
// Then size it to the document
7030
mask.style.height = Dom.getDocumentHeight() + "px";
7031
mask.style.width = Dom.getDocumentWidth() + "px";
7036
* Sets the zindex of the mask, if it exists, based on the zindex of
7037
* the Panel element. The zindex of the mask is set to be one less
7038
* than the Panel element's zindex.
7040
* <p>NOTE: This method will not bump up the zindex of the Panel
7041
* to ensure that the mask has a non-negative zindex. If you require the
7042
* mask zindex to be 0 or higher, the zindex of the Panel
7043
* should be set to a value higher than 0, before this method is called.
7047
stackMask: function() {
7049
var panelZ = Dom.getStyle(this.element, "zIndex");
7050
if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
7051
Dom.setStyle(this.mask, "zIndex", panelZ - 1);
7057
* Renders the Panel by inserting the elements that are not already in
7058
* the main Panel into their correct places. Optionally appends the
7059
* Panel to the specified node prior to the render's execution. NOTE:
7060
* For Panels without existing markup, the appendToNode argument is
7061
* REQUIRED. If this argument is ommitted and the current element is
7062
* not present in the document, the function will return false,
7063
* indicating that the render was a failure.
7065
* @param {String} appendToNode The element id to which the Module
7066
* should be appended to prior to rendering <em>OR</em>
7067
* @param {HTMLElement} appendToNode The element to which the Module
7068
* should be appended to prior to rendering
7069
* @return {boolean} Success or failure of the render
7071
render: function (appendToNode) {
7073
return Panel.superclass.render.call(this,
7074
appendToNode, this.innerElement);
7079
* Removes the Panel element from the DOM and sets all child elements
7083
destroy: function () {
7084
Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
7087
Event.purgeElement(this.close);
7089
Panel.superclass.destroy.call(this);
7093
* Forces the underlay element to be repainted through the application/removal
7094
* of a yui-force-redraw class to the underlay element.
7096
* @method forceUnderlayRedraw
7098
forceUnderlayRedraw : function () {
7099
var u = this.underlay;
7100
Dom.addClass(u, "yui-force-redraw");
7101
setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
7105
* Returns a String representation of the object.
7107
* @return {String} The string representation of the Panel.
7109
toString: function () {
7110
return "Panel " + this.id;
7121
* Dialog is an implementation of Panel that can be used to submit form
7125
* Built-in functionality for buttons with event handlers is included.
7126
* If the optional YUI Button dependancy is included on the page, the buttons
7127
* created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
7131
* Forms can be processed in 3 ways -- via an asynchronous Connection utility call,
7132
* a simple form POST or GET, or manually. The YUI Connection utility should be
7133
* included if you're using the default "async" postmethod, but is not required if
7134
* you're using any of the other postmethod values.
7136
* @namespace YAHOO.widget
7138
* @extends YAHOO.widget.Panel
7140
* @param {String} el The element ID representing the Dialog <em>OR</em>
7141
* @param {HTMLElement} el The element representing the Dialog
7142
* @param {Object} userConfig The configuration object literal containing
7143
* the configuration that should be set for this Dialog. See configuration
7144
* documentation for more details.
7146
YAHOO.widget.Dialog = function (el, userConfig) {
7147
YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
7150
var Event = YAHOO.util.Event,
7151
CustomEvent = YAHOO.util.CustomEvent,
7152
Dom = YAHOO.util.Dom,
7153
Dialog = YAHOO.widget.Dialog,
7157
* Constant representing the name of the Dialog's events
7158
* @property EVENT_TYPES
7164
"BEFORE_SUBMIT": "beforeSubmit",
7166
"MANUAL_SUBMIT": "manualSubmit",
7167
"ASYNC_SUBMIT": "asyncSubmit",
7168
"FORM_SUBMIT": "formSubmit",
7173
* Constant representing the Dialog's configuration properties
7174
* @property DEFAULT_CONFIG
7194
supercedes: ["visible"]
7197
"HIDEAFTERSUBMIT" : {
7198
key: "hideaftersubmit",
7205
* Constant representing the default CSS class used for a Dialog
7206
* @property YAHOO.widget.Dialog.CSS_DIALOG
7211
Dialog.CSS_DIALOG = "yui-dialog";
7213
function removeButtonEventHandlers() {
7215
var aButtons = this._aButtons,
7220
if (Lang.isArray(aButtons)) {
7221
nButtons = aButtons.length;
7226
oButton = aButtons[i];
7228
if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
7231
else if (oButton.tagName.toUpperCase() == "BUTTON") {
7232
Event.purgeElement(oButton);
7233
Event.purgeElement(oButton, false);
7241
YAHOO.extend(Dialog, YAHOO.widget.Panel, {
7245
* @description Object reference to the Dialog's
7246
* <code><form></code> element.
7248
* @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7249
* level-one-html.html#ID-40002357">HTMLFormElement</a>
7254
* Initializes the class's configurable properties which can be changed
7255
* using the Dialog's Config object (cfg).
7256
* @method initDefaultConfig
7258
initDefaultConfig: function () {
7259
Dialog.superclass.initDefaultConfig.call(this);
7262
* The internally maintained callback object for use with the
7263
* Connection utility. The format of the callback object is
7264
* similar to Connection Manager's callback object and is
7265
* simply passed through to Connection Manager when the async
7267
* @property callback
7273
* The function to execute upon success of the
7274
* Connection submission (when the form does not
7275
* contain a file input element).
7277
* @property callback.success
7283
* The function to execute upon failure of the
7284
* Connection submission
7285
* @property callback.failure
7292
* The function to execute upon success of the
7293
* Connection submission, when the form contains
7294
* a file input element.
7297
* <em>NOTE:</em> Connection manager will not
7298
* invoke the success or failure handlers for the file
7299
* upload use case. This will be the only callback
7303
* For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
7304
* Connection Manager documenation on file uploads</a>.
7306
* @property callback.upload
7311
* The arbitraty argument or arguments to pass to the Connection
7312
* callback functions
7313
* @property callback.argument
7320
// Add form dialog config properties //
7322
* The method to use for posting the Dialog's form. Possible values
7323
* are "async", "form", and "manual".
7324
* @config postmethod
7328
this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
7329
handler: this.configPostMethod,
7330
value: DEFAULT_CONFIG.POST_METHOD.value,
7331
validator: function (val) {
7332
if (val != "form" && val != "async" && val != "none" &&
7342
* Any additional post data which needs to be sent when using the
7343
* <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
7344
* The format for the post data string is defined by Connection Manager's
7345
* <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a>
7351
this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
7352
value: DEFAULT_CONFIG.POST_DATA.value
7356
* This property is used to configure whether or not the
7357
* dialog should be automatically hidden after submit.
7359
* @config hideaftersubmit
7363
this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
7364
value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
7368
* Array of object literals, each containing a set of properties
7369
* defining a button to be appended into the Dialog's footer.
7371
* <p>Each button object in the buttons array can have three properties:</p>
7375
* The text that will display on the face of the button. The text can
7376
* include HTML, as long as it is compliant with HTML Button specifications.
7379
* <dd>Can be either:
7381
* <li>A reference to a function that should fire when the
7382
* button is clicked. (In this case scope of this function is
7383
* always its Dialog instance.)</li>
7385
* <li>An object literal representing the code to be
7386
* executed when the button is clicked.
7393
* <strong>fn:</strong> Function, //
7394
* The handler to call when the event fires.
7396
* <strong>obj:</strong> Object, //
7397
* An object to pass back to the handler.
7399
* <strong>scope:</strong> Object //
7400
* The object to use for the scope of the handler.
7407
* <dt>isDefault:</dt>
7409
* An optional boolean value that specifies that a button
7410
* should be highlighted and focused by default.
7414
* <em>NOTE:</em>If the YUI Button Widget is included on the page,
7415
* the buttons created will be instances of YAHOO.widget.Button.
7416
* Otherwise, HTML Buttons (<code><BUTTON></code>) will be
7420
* @type {Array|String}
7423
this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
7424
handler: this.configButtons,
7425
value: DEFAULT_CONFIG.BUTTONS.value,
7426
supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
7432
* Initializes the custom events for Dialog which are fired
7433
* automatically at appropriate times by the Dialog class.
7434
* @method initEvents
7436
initEvents: function () {
7437
Dialog.superclass.initEvents.call(this);
7439
var SIGNATURE = CustomEvent.LIST;
7442
* CustomEvent fired prior to submission
7443
* @event beforeSubmitEvent
7445
this.beforeSubmitEvent =
7446
this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
7447
this.beforeSubmitEvent.signature = SIGNATURE;
7450
* CustomEvent fired after submission
7451
* @event submitEvent
7453
this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
7454
this.submitEvent.signature = SIGNATURE;
7457
* CustomEvent fired for manual submission, before the generic submit event is fired
7458
* @event manualSubmitEvent
7460
this.manualSubmitEvent =
7461
this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
7462
this.manualSubmitEvent.signature = SIGNATURE;
7465
* CustomEvent fired after asynchronous submission, before the generic submit event is fired
7467
* @event asyncSubmitEvent
7468
* @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
7470
this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
7471
this.asyncSubmitEvent.signature = SIGNATURE;
7474
* CustomEvent fired after form-based submission, before the generic submit event is fired
7475
* @event formSubmitEvent
7477
this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
7478
this.formSubmitEvent.signature = SIGNATURE;
7481
* CustomEvent fired after cancel
7482
* @event cancelEvent
7484
this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
7485
this.cancelEvent.signature = SIGNATURE;
7490
* The Dialog initialization method, which is executed for Dialog and
7491
* all of its subclasses. This method is automatically called by the
7492
* constructor, and sets up all DOM references for pre-existing markup,
7493
* and creates required markup if it is not already present.
7496
* @param {String} el The element ID representing the Dialog <em>OR</em>
7497
* @param {HTMLElement} el The element representing the Dialog
7498
* @param {Object} userConfig The configuration object literal
7499
* containing the configuration that should be set for this Dialog.
7500
* See configuration documentation for more details.
7502
init: function (el, userConfig) {
7505
Note that we don't pass the user config in here yet because
7506
we only want it executed once, at the lowest subclass level
7509
Dialog.superclass.init.call(this, el/*, userConfig*/);
7511
this.beforeInitEvent.fire(Dialog);
7513
Dom.addClass(this.element, Dialog.CSS_DIALOG);
7515
this.cfg.setProperty("visible", false);
7518
this.cfg.applyConfig(userConfig, true);
7521
this.showEvent.subscribe(this.focusFirst, this, true);
7522
this.beforeHideEvent.subscribe(this.blurButtons, this, true);
7524
this.subscribe("changeBody", this.registerForm);
7526
this.initEvent.fire(Dialog);
7530
* Submits the Dialog's form depending on the value of the
7531
* "postmethod" configuration property. <strong>Please note:
7532
* </strong> As of version 2.3 this method will automatically handle
7533
* asyncronous file uploads should the Dialog instance's form contain
7534
* <code><input type="file"></code> elements. If a Dialog
7535
* instance will be handling asyncronous file uploads, its
7536
* <code>callback</code> property will need to be setup with a
7537
* <code>upload</code> handler rather than the standard
7538
* <code>success</code> and, or <code>failure</code> handlers. For more
7539
* information, see the <a href="http://developer.yahoo.com/yui/
7540
* connection/#file">Connection Manager documenation on file uploads</a>.
7543
doSubmit: function () {
7545
var Connect = YAHOO.util.Connect,
7547
bUseFileUpload = false,
7548
bUseSecureFileUpload = false,
7554
switch (this.cfg.getProperty("postmethod")) {
7557
aElements = oForm.elements;
7558
nElements = aElements.length;
7560
if (nElements > 0) {
7563
if (aElements[i].type == "file") {
7564
bUseFileUpload = true;
7571
if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
7572
bUseSecureFileUpload = true;
7575
formAttrs = this._getFormAttributes(oForm);
7577
Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
7579
var postData = this.cfg.getProperty("postdata");
7580
var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
7582
this.asyncSubmitEvent.fire(c);
7588
this.formSubmitEvent.fire();
7593
this.manualSubmitEvent.fire();
7599
* Retrieves important attributes (currently method and action) from
7600
* the form element, accounting for any elements which may have the same name
7601
* as the attributes. Defaults to "POST" and "" for method and action respectively
7602
* if the attribute cannot be retrieved.
7604
* @method _getFormAttributes
7606
* @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
7607
* @return {Object} Object literal, with method and action String properties.
7609
_getFormAttributes : function(oForm){
7616
if (oForm.getAttributeNode) {
7617
var action = oForm.getAttributeNode("action");
7618
var method = oForm.getAttributeNode("method");
7621
attrs.action = action.value;
7625
attrs.method = method.value;
7629
attrs.action = oForm.getAttribute("action");
7630
attrs.method = oForm.getAttribute("method");
7634
attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
7635
attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
7641
* Prepares the Dialog's internal FORM object, creating one if one is
7642
* not currently present.
7643
* @method registerForm
7645
registerForm: function() {
7647
var form = this.element.getElementsByTagName("form")[0];
7650
if (this.form == form && Dom.isAncestor(this.element, this.form)) {
7653
Event.purgeElement(this.form);
7659
form = document.createElement("form");
7660
form.name = "frm_" + this.id;
7661
this.body.appendChild(form);
7666
Event.on(form, "submit", this._submitHandler, this, true);
7671
* Internal handler for the form submit event
7673
* @method _submitHandler
7675
* @param {DOMEvent} e The DOM Event object
7677
_submitHandler : function(e) {
7684
* Sets up a tab, shift-tab loop between the first and last elements
7685
* provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
7686
* instance properties, which are reset everytime this method is invoked.
7688
* @method setTabLoop
7689
* @param {HTMLElement} firstElement
7690
* @param {HTMLElement} lastElement
7693
setTabLoop : function(firstElement, lastElement) {
7695
firstElement = firstElement || this.firstButton;
7696
lastElement = this.lastButton || lastElement;
7698
Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
7702
* Configures instance properties, pointing to the
7703
* first and last focusable elements in the Dialog's form.
7705
* @method setFirstLastFocusable
7707
setFirstLastFocusable : function() {
7709
Dialog.superclass.setFirstLastFocusable.call(this);
7711
var i, l, el, elements = this.focusableElements;
7713
this.firstFormElement = null;
7714
this.lastFormElement = null;
7716
if (this.form && elements && elements.length > 0) {
7717
l = elements.length;
7719
for (i = 0; i < l; ++i) {
7721
if (this.form === el.form) {
7722
this.firstFormElement = el;
7727
for (i = l-1; i >= 0; --i) {
7729
if (this.form === el.form) {
7730
this.lastFormElement = el;
7737
// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7739
* The default event handler fired when the "close" property is
7740
* changed. The method controls the appending or hiding of the close
7741
* icon at the top right of the Dialog.
7742
* @method configClose
7743
* @param {String} type The CustomEvent type (usually the property name)
7744
* @param {Object[]} args The CustomEvent arguments. For
7745
* configuration handlers, args[0] will equal the newly applied value
7747
* @param {Object} obj The scope object. For configuration handlers,
7748
* this will usually equal the owner.
7750
configClose: function (type, args, obj) {
7751
Dialog.superclass.configClose.apply(this, arguments);
7755
* Event handler for the close icon
7760
* @param {DOMEvent} e
7762
_doClose : function(e) {
7763
Event.preventDefault(e);
7768
* The default event handler for the "buttons" configuration property
7769
* @method configButtons
7770
* @param {String} type The CustomEvent type (usually the property name)
7771
* @param {Object[]} args The CustomEvent arguments. For configuration
7772
* handlers, args[0] will equal the newly applied value for the property.
7773
* @param {Object} obj The scope object. For configuration handlers,
7774
* this will usually equal the owner.
7776
configButtons: function (type, args, obj) {
7778
var Button = YAHOO.widget.Button,
7780
oInnerElement = this.innerElement,
7789
removeButtonEventHandlers.call(this);
7791
this._aButtons = null;
7793
if (Lang.isArray(aButtons)) {
7795
oSpan = document.createElement("span");
7796
oSpan.className = "button-group";
7797
nButtons = aButtons.length;
7799
this._aButtons = [];
7800
this.defaultHtmlButton = null;
7802
for (i = 0; i < nButtons; i++) {
7803
oButton = aButtons[i];
7806
oYUIButton = new Button({ label: oButton.text});
7807
oYUIButton.appendTo(oSpan);
7809
oButtonEl = oYUIButton.get("element");
7811
if (oButton.isDefault) {
7812
oYUIButton.addClass("default");
7813
this.defaultHtmlButton = oButtonEl;
7816
if (Lang.isFunction(oButton.handler)) {
7818
oYUIButton.set("onclick", {
7819
fn: oButton.handler,
7824
} else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
7826
oYUIButton.set("onclick", {
7827
fn: oButton.handler.fn,
7828
obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7829
scope: (oButton.handler.scope || this)
7834
this._aButtons[this._aButtons.length] = oYUIButton;
7838
oButtonEl = document.createElement("button");
7839
oButtonEl.setAttribute("type", "button");
7841
if (oButton.isDefault) {
7842
oButtonEl.className = "default";
7843
this.defaultHtmlButton = oButtonEl;
7846
oButtonEl.innerHTML = oButton.text;
7848
if (Lang.isFunction(oButton.handler)) {
7849
Event.on(oButtonEl, "click", oButton.handler, this, true);
7850
} else if (Lang.isObject(oButton.handler) &&
7851
Lang.isFunction(oButton.handler.fn)) {
7853
Event.on(oButtonEl, "click",
7855
((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7856
(oButton.handler.scope || this));
7859
oSpan.appendChild(oButtonEl);
7860
this._aButtons[this._aButtons.length] = oButtonEl;
7863
oButton.htmlButton = oButtonEl;
7866
this.firstButton = oButtonEl;
7869
if (i == (nButtons - 1)) {
7870
this.lastButton = oButtonEl;
7874
this.setFooter(oSpan);
7876
oFooter = this.footer;
7878
if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
7879
oInnerElement.appendChild(oFooter);
7882
this.buttonSpan = oSpan;
7884
} else { // Do cleanup
7885
oSpan = this.buttonSpan;
7886
oFooter = this.footer;
7887
if (oSpan && oFooter) {
7888
oFooter.removeChild(oSpan);
7889
this.buttonSpan = null;
7890
this.firstButton = null;
7891
this.lastButton = null;
7892
this.defaultHtmlButton = null;
7896
this.changeContentEvent.fire();
7900
* @method getButtons
7901
* @description Returns an array containing each of the Dialog's
7902
* buttons, by default an array of HTML <code><BUTTON></code>
7903
* elements. If the Dialog's buttons were created using the
7904
* YAHOO.widget.Button class (via the inclusion of the optional Button
7905
* dependancy on the page), an array of YAHOO.widget.Button instances
7909
getButtons: function () {
7910
return this._aButtons || null;
7915
* Sets focus to the first focusable element in the Dialog's form if found,
7916
* else, the default button if found, else the first button defined via the
7917
* "buttons" configuration property.
7920
* This method is invoked when the Dialog is made visible.
7922
* @method focusFirst
7924
focusFirst: function (type, args, obj) {
7926
var el = this.firstFormElement;
7928
if (args && args[1]) {
7929
Event.stopEvent(args[1]);
7935
} catch(oException) {
7939
if (this.defaultHtmlButton) {
7940
this.focusDefaultButton();
7942
this.focusFirstButton();
7948
* Sets focus to the last element in the Dialog's form or the last
7949
* button defined via the "buttons" configuration property.
7952
focusLast: function (type, args, obj) {
7954
var aButtons = this.cfg.getProperty("buttons"),
7955
el = this.lastFormElement;
7957
if (args && args[1]) {
7958
Event.stopEvent(args[1]);
7961
if (aButtons && Lang.isArray(aButtons)) {
7962
this.focusLastButton();
7967
} catch(oException) {
7975
* Helper method to normalize button references. It either returns the
7976
* YUI Button instance for the given element if found,
7977
* or the passes back the HTMLElement reference if a corresponding YUI Button
7978
* reference is not found or YAHOO.widget.Button does not exist on the page.
7980
* @method _getButton
7982
* @param {HTMLElement} button
7983
* @return {YAHOO.widget.Button|HTMLElement}
7985
_getButton : function(button) {
7986
var Button = YAHOO.widget.Button;
7988
// If we have an HTML button and YUI Button is on the page,
7989
// get the YUI Button reference if available.
7990
if (Button && button && button.nodeName && button.id) {
7991
button = Button.getButton(button.id) || button;
7998
* Sets the focus to the button that is designated as the default via
7999
* the "buttons" configuration property. By default, this method is
8000
* called when the Dialog is made visible.
8001
* @method focusDefaultButton
8003
focusDefaultButton: function () {
8004
var button = this._getButton(this.defaultHtmlButton);
8007
Place the call to the "focus" method inside a try/catch
8008
block to prevent IE from throwing JavaScript errors if
8009
the element is disabled or hidden.
8013
} catch(oException) {
8019
* Blurs all the buttons defined via the "buttons"
8020
* configuration property.
8021
* @method blurButtons
8023
blurButtons: function () {
8025
var aButtons = this.cfg.getProperty("buttons"),
8031
if (aButtons && Lang.isArray(aButtons)) {
8032
nButtons = aButtons.length;
8036
oButton = aButtons[i];
8038
oElement = this._getButton(oButton.htmlButton);
8041
Place the call to the "blur" method inside
8042
a try/catch block to prevent IE from
8043
throwing JavaScript errors if the element
8044
is disabled or hidden.
8048
} catch(oException) {
8059
* Sets the focus to the first button created via the "buttons"
8060
* configuration property.
8061
* @method focusFirstButton
8063
focusFirstButton: function () {
8065
var aButtons = this.cfg.getProperty("buttons"),
8069
if (aButtons && Lang.isArray(aButtons)) {
8070
oButton = aButtons[0];
8072
oElement = this._getButton(oButton.htmlButton);
8075
Place the call to the "focus" method inside a
8076
try/catch block to prevent IE from throwing
8077
JavaScript errors if the element is disabled
8082
} catch(oException) {
8091
* Sets the focus to the last button created via the "buttons"
8092
* configuration property.
8093
* @method focusLastButton
8095
focusLastButton: function () {
8097
var aButtons = this.cfg.getProperty("buttons"),
8102
if (aButtons && Lang.isArray(aButtons)) {
8103
nButtons = aButtons.length;
8105
oButton = aButtons[(nButtons - 1)];
8108
oElement = this._getButton(oButton.htmlButton);
8111
Place the call to the "focus" method inside a
8112
try/catch block to prevent IE from throwing
8113
JavaScript errors if the element is disabled
8119
} catch(oException) {
8129
* The default event handler for the "postmethod" configuration property
8130
* @method configPostMethod
8131
* @param {String} type The CustomEvent type (usually the property name)
8132
* @param {Object[]} args The CustomEvent arguments. For
8133
* configuration handlers, args[0] will equal the newly applied value
8135
* @param {Object} obj The scope object. For configuration handlers,
8136
* this will usually equal the owner.
8138
configPostMethod: function (type, args, obj) {
8139
this.registerForm();
8142
// END BUILT-IN PROPERTY EVENT HANDLERS //
8145
* Built-in function hook for writing a validation function that will
8146
* be checked for a "true" value prior to a submit. This function, as
8147
* implemented by default, always returns true, so it should be
8148
* overridden if validation is necessary.
8151
validate: function () {
8156
* Executes a submit of the Dialog if validation
8157
* is successful. By default the Dialog is hidden
8158
* after submission, but you can set the "hideaftersubmit"
8159
* configuration property to false, to prevent the Dialog
8160
* from being hidden.
8164
submit: function () {
8165
if (this.validate()) {
8166
this.beforeSubmitEvent.fire();
8168
this.submitEvent.fire();
8170
if (this.cfg.getProperty("hideaftersubmit")) {
8181
* Executes the cancel of the Dialog followed by a hide.
8184
cancel: function () {
8185
this.cancelEvent.fire();
8190
* Returns a JSON-compatible data structure representing the data
8191
* currently contained in the form.
8193
* @return {Object} A JSON object reprsenting the data of the
8196
getData: function () {
8198
var oForm = this.form,
8217
function isFormElement(p_oElement) {
8218
var sTag = p_oElement.tagName.toUpperCase();
8219
return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
8220
sTag == "SELECT") && p_oElement.name == sName);
8225
aElements = oForm.elements;
8226
nTotalElements = aElements.length;
8229
for (i = 0; i < nTotalElements; i++) {
8230
sName = aElements[i].name;
8233
Using "Dom.getElementsBy" to safeguard user from JS
8234
errors that result from giving a form field (or set of
8235
fields) the same name as a native method of a form
8236
(like "submit") or a DOM collection (such as the "item"
8237
method). Originally tried accessing fields via the
8238
"namedItem" method of the "element" collection, but
8239
discovered that it won't return a collection of fields
8243
oElement = Dom.getElementsBy(isFormElement, "*", oForm);
8244
nElements = oElement.length;
8246
if (nElements > 0) {
8247
if (nElements == 1) {
8248
oElement = oElement[0];
8250
sType = oElement.type;
8251
sTagName = oElement.tagName.toUpperCase();
8255
if (sType == "checkbox") {
8256
oData[sName] = oElement.checked;
8257
} else if (sType != "radio") {
8258
oData[sName] = oElement.value;
8263
oData[sName] = oElement.value;
8267
aOptions = oElement.options;
8268
nOptions = aOptions.length;
8271
for (n = 0; n < nOptions; n++) {
8272
oOption = aOptions[n];
8274
if (oOption.selected) {
8275
sValue = oOption.value;
8276
if (!sValue || sValue === "") {
8277
sValue = oOption.text;
8279
aValues[aValues.length] = sValue;
8282
oData[sName] = aValues;
8287
sType = oElement[0].type;
8290
for (n = 0; n < nElements; n++) {
8291
oRadio = oElement[n];
8292
if (oRadio.checked) {
8293
oData[sName] = oRadio.value;
8301
for (n = 0; n < nElements; n++) {
8302
oCheckbox = oElement[n];
8303
if (oCheckbox.checked) {
8304
aValues[aValues.length] = oCheckbox.value;
8307
oData[sName] = aValues;
8319
* Removes the Panel element from the DOM and sets all child elements
8323
destroy: function () {
8324
removeButtonEventHandlers.call(this);
8326
this._aButtons = null;
8328
var aForms = this.element.getElementsByTagName("form"),
8331
if (aForms.length > 0) {
8335
Event.purgeElement(oForm);
8336
if (oForm.parentNode) {
8337
oForm.parentNode.removeChild(oForm);
8342
Dialog.superclass.destroy.call(this);
8346
* Returns a string representation of the object.
8348
* @return {String} The string representation of the Dialog
8350
toString: function () {
8351
return "Dialog " + this.id;
8361
* SimpleDialog is a simple implementation of Dialog that can be used to
8362
* submit a single value. Forms can be processed in 3 ways -- via an
8363
* asynchronous Connection utility call, a simple form POST or GET,
8365
* @namespace YAHOO.widget
8366
* @class SimpleDialog
8367
* @extends YAHOO.widget.Dialog
8369
* @param {String} el The element ID representing the SimpleDialog
8371
* @param {HTMLElement} el The element representing the SimpleDialog
8372
* @param {Object} userConfig The configuration object literal containing
8373
* the configuration that should be set for this SimpleDialog. See
8374
* configuration documentation for more details.
8376
YAHOO.widget.SimpleDialog = function (el, userConfig) {
8378
YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
8383
var Dom = YAHOO.util.Dom,
8384
SimpleDialog = YAHOO.widget.SimpleDialog,
8387
* Constant representing the SimpleDialog's configuration properties
8388
* @property DEFAULT_CONFIG
8404
suppressEvent: true,
8405
supercedes: ["icon"]
8411
* Constant for the standard network icon for a blocking action
8412
* @property YAHOO.widget.SimpleDialog.ICON_BLOCK
8417
SimpleDialog.ICON_BLOCK = "blckicon";
8420
* Constant for the standard network icon for alarm
8421
* @property YAHOO.widget.SimpleDialog.ICON_ALARM
8426
SimpleDialog.ICON_ALARM = "alrticon";
8429
* Constant for the standard network icon for help
8430
* @property YAHOO.widget.SimpleDialog.ICON_HELP
8435
SimpleDialog.ICON_HELP = "hlpicon";
8438
* Constant for the standard network icon for info
8439
* @property YAHOO.widget.SimpleDialog.ICON_INFO
8444
SimpleDialog.ICON_INFO = "infoicon";
8447
* Constant for the standard network icon for warn
8448
* @property YAHOO.widget.SimpleDialog.ICON_WARN
8453
SimpleDialog.ICON_WARN = "warnicon";
8456
* Constant for the standard network icon for a tip
8457
* @property YAHOO.widget.SimpleDialog.ICON_TIP
8462
SimpleDialog.ICON_TIP = "tipicon";
8465
* Constant representing the name of the CSS class applied to the element
8466
* created by the "icon" configuration property.
8467
* @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
8472
SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
8475
* Constant representing the default CSS class used for a SimpleDialog
8476
* @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
8481
SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
8484
YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
8487
* Initializes the class's configurable properties which can be changed
8488
* using the SimpleDialog's Config object (cfg).
8489
* @method initDefaultConfig
8491
initDefaultConfig: function () {
8493
SimpleDialog.superclass.initDefaultConfig.call(this);
8495
// Add dialog config properties //
8498
* Sets the informational icon for the SimpleDialog
8503
this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
8504
handler: this.configIcon,
8505
value: DEFAULT_CONFIG.ICON.value,
8506
suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
8510
* Sets the text for the SimpleDialog
8515
this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
8516
handler: this.configText,
8517
value: DEFAULT_CONFIG.TEXT.value,
8518
suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
8519
supercedes: DEFAULT_CONFIG.TEXT.supercedes
8526
* The SimpleDialog initialization method, which is executed for
8527
* SimpleDialog and all of its subclasses. This method is automatically
8528
* called by the constructor, and sets up all DOM references for
8529
* pre-existing markup, and creates required markup if it is not
8532
* @param {String} el The element ID representing the SimpleDialog
8534
* @param {HTMLElement} el The element representing the SimpleDialog
8535
* @param {Object} userConfig The configuration object literal
8536
* containing the configuration that should be set for this
8537
* SimpleDialog. See configuration documentation for more details.
8539
init: function (el, userConfig) {
8542
Note that we don't pass the user config in here yet because we
8543
only want it executed once, at the lowest subclass level
8546
SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
8548
this.beforeInitEvent.fire(SimpleDialog);
8550
Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
8552
this.cfg.queueProperty("postmethod", "manual");
8555
this.cfg.applyConfig(userConfig, true);
8558
this.beforeRenderEvent.subscribe(function () {
8564
this.initEvent.fire(SimpleDialog);
8569
* Prepares the SimpleDialog's internal FORM object, creating one if one
8570
* is not currently present, and adding the value hidden field.
8571
* @method registerForm
8573
registerForm: function () {
8575
SimpleDialog.superclass.registerForm.call(this);
8577
this.form.innerHTML += "<input type=\"hidden\" name=\"" +
8578
this.id + "\" value=\"\"/>";
8582
// BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
8585
* Fired when the "icon" property is set.
8586
* @method configIcon
8587
* @param {String} type The CustomEvent type (usually the property name)
8588
* @param {Object[]} args The CustomEvent arguments. For configuration
8589
* handlers, args[0] will equal the newly applied value for the property.
8590
* @param {Object} obj The scope object. For configuration handlers,
8591
* this will usually equal the owner.
8593
configIcon: function (type,args,obj) {
8595
var sIcon = args[0],
8597
sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
8601
if (sIcon && sIcon != "none") {
8603
oIcon = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
8607
oIconParent = oIcon.parentNode;
8611
oIconParent.removeChild(oIcon);
8620
if (sIcon.indexOf(".") == -1) {
8622
oIcon = document.createElement("span");
8623
oIcon.className = (sCSSClass + " " + sIcon);
8624
oIcon.innerHTML = " ";
8628
oIcon = document.createElement("img");
8629
oIcon.src = (this.imageRoot + sIcon);
8630
oIcon.className = sCSSClass;
8637
oBody.insertBefore(oIcon, oBody.firstChild);
8646
* Fired when the "text" property is set.
8647
* @method configText
8648
* @param {String} type The CustomEvent type (usually the property name)
8649
* @param {Object[]} args The CustomEvent arguments. For configuration
8650
* handlers, args[0] will equal the newly applied value for the property.
8651
* @param {Object} obj The scope object. For configuration handlers,
8652
* this will usually equal the owner.
8654
configText: function (type,args,obj) {
8658
this.cfg.refireEvent("icon");
8662
// END BUILT-IN PROPERTY EVENT HANDLERS //
8665
* Returns a string representation of the object.
8667
* @return {String} The string representation of the SimpleDialog
8669
toString: function () {
8670
return "SimpleDialog " + this.id;
8675
* Sets the SimpleDialog's body content to the HTML specified.
8676
* If no body is present, one will be automatically created.
8677
* An empty string can be passed to the method to clear the contents of the body.
8679
* <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
8680
* and <a href="#config_icon">icon</a> configuration properties to set the contents
8681
* of it's body element in accordance with the UI design for a SimpleDialog (an
8682
* icon and message text). Calling setBody on the SimpleDialog will not enforce this
8683
* UI design constraint and will replace the entire contents of the SimpleDialog body.
8684
* It should only be used if you wish the replace the default icon/text body structure
8685
* of a SimpleDialog with your own custom markup.</p>
8688
* @param {String} bodyContent The HTML used to set the body.
8689
* As a convenience, non HTMLElement objects can also be passed into
8690
* the method, and will be treated as strings, with the body innerHTML
8691
* set to their default toString implementations.
8693
* @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
8695
* @param {DocumentFragment} bodyContent The document fragment
8696
* containing elements which are to be added to the body
8705
* ContainerEffect encapsulates animation transitions that are executed when
8706
* an Overlay is shown or hidden.
8707
* @namespace YAHOO.widget
8708
* @class ContainerEffect
8710
* @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
8711
* should be associated with
8712
* @param {Object} attrIn The object literal representing the animation
8713
* arguments to be used for the animate-in transition. The arguments for
8714
* this literal are: attributes(object, see YAHOO.util.Anim for description),
8715
* duration(Number), and method(i.e. Easing.easeIn).
8716
* @param {Object} attrOut The object literal representing the animation
8717
* arguments to be used for the animate-out transition. The arguments for
8718
* this literal are: attributes(object, see YAHOO.util.Anim for description),
8719
* duration(Number), and method(i.e. Easing.easeIn).
8720
* @param {HTMLElement} targetElement Optional. The target element that
8721
* should be animated during the transition. Defaults to overlay.element.
8722
* @param {class} Optional. The animation class to instantiate. Defaults to
8723
* YAHOO.util.Anim. Other options include YAHOO.util.Motion.
8725
YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
8728
animClass = YAHOO.util.Anim;
8732
* The overlay to animate
8734
* @type YAHOO.widget.Overlay
8736
this.overlay = overlay;
8739
* The animation attributes to use when transitioning into view
8743
this.attrIn = attrIn;
8746
* The animation attributes to use when transitioning out of view
8750
this.attrOut = attrOut;
8753
* The target element to be animated
8754
* @property targetElement
8757
this.targetElement = targetElement || overlay.element;
8760
* The animation class to use for animating the overlay
8761
* @property animClass
8764
this.animClass = animClass;
8769
var Dom = YAHOO.util.Dom,
8770
CustomEvent = YAHOO.util.CustomEvent,
8771
ContainerEffect = YAHOO.widget.ContainerEffect;
8775
* A pre-configured ContainerEffect instance that can be used for fading
8776
* an overlay in and out.
8779
* @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8780
* @param {Number} dur The duration of the animation
8781
* @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8783
ContainerEffect.FADE = function (overlay, dur) {
8785
var Easing = YAHOO.util.Easing,
8787
attributes: {opacity:{from:0, to:1}},
8789
method: Easing.easeIn
8792
attributes: {opacity:{to:0}},
8794
method: Easing.easeOut
8796
fade = new ContainerEffect(overlay, fin, fout, overlay.element);
8798
fade.handleUnderlayStart = function() {
8799
var underlay = this.overlay.underlay;
8800
if (underlay && YAHOO.env.ua.ie) {
8801
var hasFilters = (underlay.filters && underlay.filters.length > 0);
8803
Dom.addClass(overlay.element, "yui-effect-fade");
8808
fade.handleUnderlayComplete = function() {
8809
var underlay = this.overlay.underlay;
8810
if (underlay && YAHOO.env.ua.ie) {
8811
Dom.removeClass(overlay.element, "yui-effect-fade");
8815
fade.handleStartAnimateIn = function (type, args, obj) {
8816
Dom.addClass(obj.overlay.element, "hide-select");
8818
if (!obj.overlay.underlay) {
8819
obj.overlay.cfg.refireEvent("underlay");
8822
obj.handleUnderlayStart();
8824
obj.overlay._setDomVisibility(true);
8825
Dom.setStyle(obj.overlay.element, "opacity", 0);
8828
fade.handleCompleteAnimateIn = function (type,args,obj) {
8829
Dom.removeClass(obj.overlay.element, "hide-select");
8831
if (obj.overlay.element.style.filter) {
8832
obj.overlay.element.style.filter = null;
8835
obj.handleUnderlayComplete();
8837
obj.overlay.cfg.refireEvent("iframe");
8838
obj.animateInCompleteEvent.fire();
8841
fade.handleStartAnimateOut = function (type, args, obj) {
8842
Dom.addClass(obj.overlay.element, "hide-select");
8843
obj.handleUnderlayStart();
8846
fade.handleCompleteAnimateOut = function (type, args, obj) {
8847
Dom.removeClass(obj.overlay.element, "hide-select");
8848
if (obj.overlay.element.style.filter) {
8849
obj.overlay.element.style.filter = null;
8851
obj.overlay._setDomVisibility(false);
8852
Dom.setStyle(obj.overlay.element, "opacity", 1);
8854
obj.handleUnderlayComplete();
8856
obj.overlay.cfg.refireEvent("iframe");
8857
obj.animateOutCompleteEvent.fire();
8866
* A pre-configured ContainerEffect instance that can be used for sliding an
8867
* overlay in and out.
8870
* @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8871
* @param {Number} dur The duration of the animation
8872
* @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8874
ContainerEffect.SLIDE = function (overlay, dur) {
8875
var Easing = YAHOO.util.Easing,
8877
x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
8878
y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
8879
clientWidth = Dom.getClientWidth(),
8880
offsetWidth = overlay.element.offsetWidth,
8883
attributes: { points: { to: [x, y] } },
8885
method: Easing.easeIn
8889
attributes: { points: { to: [(clientWidth + 25), y] } },
8891
method: Easing.easeOut
8894
slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
8896
slide.handleStartAnimateIn = function (type,args,obj) {
8897
obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
8898
obj.overlay.element.style.top = y + "px";
8901
slide.handleTweenAnimateIn = function (type, args, obj) {
8903
var pos = Dom.getXY(obj.overlay.element),
8907
if (Dom.getStyle(obj.overlay.element, "visibility") ==
8908
"hidden" && currentX < x) {
8910
obj.overlay._setDomVisibility(true);
8914
obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
8915
obj.overlay.cfg.refireEvent("iframe");
8918
slide.handleCompleteAnimateIn = function (type, args, obj) {
8919
obj.overlay.cfg.setProperty("xy", [x, y], true);
8922
obj.overlay.cfg.refireEvent("iframe");
8923
obj.animateInCompleteEvent.fire();
8926
slide.handleStartAnimateOut = function (type, args, obj) {
8928
var vw = Dom.getViewportWidth(),
8929
pos = Dom.getXY(obj.overlay.element),
8932
obj.animOut.attributes.points.to = [(vw + 25), yso];
8935
slide.handleTweenAnimateOut = function (type, args, obj) {
8937
var pos = Dom.getXY(obj.overlay.element),
8941
obj.overlay.cfg.setProperty("xy", [xto, yto], true);
8942
obj.overlay.cfg.refireEvent("iframe");
8945
slide.handleCompleteAnimateOut = function (type, args, obj) {
8946
obj.overlay._setDomVisibility(false);
8948
obj.overlay.cfg.setProperty("xy", [x, y]);
8949
obj.animateOutCompleteEvent.fire();
8956
ContainerEffect.prototype = {
8959
* Initializes the animation classes and events.
8964
this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
8965
this.beforeAnimateInEvent.signature = CustomEvent.LIST;
8967
this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
8968
this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
8970
this.animateInCompleteEvent = this.createEvent("animateInComplete");
8971
this.animateInCompleteEvent.signature = CustomEvent.LIST;
8973
this.animateOutCompleteEvent =
8974
this.createEvent("animateOutComplete");
8975
this.animateOutCompleteEvent.signature = CustomEvent.LIST;
8977
this.animIn = new this.animClass(this.targetElement,
8978
this.attrIn.attributes, this.attrIn.duration,
8979
this.attrIn.method);
8981
this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
8982
this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
8984
this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
8987
this.animOut = new this.animClass(this.targetElement,
8988
this.attrOut.attributes, this.attrOut.duration,
8989
this.attrOut.method);
8991
this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
8992
this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
8993
this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
8999
* Triggers the in-animation.
9002
animateIn: function () {
9003
this.beforeAnimateInEvent.fire();
9004
this.animIn.animate();
9008
* Triggers the out-animation.
9009
* @method animateOut
9011
animateOut: function () {
9012
this.beforeAnimateOutEvent.fire();
9013
this.animOut.animate();
9017
* The default onStart handler for the in-animation.
9018
* @method handleStartAnimateIn
9019
* @param {String} type The CustomEvent type
9020
* @param {Object[]} args The CustomEvent arguments
9021
* @param {Object} obj The scope object
9023
handleStartAnimateIn: function (type, args, obj) { },
9026
* The default onTween handler for the in-animation.
9027
* @method handleTweenAnimateIn
9028
* @param {String} type The CustomEvent type
9029
* @param {Object[]} args The CustomEvent arguments
9030
* @param {Object} obj The scope object
9032
handleTweenAnimateIn: function (type, args, obj) { },
9035
* The default onComplete handler for the in-animation.
9036
* @method handleCompleteAnimateIn
9037
* @param {String} type The CustomEvent type
9038
* @param {Object[]} args The CustomEvent arguments
9039
* @param {Object} obj The scope object
9041
handleCompleteAnimateIn: function (type, args, obj) { },
9044
* The default onStart handler for the out-animation.
9045
* @method handleStartAnimateOut
9046
* @param {String} type The CustomEvent type
9047
* @param {Object[]} args The CustomEvent arguments
9048
* @param {Object} obj The scope object
9050
handleStartAnimateOut: function (type, args, obj) { },
9053
* The default onTween handler for the out-animation.
9054
* @method handleTweenAnimateOut
9055
* @param {String} type The CustomEvent type
9056
* @param {Object[]} args The CustomEvent arguments
9057
* @param {Object} obj The scope object
9059
handleTweenAnimateOut: function (type, args, obj) { },
9062
* The default onComplete handler for the out-animation.
9063
* @method handleCompleteAnimateOut
9064
* @param {String} type The CustomEvent type
9065
* @param {Object[]} args The CustomEvent arguments
9066
* @param {Object} obj The scope object
9068
handleCompleteAnimateOut: function (type, args, obj) { },
9071
* Returns a string representation of the object.
9073
* @return {String} The string representation of the ContainerEffect
9075
toString: function () {
9076
var output = "ContainerEffect";
9078
output += " [" + this.overlay.toString() + "]";
9084
YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
9088
YAHOO.register("container", YAHOO.widget.Module, {version: "2.7.0", build: "1799"});