Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('yui2-containercore', function(Y) {
2
    var YAHOO    = Y.YUI2;
3
    /*
4
Copyright (c) 2011, Yahoo! Inc. All rights reserved.
5
Code licensed under the BSD License:
6
http://developer.yahoo.com/yui/license.html
7
version: 2.9.0
8
*/
9
(function () {
10
 
11
    /**
12
    * Config is a utility used within an Object to allow the implementer to
13
    * maintain a list of local configuration properties and listen for changes
14
    * to those properties dynamically using CustomEvent. The initial values are
15
    * also maintained so that the configuration can be reset at any given point
16
    * to its initial state.
17
    * @namespace YAHOO.util
18
    * @class Config
19
    * @constructor
20
    * @param {Object} owner The owner Object to which this Config Object belongs
21
    */
22
    YAHOO.util.Config = function (owner) {
23
 
24
        if (owner) {
25
            this.init(owner);
26
        }
27
 
28
 
29
    };
30
 
31
 
32
    var Lang = YAHOO.lang,
33
        CustomEvent = YAHOO.util.CustomEvent,
34
        Config = YAHOO.util.Config;
35
 
36
 
37
    /**
38
     * Constant representing the CustomEvent type for the config changed event.
39
     * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
40
     * @private
41
     * @static
42
     * @final
43
     */
44
    Config.CONFIG_CHANGED_EVENT = "configChanged";
45
 
46
    /**
47
     * Constant representing the boolean type string
48
     * @property YAHOO.util.Config.BOOLEAN_TYPE
49
     * @private
50
     * @static
51
     * @final
52
     */
53
    Config.BOOLEAN_TYPE = "boolean";
54
 
55
    Config.prototype = {
56
 
57
        /**
58
        * Object reference to the owner of this Config Object
59
        * @property owner
60
        * @type Object
61
        */
62
        owner: null,
63
 
64
        /**
65
        * Boolean flag that specifies whether a queue is currently
66
        * being executed
67
        * @property queueInProgress
68
        * @type Boolean
69
        */
70
        queueInProgress: false,
71
 
72
        /**
73
        * Maintains the local collection of configuration property objects and
74
        * their specified values
75
        * @property config
76
        * @private
77
        * @type Object
78
        */
79
        config: null,
80
 
81
        /**
82
        * Maintains the local collection of configuration property objects as
83
        * they were initially applied.
84
        * This object is used when resetting a property.
85
        * @property initialConfig
86
        * @private
87
        * @type Object
88
        */
89
        initialConfig: null,
90
 
91
        /**
92
        * Maintains the local, normalized CustomEvent queue
93
        * @property eventQueue
94
        * @private
95
        * @type Object
96
        */
97
        eventQueue: null,
98
 
99
        /**
100
        * Custom Event, notifying subscribers when Config properties are set
101
        * (setProperty is called without the silent flag
102
        * @event configChangedEvent
103
        */
104
        configChangedEvent: null,
105
 
106
        /**
107
        * Initializes the configuration Object and all of its local members.
108
        * @method init
109
        * @param {Object} owner The owner Object to which this Config
110
        * Object belongs
111
        */
112
        init: function (owner) {
113
 
114
            this.owner = owner;
115
 
116
            this.configChangedEvent =
117
                this.createEvent(Config.CONFIG_CHANGED_EVENT);
118
 
119
            this.configChangedEvent.signature = CustomEvent.LIST;
120
            this.queueInProgress = false;
121
            this.config = {};
122
            this.initialConfig = {};
123
            this.eventQueue = [];
124
 
125
        },
126
 
127
        /**
128
        * Validates that the value passed in is a Boolean.
129
        * @method checkBoolean
130
        * @param {Object} val The value to validate
131
        * @return {Boolean} true, if the value is valid
132
        */
133
        checkBoolean: function (val) {
134
            return (typeof val == Config.BOOLEAN_TYPE);
135
        },
136
 
137
        /**
138
        * Validates that the value passed in is a number.
139
        * @method checkNumber
140
        * @param {Object} val The value to validate
141
        * @return {Boolean} true, if the value is valid
142
        */
143
        checkNumber: function (val) {
144
            return (!isNaN(val));
145
        },
146
 
147
        /**
148
        * Fires a configuration property event using the specified value.
149
        * @method fireEvent
150
        * @private
151
        * @param {String} key The configuration property's name
152
        * @param {value} Object The value of the correct type for the property
153
        */
154
        fireEvent: function ( key, value ) {
155
            var property = this.config[key];
156
 
157
            if (property && property.event) {
158
                property.event.fire(value);
159
            }
160
        },
161
 
162
        /**
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
168
        */
169
        addProperty: function ( key, propertyObject ) {
170
            key = key.toLowerCase();
171
 
172
            this.config[key] = propertyObject;
173
 
174
            propertyObject.event = this.createEvent(key, { scope: this.owner });
175
            propertyObject.event.signature = CustomEvent.LIST;
176
 
177
 
178
            propertyObject.key = key;
179
 
180
            if (propertyObject.handler) {
181
                propertyObject.event.subscribe(propertyObject.handler,
182
                    this.owner);
183
            }
184
 
185
            this.setProperty(key, propertyObject.value, true);
186
 
187
            if (! propertyObject.suppressEvent) {
188
                this.queueProperty(key, propertyObject.value);
189
            }
190
 
191
        },
192
 
193
        /**
194
        * Returns a key-value configuration map of the values currently set in
195
        * the Config Object.
196
        * @method getConfig
197
        * @return {Object} The current config, represented in a key-value map
198
        */
199
        getConfig: function () {
200
 
201
            var cfg = {},
202
                currCfg = this.config,
203
                prop,
204
                property;
205
 
206
            for (prop in currCfg) {
207
                if (Lang.hasOwnProperty(currCfg, prop)) {
208
                    property = currCfg[prop];
209
                    if (property && property.event) {
210
                        cfg[prop] = property.value;
211
                    }
212
                }
213
            }
214
 
215
            return cfg;
216
        },
217
 
218
        /**
219
        * Returns the value of specified property.
220
        * @method getProperty
221
        * @param {String} key The name of the property
222
        * @return {Object}  The value of the specified property
223
        */
224
        getProperty: function (key) {
225
            var property = this.config[key.toLowerCase()];
226
            if (property && property.event) {
227
                return property.value;
228
            } else {
229
                return undefined;
230
            }
231
        },
232
 
233
        /**
234
        * Resets the specified property's value to its initial value.
235
        * @method resetProperty
236
        * @param {String} key The name of the property
237
        * @return {Boolean} True is the property was reset, false if not
238
        */
239
        resetProperty: function (key) {
240
            key = key.toLowerCase();
241
 
242
            var property = this.config[key];
243
 
244
            if (property && property.event) {
245
                if (key in this.initialConfig) {
246
                    this.setProperty(key, this.initialConfig[key]);
247
                    return true;
248
                }
249
            } else {
250
                return false;
251
            }
252
        },
253
 
254
        /**
255
        * Sets the value of a property. If the silent property is passed as
256
        * true, the property's event will not be fired.
257
        * @method setProperty
258
        * @param {String} key The name of the property
259
        * @param {String} value The value to set the property to
260
        * @param {Boolean} silent Whether the value should be set silently,
261
        * without firing the property event.
262
        * @return {Boolean} True, if the set was successful, false if it failed.
263
        */
264
        setProperty: function (key, value, silent) {
265
 
266
            var property;
267
 
268
            key = key.toLowerCase();
269
 
270
            if (this.queueInProgress && ! silent) {
271
                // Currently running through a queue...
272
                this.queueProperty(key,value);
273
                return true;
274
 
275
            } else {
276
                property = this.config[key];
277
                if (property && property.event) {
278
                    if (property.validator && !property.validator(value)) {
279
                        return false;
280
                    } else {
281
                        property.value = value;
282
                        if (! silent) {
283
                            this.fireEvent(key, value);
284
                            this.configChangedEvent.fire([key, value]);
285
                        }
286
                        return true;
287
                    }
288
                } else {
289
                    return false;
290
                }
291
            }
292
        },
293
 
294
        /**
295
        * Sets the value of a property and queues its event to execute. If the
296
        * event is already scheduled to execute, it is
297
        * moved from its current position to the end of the queue.
298
        * @method queueProperty
299
        * @param {String} key The name of the property
300
        * @param {String} value The value to set the property to
301
        * @return {Boolean}  true, if the set was successful, false if
302
        * it failed.
303
        */
304
        queueProperty: function (key, value) {
305
 
306
            key = key.toLowerCase();
307
 
308
            var property = this.config[key],
309
                foundDuplicate = false,
310
                iLen,
311
                queueItem,
312
                queueItemKey,
313
                queueItemValue,
314
                sLen,
315
                supercedesCheck,
316
                qLen,
317
                queueItemCheck,
318
                queueItemCheckKey,
319
                queueItemCheckValue,
320
                i,
321
                s,
322
                q;
323
 
324
            if (property && property.event) {
325
 
326
                if (!Lang.isUndefined(value) && property.validator &&
327
                    !property.validator(value)) { // validator
328
                    return false;
329
                } else {
330
 
331
                    if (!Lang.isUndefined(value)) {
332
                        property.value = value;
333
                    } else {
334
                        value = property.value;
335
                    }
336
 
337
                    foundDuplicate = false;
338
                    iLen = this.eventQueue.length;
339
 
340
                    for (i = 0; i < iLen; i++) {
341
                        queueItem = this.eventQueue[i];
342
 
343
                        if (queueItem) {
344
                            queueItemKey = queueItem[0];
345
                            queueItemValue = queueItem[1];
346
 
347
                            if (queueItemKey == key) {
348
 
349
                                /*
350
                                    found a dupe... push to end of queue, null
351
                                    current item, and break
352
                                */
353
 
354
                                this.eventQueue[i] = null;
355
 
356
                                this.eventQueue.push(
357
                                    [key, (!Lang.isUndefined(value) ?
358
                                    value : queueItemValue)]);
359
 
360
                                foundDuplicate = true;
361
                                break;
362
                            }
363
                        }
364
                    }
365
 
366
                    // this is a refire, or a new property in the queue
367
 
368
                    if (! foundDuplicate && !Lang.isUndefined(value)) {
369
                        this.eventQueue.push([key, value]);
370
                    }
371
                }
372
 
373
                if (property.supercedes) {
374
 
375
                    sLen = property.supercedes.length;
376
 
377
                    for (s = 0; s < sLen; s++) {
378
 
379
                        supercedesCheck = property.supercedes[s];
380
                        qLen = this.eventQueue.length;
381
 
382
                        for (q = 0; q < qLen; q++) {
383
                            queueItemCheck = this.eventQueue[q];
384
 
385
                            if (queueItemCheck) {
386
                                queueItemCheckKey = queueItemCheck[0];
387
                                queueItemCheckValue = queueItemCheck[1];
388
 
389
                                if (queueItemCheckKey ==
390
                                    supercedesCheck.toLowerCase() ) {
391
 
392
                                    this.eventQueue.push([queueItemCheckKey,
393
                                        queueItemCheckValue]);
394
 
395
                                    this.eventQueue[q] = null;
396
                                    break;
397
 
398
                                }
399
                            }
400
                        }
401
                    }
402
                }
403
 
404
 
405
                return true;
406
            } else {
407
                return false;
408
            }
409
        },
410
 
411
        /**
412
        * Fires the event for a property using the property's current value.
413
        * @method refireEvent
414
        * @param {String} key The name of the property
415
        */
416
        refireEvent: function (key) {
417
 
418
            key = key.toLowerCase();
419
 
420
            var property = this.config[key];
421
 
422
            if (property && property.event &&
423
 
424
                !Lang.isUndefined(property.value)) {
425
 
426
                if (this.queueInProgress) {
427
 
428
                    this.queueProperty(key);
429
 
430
                } else {
431
 
432
                    this.fireEvent(key, property.value);
433
 
434
                }
435
 
436
            }
437
        },
438
 
439
        /**
440
        * Applies a key-value Object literal to the configuration, replacing
441
        * any existing values, and queueing the property events.
442
        * Although the values will be set, fireQueue() must be called for their
443
        * associated events to execute.
444
        * @method applyConfig
445
        * @param {Object} userConfig The configuration Object literal
446
        * @param {Boolean} init  When set to true, the initialConfig will
447
        * be set to the userConfig passed in, so that calling a reset will
448
        * reset the properties to the passed values.
449
        */
450
        applyConfig: function (userConfig, init) {
451
 
452
            var sKey,
453
                oConfig;
454
 
455
            if (init) {
456
                oConfig = {};
457
                for (sKey in userConfig) {
458
                    if (Lang.hasOwnProperty(userConfig, sKey)) {
459
                        oConfig[sKey.toLowerCase()] = userConfig[sKey];
460
                    }
461
                }
462
                this.initialConfig = oConfig;
463
            }
464
 
465
            for (sKey in userConfig) {
466
                if (Lang.hasOwnProperty(userConfig, sKey)) {
467
                    this.queueProperty(sKey, userConfig[sKey]);
468
                }
469
            }
470
        },
471
 
472
        /**
473
        * Refires the events for all configuration properties using their
474
        * current values.
475
        * @method refresh
476
        */
477
        refresh: function () {
478
 
479
            var prop;
480
 
481
            for (prop in this.config) {
482
                if (Lang.hasOwnProperty(this.config, prop)) {
483
                    this.refireEvent(prop);
484
                }
485
            }
486
        },
487
 
488
        /**
489
        * Fires the normalized list of queued property change events
490
        * @method fireQueue
491
        */
492
        fireQueue: function () {
493
 
494
            var i,
495
                queueItem,
496
                key,
497
                value,
498
                property;
499
 
500
            this.queueInProgress = true;
501
            for (i = 0;i < this.eventQueue.length; i++) {
502
                queueItem = this.eventQueue[i];
503
                if (queueItem) {
504
 
505
                    key = queueItem[0];
506
                    value = queueItem[1];
507
                    property = this.config[key];
508
 
509
                    property.value = value;
510
 
511
                    // Clear out queue entry, to avoid it being
512
                    // re-added to the queue by any queueProperty/supercedes
513
                    // calls which are invoked during fireEvent
514
                    this.eventQueue[i] = null;
515
 
516
                    this.fireEvent(key,value);
517
                }
518
            }
519
 
520
            this.queueInProgress = false;
521
            this.eventQueue = [];
522
        },
523
 
524
        /**
525
        * Subscribes an external handler to the change event for any
526
        * given property.
527
        * @method subscribeToConfigEvent
528
        * @param {String} key The property name
529
        * @param {Function} handler The handler function to use subscribe to
530
        * the property's event
531
        * @param {Object} obj The Object to use for scoping the event handler
532
        * (see CustomEvent documentation)
533
        * @param {Boolean} overrideContext Optional. If true, will override
534
        * "this" within the handler to map to the scope Object passed into the
535
        * method.
536
        * @return {Boolean} True, if the subscription was successful,
537
        * otherwise false.
538
        */
539
        subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
540
 
541
            var property = this.config[key.toLowerCase()];
542
 
543
            if (property && property.event) {
544
                if (!Config.alreadySubscribed(property.event, handler, obj)) {
545
                    property.event.subscribe(handler, obj, overrideContext);
546
                }
547
                return true;
548
            } else {
549
                return false;
550
            }
551
 
552
        },
553
 
554
        /**
555
        * Unsubscribes an external handler from the change event for any
556
        * given property.
557
        * @method unsubscribeFromConfigEvent
558
        * @param {String} key The property name
559
        * @param {Function} handler The handler function to use subscribe to
560
        * the property's event
561
        * @param {Object} obj The Object to use for scoping the event
562
        * handler (see CustomEvent documentation)
563
        * @return {Boolean} True, if the unsubscription was successful,
564
        * otherwise false.
565
        */
566
        unsubscribeFromConfigEvent: function (key, handler, obj) {
567
            var property = this.config[key.toLowerCase()];
568
            if (property && property.event) {
569
                return property.event.unsubscribe(handler, obj);
570
            } else {
571
                return false;
572
            }
573
        },
574
 
575
        /**
576
        * Returns a string representation of the Config object
577
        * @method toString
578
        * @return {String} The Config object in string format.
579
        */
580
        toString: function () {
581
            var output = "Config";
582
            if (this.owner) {
583
                output += " [" + this.owner.toString() + "]";
584
            }
585
            return output;
586
        },
587
 
588
        /**
589
        * Returns a string representation of the Config object's current
590
        * CustomEvent queue
591
        * @method outputEventQueue
592
        * @return {String} The string list of CustomEvents currently queued
593
        * for execution
594
        */
595
        outputEventQueue: function () {
596
 
597
            var output = "",
598
                queueItem,
599
                q,
600
                nQueue = this.eventQueue.length;
601
 
602
            for (q = 0; q < nQueue; q++) {
603
                queueItem = this.eventQueue[q];
604
                if (queueItem) {
605
                    output += queueItem[0] + "=" + queueItem[1] + ", ";
606
                }
607
            }
608
            return output;
609
        },
610
 
611
        /**
612
        * Sets all properties to null, unsubscribes all listeners from each
613
        * property's change event and all listeners from the configChangedEvent.
614
        * @method destroy
615
        */
616
        destroy: function () {
617
 
618
            var oConfig = this.config,
619
                sProperty,
620
                oProperty;
621
 
622
 
623
            for (sProperty in oConfig) {
624
 
625
                if (Lang.hasOwnProperty(oConfig, sProperty)) {
626
 
627
                    oProperty = oConfig[sProperty];
628
 
629
                    oProperty.event.unsubscribeAll();
630
                    oProperty.event = null;
631
 
632
                }
633
 
634
            }
635
 
636
            this.configChangedEvent.unsubscribeAll();
637
 
638
            this.configChangedEvent = null;
639
            this.owner = null;
640
            this.config = null;
641
            this.initialConfig = null;
642
            this.eventQueue = null;
643
 
644
        }
645
 
646
    };
647
 
648
 
649
 
650
    /**
651
    * Checks to determine if a particular function/Object pair are already
652
    * subscribed to the specified CustomEvent
653
    * @method YAHOO.util.Config.alreadySubscribed
654
    * @static
655
    * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
656
    * the subscriptions
657
    * @param {Function} fn The function to look for in the subscribers list
658
    * @param {Object} obj The execution scope Object for the subscription
659
    * @return {Boolean} true, if the function/Object pair is already subscribed
660
    * to the CustomEvent passed in
661
    */
662
    Config.alreadySubscribed = function (evt, fn, obj) {
663
 
664
        var nSubscribers = evt.subscribers.length,
665
            subsc,
666
            i;
667
 
668
        if (nSubscribers > 0) {
669
            i = nSubscribers - 1;
670
            do {
671
                subsc = evt.subscribers[i];
672
                if (subsc && subsc.obj == obj && subsc.fn == fn) {
673
                    return true;
674
                }
675
            }
676
            while (i--);
677
        }
678
 
679
        return false;
680
 
681
    };
682
 
683
    YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
684
 
685
}());
686
(function () {
687
 
688
    /**
689
    * The Container family of components is designed to enable developers to
690
    * create different kinds of content-containing modules on the web. Module
691
    * and Overlay are the most basic containers, and they can be used directly
692
    * or extended to build custom containers. Also part of the Container family
693
    * are four UI controls that extend Module and Overlay: Tooltip, Panel,
694
    * Dialog, and SimpleDialog.
695
    * @module container
696
    * @title Container
697
    * @requires yahoo, dom, event
698
    * @optional dragdrop, animation, button
699
    */
700
 
701
    /**
702
    * Module is a JavaScript representation of the Standard Module Format.
703
    * Standard Module Format is a simple standard for markup containers where
704
    * child nodes representing the header, body, and footer of the content are
705
    * denoted using the CSS classes "hd", "bd", and "ft" respectively.
706
    * Module is the base class for all other classes in the YUI
707
    * Container package.
708
    * @namespace YAHOO.widget
709
    * @class Module
710
    * @constructor
711
    * @param {String} el The element ID representing the Module <em>OR</em>
712
    * @param {HTMLElement} el The element representing the Module
713
    * @param {Object} userConfig The configuration Object literal containing
714
    * the configuration that should be set for this module. See configuration
715
    * documentation for more details.
716
    */
717
    YAHOO.widget.Module = function (el, userConfig) {
718
        if (el) {
719
            this.init(el, userConfig);
720
        } else {
721
        }
722
    };
723
 
724
    var Dom = YAHOO.util.Dom,
725
        Config = YAHOO.util.Config,
726
        Event = YAHOO.util.Event,
727
        CustomEvent = YAHOO.util.CustomEvent,
728
        Module = YAHOO.widget.Module,
729
        UA = YAHOO.env.ua,
730
 
731
        m_oModuleTemplate,
732
        m_oHeaderTemplate,
733
        m_oBodyTemplate,
734
        m_oFooterTemplate,
735
 
736
        /**
737
        * Constant representing the name of the Module's events
738
        * @property EVENT_TYPES
739
        * @private
740
        * @final
741
        * @type Object
742
        */
743
        EVENT_TYPES = {
744
            "BEFORE_INIT": "beforeInit",
745
            "INIT": "init",
746
            "APPEND": "append",
747
            "BEFORE_RENDER": "beforeRender",
748
            "RENDER": "render",
749
            "CHANGE_HEADER": "changeHeader",
750
            "CHANGE_BODY": "changeBody",
751
            "CHANGE_FOOTER": "changeFooter",
752
            "CHANGE_CONTENT": "changeContent",
753
            "DESTROY": "destroy",
754
            "BEFORE_SHOW": "beforeShow",
755
            "SHOW": "show",
756
            "BEFORE_HIDE": "beforeHide",
757
            "HIDE": "hide"
758
        },
759
 
760
        /**
761
        * Constant representing the Module's configuration properties
762
        * @property DEFAULT_CONFIG
763
        * @private
764
        * @final
765
        * @type Object
766
        */
767
        DEFAULT_CONFIG = {
768
 
769
            "VISIBLE": {
770
                key: "visible",
771
                value: true,
772
                validator: YAHOO.lang.isBoolean
773
            },
774
 
775
            "EFFECT": {
776
                key: "effect",
777
                suppressEvent: true,
778
                supercedes: ["visible"]
779
            },
780
 
781
            "MONITOR_RESIZE": {
782
                key: "monitorresize",
783
                value: true
784
            },
785
 
786
            "APPEND_TO_DOCUMENT_BODY": {
787
                key: "appendtodocumentbody",
788
                value: false
789
            }
790
        };
791
 
792
    /**
793
    * Constant representing the prefix path to use for non-secure images
794
    * @property YAHOO.widget.Module.IMG_ROOT
795
    * @static
796
    * @final
797
    * @type String
798
    */
799
    Module.IMG_ROOT = null;
800
 
801
    /**
802
    * Constant representing the prefix path to use for securely served images
803
    * @property YAHOO.widget.Module.IMG_ROOT_SSL
804
    * @static
805
    * @final
806
    * @type String
807
    */
808
    Module.IMG_ROOT_SSL = null;
809
 
810
    /**
811
    * Constant for the default CSS class name that represents a Module
812
    * @property YAHOO.widget.Module.CSS_MODULE
813
    * @static
814
    * @final
815
    * @type String
816
    */
817
    Module.CSS_MODULE = "yui-module";
818
 
819
    /**
820
    * CSS classname representing the module header. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
821
    * @property YAHOO.widget.Module.CSS_HEADER
822
    * @static
823
    * @final
824
    * @type String
825
    */
826
    Module.CSS_HEADER = "hd";
827
 
828
    /**
829
    * CSS classname representing the module body. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
830
    * @property YAHOO.widget.Module.CSS_BODY
831
    * @static
832
    * @final
833
    * @type String
834
    */
835
    Module.CSS_BODY = "bd";
836
 
837
    /**
838
    * CSS classname representing the module footer. NOTE: The classname is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
839
    * @property YAHOO.widget.Module.CSS_FOOTER
840
    * @static
841
    * @final
842
    * @type String
843
    */
844
    Module.CSS_FOOTER = "ft";
845
 
846
    /**
847
    * Constant representing the url for the "src" attribute of the iframe
848
    * used to monitor changes to the browser's base font size
849
    * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
850
    * @static
851
    * @final
852
    * @type String
853
    */
854
    Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
855
 
856
    /**
857
    * Constant representing the buffer amount (in pixels) to use when positioning
858
    * the text resize monitor offscreen. The resize monitor is positioned
859
    * offscreen by an amount eqaul to its offsetHeight + the buffer value.
860
    *
861
    * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
862
    * @static
863
    * @type Number
864
    */
865
    // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
866
    Module.RESIZE_MONITOR_BUFFER = 1;
867
 
868
    /**
869
    * Singleton CustomEvent fired when the font size is changed in the browser.
870
    * Opera's "zoom" functionality currently does not support text
871
    * size detection.
872
    * @event YAHOO.widget.Module.textResizeEvent
873
    */
874
    Module.textResizeEvent = new CustomEvent("textResize");
875
 
876
    /**
877
     * Helper utility method, which forces a document level
878
     * redraw for Opera, which can help remove repaint
879
     * irregularities after applying DOM changes.
880
     *
881
     * @method YAHOO.widget.Module.forceDocumentRedraw
882
     * @static
883
     */
884
    Module.forceDocumentRedraw = function() {
885
        var docEl = document.documentElement;
886
        if (docEl) {
887
            docEl.className += " ";
888
            docEl.className = YAHOO.lang.trim(docEl.className);
889
        }
890
    };
891
 
892
    function createModuleTemplate() {
893
 
894
        if (!m_oModuleTemplate) {
895
            m_oModuleTemplate = document.createElement("div");
896
 
897
            m_oModuleTemplate.innerHTML = ("<div class=\"" +
898
                Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
899
                Module.CSS_BODY + "\"></div><div class=\"" +
900
                Module.CSS_FOOTER + "\"></div>");
901
 
902
            m_oHeaderTemplate = m_oModuleTemplate.firstChild;
903
            m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
904
            m_oFooterTemplate = m_oBodyTemplate.nextSibling;
905
        }
906
 
907
        return m_oModuleTemplate;
908
    }
909
 
910
    function createHeader() {
911
        if (!m_oHeaderTemplate) {
912
            createModuleTemplate();
913
        }
914
        return (m_oHeaderTemplate.cloneNode(false));
915
    }
916
 
917
    function createBody() {
918
        if (!m_oBodyTemplate) {
919
            createModuleTemplate();
920
        }
921
        return (m_oBodyTemplate.cloneNode(false));
922
    }
923
 
924
    function createFooter() {
925
        if (!m_oFooterTemplate) {
926
            createModuleTemplate();
927
        }
928
        return (m_oFooterTemplate.cloneNode(false));
929
    }
930
 
931
    Module.prototype = {
932
 
933
        /**
934
        * The class's constructor function
935
        * @property contructor
936
        * @type Function
937
        */
938
        constructor: Module,
939
 
940
        /**
941
        * The main module element that contains the header, body, and footer
942
        * @property element
943
        * @type HTMLElement
944
        */
945
        element: null,
946
 
947
        /**
948
        * The header element, denoted with CSS class "hd"
949
        * @property header
950
        * @type HTMLElement
951
        */
952
        header: null,
953
 
954
        /**
955
        * The body element, denoted with CSS class "bd"
956
        * @property body
957
        * @type HTMLElement
958
        */
959
        body: null,
960
 
961
        /**
962
        * The footer element, denoted with CSS class "ft"
963
        * @property footer
964
        * @type HTMLElement
965
        */
966
        footer: null,
967
 
968
        /**
969
        * The id of the element
970
        * @property id
971
        * @type String
972
        */
973
        id: null,
974
 
975
        /**
976
        * A string representing the root path for all images created by
977
        * a Module instance.
978
        * @deprecated It is recommend that any images for a Module be applied
979
        * via CSS using the "background-image" property.
980
        * @property imageRoot
981
        * @type String
982
        */
983
        imageRoot: Module.IMG_ROOT,
984
 
985
        /**
986
        * Initializes the custom events for Module which are fired
987
        * automatically at appropriate times by the Module class.
988
        * @method initEvents
989
        */
990
        initEvents: function () {
991
 
992
            var SIGNATURE = CustomEvent.LIST;
993
 
994
            /**
995
            * CustomEvent fired prior to class initalization.
996
            * @event beforeInitEvent
997
            * @param {class} classRef class reference of the initializing
998
            * class, such as this.beforeInitEvent.fire(Module)
999
            */
1000
            this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1001
            this.beforeInitEvent.signature = SIGNATURE;
1002
 
1003
            /**
1004
            * CustomEvent fired after class initalization.
1005
            * @event initEvent
1006
            * @param {class} classRef class reference of the initializing
1007
            * class, such as this.beforeInitEvent.fire(Module)
1008
            */
1009
            this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1010
            this.initEvent.signature = SIGNATURE;
1011
 
1012
            /**
1013
            * CustomEvent fired when the Module is appended to the DOM
1014
            * @event appendEvent
1015
            */
1016
            this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1017
            this.appendEvent.signature = SIGNATURE;
1018
 
1019
            /**
1020
            * CustomEvent fired before the Module is rendered
1021
            * @event beforeRenderEvent
1022
            */
1023
            this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1024
            this.beforeRenderEvent.signature = SIGNATURE;
1025
 
1026
            /**
1027
            * CustomEvent fired after the Module is rendered
1028
            * @event renderEvent
1029
            */
1030
            this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1031
            this.renderEvent.signature = SIGNATURE;
1032
 
1033
            /**
1034
            * CustomEvent fired when the header content of the Module
1035
            * is modified
1036
            * @event changeHeaderEvent
1037
            * @param {String/HTMLElement} content String/element representing
1038
            * the new header content
1039
            */
1040
            this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1041
            this.changeHeaderEvent.signature = SIGNATURE;
1042
 
1043
            /**
1044
            * CustomEvent fired when the body content of the Module is modified
1045
            * @event changeBodyEvent
1046
            * @param {String/HTMLElement} content String/element representing
1047
            * the new body content
1048
            */
1049
            this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1050
            this.changeBodyEvent.signature = SIGNATURE;
1051
 
1052
            /**
1053
            * CustomEvent fired when the footer content of the Module
1054
            * is modified
1055
            * @event changeFooterEvent
1056
            * @param {String/HTMLElement} content String/element representing
1057
            * the new footer content
1058
            */
1059
            this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1060
            this.changeFooterEvent.signature = SIGNATURE;
1061
 
1062
            /**
1063
            * CustomEvent fired when the content of the Module is modified
1064
            * @event changeContentEvent
1065
            */
1066
            this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1067
            this.changeContentEvent.signature = SIGNATURE;
1068
 
1069
            /**
1070
            * CustomEvent fired when the Module is destroyed
1071
            * @event destroyEvent
1072
            */
1073
            this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
1074
            this.destroyEvent.signature = SIGNATURE;
1075
 
1076
            /**
1077
            * CustomEvent fired before the Module is shown
1078
            * @event beforeShowEvent
1079
            */
1080
            this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1081
            this.beforeShowEvent.signature = SIGNATURE;
1082
 
1083
            /**
1084
            * CustomEvent fired after the Module is shown
1085
            * @event showEvent
1086
            */
1087
            this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1088
            this.showEvent.signature = SIGNATURE;
1089
 
1090
            /**
1091
            * CustomEvent fired before the Module is hidden
1092
            * @event beforeHideEvent
1093
            */
1094
            this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1095
            this.beforeHideEvent.signature = SIGNATURE;
1096
 
1097
            /**
1098
            * CustomEvent fired after the Module is hidden
1099
            * @event hideEvent
1100
            */
1101
            this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1102
            this.hideEvent.signature = SIGNATURE;
1103
        },
1104
 
1105
        /**
1106
        * String identifying whether the current platform is windows or mac. This property
1107
        * currently only identifies these 2 platforms, and returns false otherwise.
1108
        * @property platform
1109
        * @deprecated Use YAHOO.env.ua
1110
        * @type {String|Boolean}
1111
        */
1112
        platform: function () {
1113
            var ua = navigator.userAgent.toLowerCase();
1114
 
1115
            if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1116
                return "windows";
1117
            } else if (ua.indexOf("macintosh") != -1) {
1118
                return "mac";
1119
            } else {
1120
                return false;
1121
            }
1122
        }(),
1123
 
1124
        /**
1125
        * String representing the user-agent of the browser
1126
        * @deprecated Use YAHOO.env.ua
1127
        * @property browser
1128
        * @type {String|Boolean}
1129
        */
1130
        browser: function () {
1131
            var ua = navigator.userAgent.toLowerCase();
1132
            /*
1133
                 Check Opera first in case of spoof and check Safari before
1134
                 Gecko since Safari's user agent string includes "like Gecko"
1135
            */
1136
            if (ua.indexOf('opera') != -1) {
1137
                return 'opera';
1138
            } else if (ua.indexOf('msie 7') != -1) {
1139
                return 'ie7';
1140
            } else if (ua.indexOf('msie') != -1) {
1141
                return 'ie';
1142
            } else if (ua.indexOf('safari') != -1) {
1143
                return 'safari';
1144
            } else if (ua.indexOf('gecko') != -1) {
1145
                return 'gecko';
1146
            } else {
1147
                return false;
1148
            }
1149
        }(),
1150
 
1151
        /**
1152
        * Boolean representing whether or not the current browsing context is
1153
        * secure (https)
1154
        * @property isSecure
1155
        * @type Boolean
1156
        */
1157
        isSecure: function () {
1158
            if (window.location.href.toLowerCase().indexOf("https") === 0) {
1159
                return true;
1160
            } else {
1161
                return false;
1162
            }
1163
        }(),
1164
 
1165
        /**
1166
        * Initializes the custom events for Module which are fired
1167
        * automatically at appropriate times by the Module class.
1168
        */
1169
        initDefaultConfig: function () {
1170
            // Add properties //
1171
            /**
1172
            * Specifies whether the Module is visible on the page.
1173
            * @config visible
1174
            * @type Boolean
1175
            * @default true
1176
            */
1177
            this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1178
                handler: this.configVisible,
1179
                value: DEFAULT_CONFIG.VISIBLE.value,
1180
                validator: DEFAULT_CONFIG.VISIBLE.validator
1181
            });
1182
 
1183
            /**
1184
            * <p>
1185
            * Object or array of objects representing the ContainerEffect
1186
            * classes that are active for animating the container.
1187
            * </p>
1188
            * <p>
1189
            * <strong>NOTE:</strong> Although this configuration
1190
            * property is introduced at the Module level, an out of the box
1191
            * implementation is not shipped for the Module class so setting
1192
            * the proroperty on the Module class has no effect. The Overlay
1193
            * class is the first class to provide out of the box ContainerEffect
1194
            * support.
1195
            * </p>
1196
            * @config effect
1197
            * @type Object
1198
            * @default null
1199
            */
1200
            this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1201
                handler: this.configEffect,
1202
                suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1203
                supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1204
            });
1205
 
1206
            /**
1207
            * Specifies whether to create a special proxy iframe to monitor
1208
            * for user font resizing in the document
1209
            * @config monitorresize
1210
            * @type Boolean
1211
            * @default true
1212
            */
1213
            this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1214
                handler: this.configMonitorResize,
1215
                value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1216
            });
1217
 
1218
            /**
1219
            * Specifies if the module should be rendered as the first child
1220
            * of document.body or appended as the last child when render is called
1221
            * with document.body as the "appendToNode".
1222
            * <p>
1223
            * Appending to the body while the DOM is still being constructed can
1224
            * lead to Operation Aborted errors in IE hence this flag is set to
1225
            * false by default.
1226
            * </p>
1227
            *
1228
            * @config appendtodocumentbody
1229
            * @type Boolean
1230
            * @default false
1231
            */
1232
            this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1233
                value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1234
            });
1235
        },
1236
 
1237
        /**
1238
        * The Module class's initialization method, which is executed for
1239
        * Module and all of its subclasses. This method is automatically
1240
        * called by the constructor, and  sets up all DOM references for
1241
        * pre-existing markup, and creates required markup if it is not
1242
        * already present.
1243
        * <p>
1244
        * If the element passed in does not have an id, one will be generated
1245
        * for it.
1246
        * </p>
1247
        * @method init
1248
        * @param {String} el The element ID representing the Module <em>OR</em>
1249
        * @param {HTMLElement} el The element representing the Module
1250
        * @param {Object} userConfig The configuration Object literal
1251
        * containing the configuration that should be set for this module.
1252
        * See configuration documentation for more details.
1253
        */
1254
        init: function (el, userConfig) {
1255
 
1256
            var elId, child;
1257
 
1258
            this.initEvents();
1259
            this.beforeInitEvent.fire(Module);
1260
 
1261
            /**
1262
            * The Module's Config object used for monitoring
1263
            * configuration properties.
1264
            * @property cfg
1265
            * @type YAHOO.util.Config
1266
            */
1267
            this.cfg = new Config(this);
1268
 
1269
            if (this.isSecure) {
1270
                this.imageRoot = Module.IMG_ROOT_SSL;
1271
            }
1272
 
1273
            if (typeof el == "string") {
1274
                elId = el;
1275
                el = document.getElementById(el);
1276
                if (! el) {
1277
                    el = (createModuleTemplate()).cloneNode(false);
1278
                    el.id = elId;
1279
                }
1280
            }
1281
 
1282
            this.id = Dom.generateId(el);
1283
            this.element = el;
1284
 
1285
            child = this.element.firstChild;
1286
 
1287
            if (child) {
1288
                var fndHd = false, fndBd = false, fndFt = false;
1289
                do {
1290
                    // We're looking for elements
1291
                    if (1 == child.nodeType) {
1292
                        if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1293
                            this.header = child;
1294
                            fndHd = true;
1295
                        } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1296
                            this.body = child;
1297
                            fndBd = true;
1298
                        } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1299
                            this.footer = child;
1300
                            fndFt = true;
1301
                        }
1302
                    }
1303
                } while ((child = child.nextSibling));
1304
            }
1305
 
1306
            this.initDefaultConfig();
1307
 
1308
            Dom.addClass(this.element, Module.CSS_MODULE);
1309
 
1310
            if (userConfig) {
1311
                this.cfg.applyConfig(userConfig, true);
1312
            }
1313
 
1314
            /*
1315
                Subscribe to the fireQueue() method of Config so that any
1316
                queued configuration changes are excecuted upon render of
1317
                the Module
1318
            */
1319
 
1320
            if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1321
                this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1322
            }
1323
 
1324
            this.initEvent.fire(Module);
1325
        },
1326
 
1327
        /**
1328
        * Initialize an empty IFRAME that is placed out of the visible area
1329
        * that can be used to detect text resize.
1330
        * @method initResizeMonitor
1331
        */
1332
        initResizeMonitor: function () {
1333
 
1334
            var isGeckoWin = (UA.gecko && this.platform == "windows");
1335
            if (isGeckoWin) {
1336
                // Help prevent spinning loading icon which
1337
                // started with FireFox 2.0.0.8/Win
1338
                var self = this;
1339
                setTimeout(function(){self._initResizeMonitor();}, 0);
1340
            } else {
1341
                this._initResizeMonitor();
1342
            }
1343
        },
1344
 
1345
        /**
1346
         * Create and initialize the text resize monitoring iframe.
1347
         *
1348
         * @protected
1349
         * @method _initResizeMonitor
1350
         */
1351
        _initResizeMonitor : function() {
1352
 
1353
            var oDoc,
1354
                oIFrame,
1355
                sHTML;
1356
 
1357
            function fireTextResize() {
1358
                Module.textResizeEvent.fire();
1359
            }
1360
 
1361
            if (!UA.opera) {
1362
                oIFrame = Dom.get("_yuiResizeMonitor");
1363
 
1364
                var supportsCWResize = this._supportsCWResize();
1365
 
1366
                if (!oIFrame) {
1367
                    oIFrame = document.createElement("iframe");
1368
 
1369
                    if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1370
                        oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1371
                    }
1372
 
1373
                    if (!supportsCWResize) {
1374
                        // Can't monitor on contentWindow, so fire from inside iframe
1375
                        sHTML = ["<html><head><script ",
1376
                                 "type=\"text/javascript\">",
1377
                                 "window.onresize=function(){window.parent.",
1378
                                 "YAHOO.widget.Module.textResizeEvent.",
1379
                                 "fire();};<",
1380
                                 "\/script></head>",
1381
                                 "<body></body></html>"].join('');
1382
 
1383
                        oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1384
                    }
1385
 
1386
                    oIFrame.id = "_yuiResizeMonitor";
1387
                    oIFrame.title = "Text Resize Monitor";
1388
                    oIFrame.tabIndex = -1;
1389
                    oIFrame.setAttribute("role", "presentation");
1390
 
1391
                    /*
1392
                        Need to set "position" property before inserting the
1393
                        iframe into the document or Safari's status bar will
1394
                        forever indicate the iframe is loading
1395
                        (See YUILibrary bug #1723064)
1396
                    */
1397
                    oIFrame.style.position = "absolute";
1398
                    oIFrame.style.visibility = "hidden";
1399
 
1400
                    var db = document.body,
1401
                        fc = db.firstChild;
1402
                    if (fc) {
1403
                        db.insertBefore(oIFrame, fc);
1404
                    } else {
1405
                        db.appendChild(oIFrame);
1406
                    }
1407
 
1408
                    // Setting the background color fixes an issue with IE6/IE7, where
1409
                    // elements in the DOM, with -ve margin-top which positioned them
1410
                    // offscreen (so they would be overlapped by the iframe and its -ve top
1411
                    // setting), would have their -ve margin-top ignored, when the iframe
1412
                    // was added.
1413
                    oIFrame.style.backgroundColor = "transparent";
1414
 
1415
                    oIFrame.style.borderWidth = "0";
1416
                    oIFrame.style.width = "2em";
1417
                    oIFrame.style.height = "2em";
1418
                    oIFrame.style.left = "0";
1419
                    oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1420
                    oIFrame.style.visibility = "visible";
1421
 
1422
                    /*
1423
                       Don't open/close the document for Gecko like we used to, since it
1424
                       leads to duplicate cookies. (See YUILibrary bug #1721755)
1425
                    */
1426
                    if (UA.webkit) {
1427
                        oDoc = oIFrame.contentWindow.document;
1428
                        oDoc.open();
1429
                        oDoc.close();
1430
                    }
1431
                }
1432
 
1433
                if (oIFrame && oIFrame.contentWindow) {
1434
                    Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1435
 
1436
                    if (!Module.textResizeInitialized) {
1437
                        if (supportsCWResize) {
1438
                            if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1439
                                /*
1440
                                     This will fail in IE if document.domain has
1441
                                     changed, so we must change the listener to
1442
                                     use the oIFrame element instead
1443
                                */
1444
                                Event.on(oIFrame, "resize", fireTextResize);
1445
                            }
1446
                        }
1447
                        Module.textResizeInitialized = true;
1448
                    }
1449
                    this.resizeMonitor = oIFrame;
1450
                }
1451
            }
1452
        },
1453
 
1454
        /**
1455
         * Text resize monitor helper method.
1456
         * Determines if the browser supports resize events on iframe content windows.
1457
         *
1458
         * @private
1459
         * @method _supportsCWResize
1460
         */
1461
        _supportsCWResize : function() {
1462
            /*
1463
                Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1464
                Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1465
 
1466
                We don't want to start sniffing for patch versions, so fire textResize the same
1467
                way on all FF2 flavors
1468
             */
1469
            var bSupported = true;
1470
            if (UA.gecko && UA.gecko <= 1.8) {
1471
                bSupported = false;
1472
            }
1473
            return bSupported;
1474
        },
1475
 
1476
        /**
1477
        * Event handler fired when the resize monitor element is resized.
1478
        * @method onDomResize
1479
        * @param {DOMEvent} e The DOM resize event
1480
        * @param {Object} obj The scope object passed to the handler
1481
        */
1482
        onDomResize: function (e, obj) {
1483
 
1484
            var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1485
 
1486
            this.resizeMonitor.style.top = nTop + "px";
1487
            this.resizeMonitor.style.left = "0";
1488
        },
1489
 
1490
        /**
1491
        * Sets the Module's header content to the markup specified, or appends
1492
        * the passed element to the header.
1493
        *
1494
        * 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.
1497
        *
1498
        * @method setHeader
1499
        * @param {HTML} headerContent The markup used to set the header content.
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.
1503
        *
1504
        * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1505
        *
1506
        * <em>OR</em>
1507
        * @param {HTMLElement} headerContent The HTMLElement to append to
1508
        * <em>OR</em>
1509
        * @param {DocumentFragment} headerContent The document fragment
1510
        * containing elements which are to be added to the header
1511
        */
1512
        setHeader: function (headerContent) {
1513
            var oHeader = this.header || (this.header = createHeader());
1514
 
1515
            if (headerContent.nodeName) {
1516
                oHeader.innerHTML = "";
1517
                oHeader.appendChild(headerContent);
1518
            } else {
1519
                oHeader.innerHTML = headerContent;
1520
            }
1521
 
1522
            if (this._rendered) {
1523
                this._renderHeader();
1524
            }
1525
 
1526
            this.changeHeaderEvent.fire(headerContent);
1527
            this.changeContentEvent.fire();
1528
 
1529
        },
1530
 
1531
        /**
1532
        * Appends the passed element to the header. If no header is present,
1533
        * one will be automatically created.
1534
        * @method appendToHeader
1535
        * @param {HTMLElement | DocumentFragment} element The element to
1536
        * append to the header. In the case of a document fragment, the
1537
        * children of the fragment will be appended to the header.
1538
        */
1539
        appendToHeader: function (element) {
1540
            var oHeader = this.header || (this.header = createHeader());
1541
 
1542
            oHeader.appendChild(element);
1543
 
1544
            this.changeHeaderEvent.fire(element);
1545
            this.changeContentEvent.fire();
1546
 
1547
        },
1548
 
1549
        /**
1550
        * Sets the Module's body content to the HTML specified.
1551
        *
1552
        * If no body is present, one will be automatically created.
1553
        *
1554
        * An empty string can be passed to the method to clear the contents of the body.
1555
        * @method setBody
1556
        * @param {HTML} bodyContent The HTML used to set the body content
1557
        * As a convenience, non HTMLElement objects can also be passed into
1558
        * the method, and will be treated as strings, with the body innerHTML
1559
        * set to their default toString implementations.
1560
        *
1561
        * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1562
        *
1563
        * <em>OR</em>
1564
        * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1565
        * child of the body element.
1566
        * <em>OR</em>
1567
        * @param {DocumentFragment} bodyContent The document fragment
1568
        * containing elements which are to be added to the body
1569
        */
1570
        setBody: function (bodyContent) {
1571
            var oBody = this.body || (this.body = createBody());
1572
 
1573
            if (bodyContent.nodeName) {
1574
                oBody.innerHTML = "";
1575
                oBody.appendChild(bodyContent);
1576
            } else {
1577
                oBody.innerHTML = bodyContent;
1578
            }
1579
 
1580
            if (this._rendered) {
1581
                this._renderBody();
1582
            }
1583
 
1584
            this.changeBodyEvent.fire(bodyContent);
1585
            this.changeContentEvent.fire();
1586
        },
1587
 
1588
        /**
1589
        * Appends the passed element to the body. If no body is present, one
1590
        * will be automatically created.
1591
        * @method appendToBody
1592
        * @param {HTMLElement | DocumentFragment} element The element to
1593
        * append to the body. In the case of a document fragment, the
1594
        * children of the fragment will be appended to the body.
1595
        *
1596
        */
1597
        appendToBody: function (element) {
1598
            var oBody = this.body || (this.body = createBody());
1599
 
1600
            oBody.appendChild(element);
1601
 
1602
            this.changeBodyEvent.fire(element);
1603
            this.changeContentEvent.fire();
1604
 
1605
        },
1606
 
1607
        /**
1608
        * Sets the Module's footer content to the HTML specified, or appends
1609
        * the passed element to the footer. If no footer is present, one will
1610
        * be automatically created. An empty string can be passed to the method
1611
        * to clear the contents of the footer.
1612
        * @method setFooter
1613
        * @param {HTML} footerContent The HTML used to set the footer
1614
        * As a convenience, non HTMLElement objects can also be passed into
1615
        * the method, and will be treated as strings, with the footer innerHTML
1616
        * set to their default toString implementations.
1617
        *
1618
        * <p>NOTE: Markup passed into this method is added to the DOM as HTML, and should be escaped by the implementor if coming from an external source.</p>
1619
        *
1620
        * <em>OR</em>
1621
        * @param {HTMLElement} footerContent The HTMLElement to append to
1622
        * the footer
1623
        * <em>OR</em>
1624
        * @param {DocumentFragment} footerContent The document fragment containing
1625
        * elements which are to be added to the footer
1626
        */
1627
        setFooter: function (footerContent) {
1628
 
1629
            var oFooter = this.footer || (this.footer = createFooter());
1630
 
1631
            if (footerContent.nodeName) {
1632
                oFooter.innerHTML = "";
1633
                oFooter.appendChild(footerContent);
1634
            } else {
1635
                oFooter.innerHTML = footerContent;
1636
            }
1637
 
1638
            if (this._rendered) {
1639
                this._renderFooter();
1640
            }
1641
 
1642
            this.changeFooterEvent.fire(footerContent);
1643
            this.changeContentEvent.fire();
1644
        },
1645
 
1646
        /**
1647
        * Appends the passed element to the footer. If no footer is present,
1648
        * one will be automatically created.
1649
        * @method appendToFooter
1650
        * @param {HTMLElement | DocumentFragment} element The element to
1651
        * append to the footer. In the case of a document fragment, the
1652
        * children of the fragment will be appended to the footer
1653
        */
1654
        appendToFooter: function (element) {
1655
 
1656
            var oFooter = this.footer || (this.footer = createFooter());
1657
 
1658
            oFooter.appendChild(element);
1659
 
1660
            this.changeFooterEvent.fire(element);
1661
            this.changeContentEvent.fire();
1662
 
1663
        },
1664
 
1665
        /**
1666
        * Renders the Module by inserting the elements that are not already
1667
        * in the main Module into their correct places. Optionally appends
1668
        * the Module to the specified node prior to the render's execution.
1669
        * <p>
1670
        * For Modules without existing markup, the appendToNode argument
1671
        * is REQUIRED. If this argument is ommitted and the current element is
1672
        * not present in the document, the function will return false,
1673
        * indicating that the render was a failure.
1674
        * </p>
1675
        * <p>
1676
        * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1677
        * then the module is rendered as the first child of the body element,
1678
        * and not appended to it, to avoid Operation Aborted errors in IE when
1679
        * rendering the module before window's load event is fired. You can
1680
        * use the appendtodocumentbody configuration property to change this
1681
        * to append to document.body if required.
1682
        * </p>
1683
        * @method render
1684
        * @param {String} appendToNode The element id to which the Module
1685
        * should be appended to prior to rendering <em>OR</em>
1686
        * @param {HTMLElement} appendToNode The element to which the Module
1687
        * should be appended to prior to rendering
1688
        * @param {HTMLElement} moduleElement OPTIONAL. The element that
1689
        * represents the actual Standard Module container.
1690
        * @return {Boolean} Success or failure of the render
1691
        */
1692
        render: function (appendToNode, moduleElement) {
1693
 
1694
            var me = this;
1695
 
1696
            function appendTo(parentNode) {
1697
                if (typeof parentNode == "string") {
1698
                    parentNode = document.getElementById(parentNode);
1699
                }
1700
 
1701
                if (parentNode) {
1702
                    me._addToParent(parentNode, me.element);
1703
                    me.appendEvent.fire();
1704
                }
1705
            }
1706
 
1707
            this.beforeRenderEvent.fire();
1708
 
1709
            if (! moduleElement) {
1710
                moduleElement = this.element;
1711
            }
1712
 
1713
            if (appendToNode) {
1714
                appendTo(appendToNode);
1715
            } else {
1716
                // No node was passed in. If the element is not already in the Dom, this fails
1717
                if (! Dom.inDocument(this.element)) {
1718
                    return false;
1719
                }
1720
            }
1721
 
1722
            this._renderHeader(moduleElement);
1723
            this._renderBody(moduleElement);
1724
            this._renderFooter(moduleElement);
1725
 
1726
            this._rendered = true;
1727
 
1728
            this.renderEvent.fire();
1729
            return true;
1730
        },
1731
 
1732
        /**
1733
         * Renders the currently set header into it's proper position under the
1734
         * module element. If the module element is not provided, "this.element"
1735
         * is used.
1736
         *
1737
         * @method _renderHeader
1738
         * @protected
1739
         * @param {HTMLElement} moduleElement Optional. A reference to the module element
1740
         */
1741
        _renderHeader: function(moduleElement){
1742
            moduleElement = moduleElement || this.element;
1743
 
1744
            // Need to get everything into the DOM if it isn't already
1745
            if (this.header && !Dom.inDocument(this.header)) {
1746
                // There is a header, but it's not in the DOM yet. Need to add it.
1747
                var firstChild = moduleElement.firstChild;
1748
                if (firstChild) {
1749
                    moduleElement.insertBefore(this.header, firstChild);
1750
                } else {
1751
                    moduleElement.appendChild(this.header);
1752
                }
1753
            }
1754
        },
1755
 
1756
        /**
1757
         * Renders the currently set body into it's proper position under the
1758
         * module element. If the module element is not provided, "this.element"
1759
         * is used.
1760
         *
1761
         * @method _renderBody
1762
         * @protected
1763
         * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1764
         */
1765
        _renderBody: function(moduleElement){
1766
            moduleElement = moduleElement || this.element;
1767
 
1768
            if (this.body && !Dom.inDocument(this.body)) {
1769
                // There is a body, but it's not in the DOM yet. Need to add it.
1770
                if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1771
                    moduleElement.insertBefore(this.body, this.footer);
1772
                } else {
1773
                    moduleElement.appendChild(this.body);
1774
                }
1775
            }
1776
        },
1777
 
1778
        /**
1779
         * Renders the currently set footer into it's proper position under the
1780
         * module element. If the module element is not provided, "this.element"
1781
         * is used.
1782
         *
1783
         * @method _renderFooter
1784
         * @protected
1785
         * @param {HTMLElement} moduleElement Optional. A reference to the module element
1786
         */
1787
        _renderFooter: function(moduleElement){
1788
            moduleElement = moduleElement || this.element;
1789
 
1790
            if (this.footer && !Dom.inDocument(this.footer)) {
1791
                // There is a footer, but it's not in the DOM yet. Need to add it.
1792
                moduleElement.appendChild(this.footer);
1793
            }
1794
        },
1795
 
1796
        /**
1797
        * Removes the Module element from the DOM, sets all child elements to null, and purges the bounding element of event listeners.
1798
        * @method destroy
1799
        * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
1800
        * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
1801
        */
1802
        destroy: function (shallowPurge) {
1803
 
1804
            var parent,
1805
                purgeChildren = !(shallowPurge);
1806
 
1807
            if (this.element) {
1808
                Event.purgeElement(this.element, purgeChildren);
1809
                parent = this.element.parentNode;
1810
            }
1811
 
1812
            if (parent) {
1813
                parent.removeChild(this.element);
1814
            }
1815
 
1816
            this.element = null;
1817
            this.header = null;
1818
            this.body = null;
1819
            this.footer = null;
1820
 
1821
            Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1822
 
1823
            this.cfg.destroy();
1824
            this.cfg = null;
1825
 
1826
            this.destroyEvent.fire();
1827
        },
1828
 
1829
        /**
1830
        * Shows the Module element by setting the visible configuration
1831
        * property to true. Also fires two events: beforeShowEvent prior to
1832
        * the visibility change, and showEvent after.
1833
        * @method show
1834
        */
1835
        show: function () {
1836
            this.cfg.setProperty("visible", true);
1837
        },
1838
 
1839
        /**
1840
        * Hides the Module element by setting the visible configuration
1841
        * property to false. Also fires two events: beforeHideEvent prior to
1842
        * the visibility change, and hideEvent after.
1843
        * @method hide
1844
        */
1845
        hide: function () {
1846
            this.cfg.setProperty("visible", false);
1847
        },
1848
 
1849
        // BUILT-IN EVENT HANDLERS FOR MODULE //
1850
        /**
1851
        * Default event handler for changing the visibility property of a
1852
        * Module. By default, this is achieved by switching the "display" style
1853
        * between "block" and "none".
1854
        * This method is responsible for firing showEvent and hideEvent.
1855
        * @param {String} type The CustomEvent type (usually the property name)
1856
        * @param {Object[]} args The CustomEvent arguments. For configuration
1857
        * handlers, args[0] will equal the newly applied value for the property.
1858
        * @param {Object} obj The scope object. For configuration handlers,
1859
        * this will usually equal the owner.
1860
        * @method configVisible
1861
        */
1862
        configVisible: function (type, args, obj) {
1863
            var visible = args[0];
1864
            if (visible) {
1865
                if(this.beforeShowEvent.fire()) {
1866
                    Dom.setStyle(this.element, "display", "block");
1867
                    this.showEvent.fire();
1868
                }
1869
            } else {
1870
                if (this.beforeHideEvent.fire()) {
1871
                    Dom.setStyle(this.element, "display", "none");
1872
                    this.hideEvent.fire();
1873
                }
1874
            }
1875
        },
1876
 
1877
        /**
1878
        * Default event handler for the "effect" configuration property
1879
        * @param {String} type The CustomEvent type (usually the property name)
1880
        * @param {Object[]} args The CustomEvent arguments. For configuration
1881
        * handlers, args[0] will equal the newly applied value for the property.
1882
        * @param {Object} obj The scope object. For configuration handlers,
1883
        * this will usually equal the owner.
1884
        * @method configEffect
1885
        */
1886
        configEffect: function (type, args, obj) {
1887
            this._cachedEffects = (this.cacheEffects) ? this._createEffects(args[0]) : null;
1888
        },
1889
 
1890
        /**
1891
         * If true, ContainerEffects (and Anim instances) are cached when "effect" is set, and reused.
1892
         * If false, new instances are created each time the container is hidden or shown, as was the
1893
         * behavior prior to 2.9.0.
1894
         *
1895
         * @property cacheEffects
1896
         * @since 2.9.0
1897
         * @default true
1898
         * @type boolean
1899
         */
1900
        cacheEffects : true,
1901
 
1902
        /**
1903
         * Creates an array of ContainerEffect instances from the provided configs
1904
         *
1905
         * @method _createEffects
1906
         * @param {Array|Object} effectCfg An effect configuration or array of effect configurations
1907
         * @return {Array} An array of ContainerEffect instances.
1908
         * @protected
1909
         */
1910
        _createEffects: function(effectCfg) {
1911
            var effectInstances = null,
1912
                n,
1913
                i,
1914
                eff;
1915
 
1916
            if (effectCfg) {
1917
                if (effectCfg instanceof Array) {
1918
                    effectInstances = [];
1919
                    n = effectCfg.length;
1920
                    for (i = 0; i < n; i++) {
1921
                        eff = effectCfg[i];
1922
                        if (eff.effect) {
1923
                            effectInstances[effectInstances.length] = eff.effect(this, eff.duration);
1924
                        }
1925
                    }
1926
                } else if (effectCfg.effect) {
1927
                    effectInstances = [effectCfg.effect(this, effectCfg.duration)];
1928
                }
1929
            }
1930
 
1931
            return effectInstances;
1932
        },
1933
 
1934
        /**
1935
        * Default event handler for the "monitorresize" configuration property
1936
        * @param {String} type The CustomEvent type (usually the property name)
1937
        * @param {Object[]} args The CustomEvent arguments. For configuration
1938
        * handlers, args[0] will equal the newly applied value for the property.
1939
        * @param {Object} obj The scope object. For configuration handlers,
1940
        * this will usually equal the owner.
1941
        * @method configMonitorResize
1942
        */
1943
        configMonitorResize: function (type, args, obj) {
1944
            var monitor = args[0];
1945
            if (monitor) {
1946
                this.initResizeMonitor();
1947
            } else {
1948
                Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1949
                this.resizeMonitor = null;
1950
            }
1951
        },
1952
 
1953
        /**
1954
         * This method is a protected helper, used when constructing the DOM structure for the module
1955
         * to account for situations which may cause Operation Aborted errors in IE. It should not
1956
         * be used for general DOM construction.
1957
         * <p>
1958
         * If the parentNode is not document.body, the element is appended as the last element.
1959
         * </p>
1960
         * <p>
1961
         * If the parentNode is document.body the element is added as the first child to help
1962
         * prevent Operation Aborted errors in IE.
1963
         * </p>
1964
         *
1965
         * @param {parentNode} The HTML element to which the element will be added
1966
         * @param {element} The HTML element to be added to parentNode's children
1967
         * @method _addToParent
1968
         * @protected
1969
         */
1970
        _addToParent: function(parentNode, element) {
1971
            if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1972
                parentNode.insertBefore(element, parentNode.firstChild);
1973
            } else {
1974
                parentNode.appendChild(element);
1975
            }
1976
        },
1977
 
1978
        /**
1979
        * Returns a String representation of the Object.
1980
        * @method toString
1981
        * @return {String} The string representation of the Module
1982
        */
1983
        toString: function () {
1984
            return "Module " + this.id;
1985
        }
1986
    };
1987
 
1988
    YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1989
 
1990
}());
1991
(function () {
1992
 
1993
    /**
1994
    * Overlay is a Module that is absolutely positioned above the page flow. It
1995
    * has convenience methods for positioning and sizing, as well as options for
1996
    * controlling zIndex and constraining the Overlay's position to the current
1997
    * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1998
    * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
1999
    * properly rendered above SELECT elements.
2000
    * @namespace YAHOO.widget
2001
    * @class Overlay
2002
    * @extends YAHOO.widget.Module
2003
    * @param {String} el The element ID representing the Overlay <em>OR</em>
2004
    * @param {HTMLElement} el The element representing the Overlay
2005
    * @param {Object} userConfig The configuration object literal containing
2006
    * the configuration that should be set for this Overlay. See configuration
2007
    * documentation for more details.
2008
    * @constructor
2009
    */
2010
    YAHOO.widget.Overlay = function (el, userConfig) {
2011
        YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
2012
    };
2013
 
2014
    var Lang = YAHOO.lang,
2015
        CustomEvent = YAHOO.util.CustomEvent,
2016
        Module = YAHOO.widget.Module,
2017
        Event = YAHOO.util.Event,
2018
        Dom = YAHOO.util.Dom,
2019
        Config = YAHOO.util.Config,
2020
        UA = YAHOO.env.ua,
2021
        Overlay = YAHOO.widget.Overlay,
2022
 
2023
        _SUBSCRIBE = "subscribe",
2024
        _UNSUBSCRIBE = "unsubscribe",
2025
        _CONTAINED = "contained",
2026
 
2027
        m_oIFrameTemplate,
2028
 
2029
        /**
2030
        * Constant representing the name of the Overlay's events
2031
        * @property EVENT_TYPES
2032
        * @private
2033
        * @final
2034
        * @type Object
2035
        */
2036
        EVENT_TYPES = {
2037
            "BEFORE_MOVE": "beforeMove",
2038
            "MOVE": "move"
2039
        },
2040
 
2041
        /**
2042
        * Constant representing the Overlay's configuration properties
2043
        * @property DEFAULT_CONFIG
2044
        * @private
2045
        * @final
2046
        * @type Object
2047
        */
2048
        DEFAULT_CONFIG = {
2049
 
2050
            "X": {
2051
                key: "x",
2052
                validator: Lang.isNumber,
2053
                suppressEvent: true,
2054
                supercedes: ["iframe"]
2055
            },
2056
 
2057
            "Y": {
2058
                key: "y",
2059
                validator: Lang.isNumber,
2060
                suppressEvent: true,
2061
                supercedes: ["iframe"]
2062
            },
2063
 
2064
            "XY": {
2065
                key: "xy",
2066
                suppressEvent: true,
2067
                supercedes: ["iframe"]
2068
            },
2069
 
2070
            "CONTEXT": {
2071
                key: "context",
2072
                suppressEvent: true,
2073
                supercedes: ["iframe"]
2074
            },
2075
 
2076
            "FIXED_CENTER": {
2077
                key: "fixedcenter",
2078
                value: false,
2079
                supercedes: ["iframe", "visible"]
2080
            },
2081
 
2082
            "WIDTH": {
2083
                key: "width",
2084
                suppressEvent: true,
2085
                supercedes: ["context", "fixedcenter", "iframe"]
2086
            },
2087
 
2088
            "HEIGHT": {
2089
                key: "height",
2090
                suppressEvent: true,
2091
                supercedes: ["context", "fixedcenter", "iframe"]
2092
            },
2093
 
2094
            "AUTO_FILL_HEIGHT" : {
2095
                key: "autofillheight",
2096
                supercedes: ["height"],
2097
                value:"body"
2098
            },
2099
 
2100
            "ZINDEX": {
2101
                key: "zindex",
2102
                value: null
2103
            },
2104
 
2105
            "CONSTRAIN_TO_VIEWPORT": {
2106
                key: "constraintoviewport",
2107
                value: false,
2108
                validator: Lang.isBoolean,
2109
                supercedes: ["iframe", "x", "y", "xy"]
2110
            },
2111
 
2112
            "IFRAME": {
2113
                key: "iframe",
2114
                value: (UA.ie == 6 ? true : false),
2115
                validator: Lang.isBoolean,
2116
                supercedes: ["zindex"]
2117
            },
2118
 
2119
            "PREVENT_CONTEXT_OVERLAP": {
2120
                key: "preventcontextoverlap",
2121
                value: false,
2122
                validator: Lang.isBoolean,
2123
                supercedes: ["constraintoviewport"]
2124
            }
2125
 
2126
        };
2127
 
2128
    /**
2129
    * The URL that will be placed in the iframe
2130
    * @property YAHOO.widget.Overlay.IFRAME_SRC
2131
    * @static
2132
    * @final
2133
    * @type String
2134
    */
2135
    Overlay.IFRAME_SRC = "javascript:false;";
2136
 
2137
    /**
2138
    * Number representing how much the iframe shim should be offset from each
2139
    * side of an Overlay instance, in pixels.
2140
    * @property YAHOO.widget.Overlay.IFRAME_SRC
2141
    * @default 3
2142
    * @static
2143
    * @final
2144
    * @type Number
2145
    */
2146
    Overlay.IFRAME_OFFSET = 3;
2147
 
2148
    /**
2149
    * Number representing the minimum distance an Overlay instance should be
2150
    * positioned relative to the boundaries of the browser's viewport, in pixels.
2151
    * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2152
    * @default 10
2153
    * @static
2154
    * @final
2155
    * @type Number
2156
    */
2157
    Overlay.VIEWPORT_OFFSET = 10;
2158
 
2159
    /**
2160
    * Constant representing the top left corner of an element, used for
2161
    * configuring the context element alignment
2162
    * @property YAHOO.widget.Overlay.TOP_LEFT
2163
    * @static
2164
    * @final
2165
    * @type String
2166
    */
2167
    Overlay.TOP_LEFT = "tl";
2168
 
2169
    /**
2170
    * Constant representing the top right corner of an element, used for
2171
    * configuring the context element alignment
2172
    * @property YAHOO.widget.Overlay.TOP_RIGHT
2173
    * @static
2174
    * @final
2175
    * @type String
2176
    */
2177
    Overlay.TOP_RIGHT = "tr";
2178
 
2179
    /**
2180
    * Constant representing the top bottom left corner of an element, used for
2181
    * configuring the context element alignment
2182
    * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2183
    * @static
2184
    * @final
2185
    * @type String
2186
    */
2187
    Overlay.BOTTOM_LEFT = "bl";
2188
 
2189
    /**
2190
    * Constant representing the bottom right corner of an element, used for
2191
    * configuring the context element alignment
2192
    * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2193
    * @static
2194
    * @final
2195
    * @type String
2196
    */
2197
    Overlay.BOTTOM_RIGHT = "br";
2198
 
2199
    Overlay.PREVENT_OVERLAP_X = {
2200
        "tltr": true,
2201
        "blbr": true,
2202
        "brbl": true,
2203
        "trtl": true
2204
    };
2205
 
2206
    Overlay.PREVENT_OVERLAP_Y = {
2207
        "trbr": true,
2208
        "tlbl": true,
2209
        "bltl": true,
2210
        "brtr": true
2211
    };
2212
 
2213
    /**
2214
    * Constant representing the default CSS class used for an Overlay
2215
    * @property YAHOO.widget.Overlay.CSS_OVERLAY
2216
    * @static
2217
    * @final
2218
    * @type String
2219
    */
2220
    Overlay.CSS_OVERLAY = "yui-overlay";
2221
 
2222
    /**
2223
    * Constant representing the default hidden CSS class used for an Overlay. This class is
2224
    * applied to the overlay's outer DIV whenever it's hidden.
2225
    *
2226
    * @property YAHOO.widget.Overlay.CSS_HIDDEN
2227
    * @static
2228
    * @final
2229
    * @type String
2230
    */
2231
    Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2232
 
2233
    /**
2234
    * Constant representing the default CSS class used for an Overlay iframe shim.
2235
    *
2236
    * @property YAHOO.widget.Overlay.CSS_IFRAME
2237
    * @static
2238
    * @final
2239
    * @type String
2240
    */
2241
    Overlay.CSS_IFRAME = "yui-overlay-iframe";
2242
 
2243
    /**
2244
     * Constant representing the names of the standard module elements
2245
     * used in the overlay.
2246
     * @property YAHOO.widget.Overlay.STD_MOD_RE
2247
     * @static
2248
     * @final
2249
     * @type RegExp
2250
     */
2251
    Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2252
 
2253
    /**
2254
    * A singleton CustomEvent used for reacting to the DOM event for
2255
    * window scroll
2256
    * @event YAHOO.widget.Overlay.windowScrollEvent
2257
    */
2258
    Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2259
 
2260
    /**
2261
    * A singleton CustomEvent used for reacting to the DOM event for
2262
    * window resize
2263
    * @event YAHOO.widget.Overlay.windowResizeEvent
2264
    */
2265
    Overlay.windowResizeEvent = new CustomEvent("windowResize");
2266
 
2267
    /**
2268
    * The DOM event handler used to fire the CustomEvent for window scroll
2269
    * @method YAHOO.widget.Overlay.windowScrollHandler
2270
    * @static
2271
    * @param {DOMEvent} e The DOM scroll event
2272
    */
2273
    Overlay.windowScrollHandler = function (e) {
2274
        var t = Event.getTarget(e);
2275
 
2276
        // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2277
        // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2278
        // - IE doesn't recognize scroll registered on the document.
2279
        //
2280
        // Also, when document view is scrolled, IE doesn't provide a target,
2281
        // rest of the browsers set target to window.document, apart from opera
2282
        // which sets target to window.
2283
        if (!t || t === window || t === window.document) {
2284
            if (UA.ie) {
2285
 
2286
                if (! window.scrollEnd) {
2287
                    window.scrollEnd = -1;
2288
                }
2289
 
2290
                clearTimeout(window.scrollEnd);
2291
 
2292
                window.scrollEnd = setTimeout(function () {
2293
                    Overlay.windowScrollEvent.fire();
2294
                }, 1);
2295
 
2296
            } else {
2297
                Overlay.windowScrollEvent.fire();
2298
            }
2299
        }
2300
    };
2301
 
2302
    /**
2303
    * The DOM event handler used to fire the CustomEvent for window resize
2304
    * @method YAHOO.widget.Overlay.windowResizeHandler
2305
    * @static
2306
    * @param {DOMEvent} e The DOM resize event
2307
    */
2308
    Overlay.windowResizeHandler = function (e) {
2309
 
2310
        if (UA.ie) {
2311
            if (! window.resizeEnd) {
2312
                window.resizeEnd = -1;
2313
            }
2314
 
2315
            clearTimeout(window.resizeEnd);
2316
 
2317
            window.resizeEnd = setTimeout(function () {
2318
                Overlay.windowResizeEvent.fire();
2319
            }, 100);
2320
        } else {
2321
            Overlay.windowResizeEvent.fire();
2322
        }
2323
    };
2324
 
2325
    /**
2326
    * A boolean that indicated whether the window resize and scroll events have
2327
    * already been subscribed to.
2328
    * @property YAHOO.widget.Overlay._initialized
2329
    * @private
2330
    * @type Boolean
2331
    */
2332
    Overlay._initialized = null;
2333
 
2334
    if (Overlay._initialized === null) {
2335
        Event.on(window, "scroll", Overlay.windowScrollHandler);
2336
        Event.on(window, "resize", Overlay.windowResizeHandler);
2337
        Overlay._initialized = true;
2338
    }
2339
 
2340
    /**
2341
     * Internal map of special event types, which are provided
2342
     * by the instance. It maps the event type to the custom event
2343
     * instance. Contains entries for the "windowScroll", "windowResize" and
2344
     * "textResize" static container events.
2345
     *
2346
     * @property YAHOO.widget.Overlay._TRIGGER_MAP
2347
     * @type Object
2348
     * @static
2349
     * @private
2350
     */
2351
    Overlay._TRIGGER_MAP = {
2352
        "windowScroll" : Overlay.windowScrollEvent,
2353
        "windowResize" : Overlay.windowResizeEvent,
2354
        "textResize"   : Module.textResizeEvent
2355
    };
2356
 
2357
    YAHOO.extend(Overlay, Module, {
2358
 
2359
        /**
2360
         * <p>
2361
         * Array of default event types which will trigger
2362
         * context alignment for the Overlay class.
2363
         * </p>
2364
         * <p>The array is empty by default for Overlay,
2365
         * but maybe populated in future releases, so classes extending
2366
         * Overlay which need to define their own set of CONTEXT_TRIGGERS
2367
         * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2368
         * value with their own array of values.
2369
         * </p>
2370
         * <p>
2371
         * E.g.:
2372
         * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2373
         * </p>
2374
         *
2375
         * @property CONTEXT_TRIGGERS
2376
         * @type Array
2377
         * @final
2378
         */
2379
        CONTEXT_TRIGGERS : [],
2380
 
2381
        /**
2382
        * The Overlay initialization method, which is executed for Overlay and
2383
        * all of its subclasses. This method is automatically called by the
2384
        * constructor, and  sets up all DOM references for pre-existing markup,
2385
        * and creates required markup if it is not already present.
2386
        * @method init
2387
        * @param {String} el The element ID representing the Overlay <em>OR</em>
2388
        * @param {HTMLElement} el The element representing the Overlay
2389
        * @param {Object} userConfig The configuration object literal
2390
        * containing the configuration that should be set for this Overlay.
2391
        * See configuration documentation for more details.
2392
        */
2393
        init: function (el, userConfig) {
2394
 
2395
            /*
2396
                 Note that we don't pass the user config in here yet because we
2397
                 only want it executed once, at the lowest subclass level
2398
            */
2399
 
2400
            Overlay.superclass.init.call(this, el/*, userConfig*/);
2401
 
2402
            this.beforeInitEvent.fire(Overlay);
2403
 
2404
            Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2405
 
2406
            if (userConfig) {
2407
                this.cfg.applyConfig(userConfig, true);
2408
            }
2409
 
2410
            if (this.platform == "mac" && UA.gecko) {
2411
 
2412
                if (! Config.alreadySubscribed(this.showEvent,
2413
                    this.showMacGeckoScrollbars, this)) {
2414
 
2415
                    this.showEvent.subscribe(this.showMacGeckoScrollbars,
2416
                        this, true);
2417
 
2418
                }
2419
 
2420
                if (! Config.alreadySubscribed(this.hideEvent,
2421
                    this.hideMacGeckoScrollbars, this)) {
2422
 
2423
                    this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2424
                        this, true);
2425
 
2426
                }
2427
            }
2428
 
2429
            this.initEvent.fire(Overlay);
2430
        },
2431
 
2432
        /**
2433
        * Initializes the custom events for Overlay which are fired
2434
        * automatically at appropriate times by the Overlay class.
2435
        * @method initEvents
2436
        */
2437
        initEvents: function () {
2438
 
2439
            Overlay.superclass.initEvents.call(this);
2440
 
2441
            var SIGNATURE = CustomEvent.LIST;
2442
 
2443
            /**
2444
            * CustomEvent fired before the Overlay is moved.
2445
            * @event beforeMoveEvent
2446
            * @param {Number} x x coordinate
2447
            * @param {Number} y y coordinate
2448
            */
2449
            this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2450
            this.beforeMoveEvent.signature = SIGNATURE;
2451
 
2452
            /**
2453
            * CustomEvent fired after the Overlay is moved.
2454
            * @event moveEvent
2455
            * @param {Number} x x coordinate
2456
            * @param {Number} y y coordinate
2457
            */
2458
            this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2459
            this.moveEvent.signature = SIGNATURE;
2460
 
2461
        },
2462
 
2463
        /**
2464
        * Initializes the class's configurable properties which can be changed
2465
        * using the Overlay's Config object (cfg).
2466
        * @method initDefaultConfig
2467
        */
2468
        initDefaultConfig: function () {
2469
 
2470
            Overlay.superclass.initDefaultConfig.call(this);
2471
 
2472
            var cfg = this.cfg;
2473
 
2474
            // Add overlay config properties //
2475
 
2476
            /**
2477
            * The absolute x-coordinate position of the Overlay
2478
            * @config x
2479
            * @type Number
2480
            * @default null
2481
            */
2482
            cfg.addProperty(DEFAULT_CONFIG.X.key, {
2483
 
2484
                handler: this.configX,
2485
                validator: DEFAULT_CONFIG.X.validator,
2486
                suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2487
                supercedes: DEFAULT_CONFIG.X.supercedes
2488
 
2489
            });
2490
 
2491
            /**
2492
            * The absolute y-coordinate position of the Overlay
2493
            * @config y
2494
            * @type Number
2495
            * @default null
2496
            */
2497
            cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2498
 
2499
                handler: this.configY,
2500
                validator: DEFAULT_CONFIG.Y.validator,
2501
                suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2502
                supercedes: DEFAULT_CONFIG.Y.supercedes
2503
 
2504
            });
2505
 
2506
            /**
2507
            * An array with the absolute x and y positions of the Overlay
2508
            * @config xy
2509
            * @type Number[]
2510
            * @default null
2511
            */
2512
            cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2513
                handler: this.configXY,
2514
                suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2515
                supercedes: DEFAULT_CONFIG.XY.supercedes
2516
            });
2517
 
2518
            /**
2519
            * <p>
2520
            * The array of context arguments for context-sensitive positioning.
2521
            * </p>
2522
            *
2523
            * <p>
2524
            * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2525
            * the 5 array elements described in detail below:
2526
            * </p>
2527
            *
2528
            * <dl>
2529
            * <dt>contextElementOrId &#60;String|HTMLElement&#62;</dt>
2530
            * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2531
            * <dt>overlayCorner &#60;String&#62;</dt>
2532
            * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2533
            * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2534
            * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2535
            * <dt>contextCorner &#60;String&#62;</dt>
2536
            * <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>
2537
            * <dt>arrayOfTriggerEvents (optional) &#60;Array[String|CustomEvent]&#62;</dt>
2538
            * <dd>
2539
            * <p>
2540
            * 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>
2541
            * 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.
2542
            * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2543
            * </p>
2544
            * <p>
2545
            * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2546
            * 3 static container event types are also currently supported : <code>"windowResize", "windowScroll", "textResize"</code> (defined in <a href="#property__TRIGGER_MAP">_TRIGGER_MAP</a> private property).
2547
            * </p>
2548
            * </dd>
2549
            * <dt>xyOffset &#60;Number[]&#62;</dt>
2550
            * <dd>
2551
            * A 2 element Array specifying the X and Y pixel amounts by which the Overlay should be offset from the aligned corner. e.g. [5,0] offsets the Overlay 5 pixels to the left, <em>after</em> aligning the given context corners.
2552
            * NOTE: If using this property and no triggers need to be defined, the arrayOfTriggerEvents property should be set to null to maintain correct array positions for the arguments.
2553
            * </dd>
2554
            * </dl>
2555
            *
2556
            * <p>
2557
            * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2558
            * align the Overlay's top left corner to the bottom left corner of the
2559
            * context element with id "img1".
2560
            * </p>
2561
            * <p>
2562
            * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
2563
            * align the Overlay's top left corner to the bottom left corner of the
2564
            * context element with id "img1", and then offset it by 5 pixels on the Y axis (providing a 5 pixel gap between the bottom of the context element and top of the overlay).
2565
            * </p>
2566
            * <p>
2567
            * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2568
            * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2569
            * </p>
2570
            *
2571
            * @config context
2572
            * @type Array
2573
            * @default null
2574
            */
2575
            cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2576
                handler: this.configContext,
2577
                suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2578
                supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2579
            });
2580
 
2581
            /**
2582
            * Determines whether or not the Overlay should be anchored
2583
            * to the center of the viewport.
2584
            *
2585
            * <p>This property can be set to:</p>
2586
            *
2587
            * <dl>
2588
            * <dt>true</dt>
2589
            * <dd>
2590
            * To enable fixed center positioning
2591
            * <p>
2592
            * When enabled, the overlay will
2593
            * be positioned in the center of viewport when initially displayed, and
2594
            * will remain in the center of the viewport whenever the window is
2595
            * scrolled or resized.
2596
            * </p>
2597
            * <p>
2598
            * If the overlay is too big for the viewport,
2599
            * it's top left corner will be aligned with the top left corner of the viewport.
2600
            * </p>
2601
            * </dd>
2602
            * <dt>false</dt>
2603
            * <dd>
2604
            * To disable fixed center positioning.
2605
            * <p>In this case the overlay can still be
2606
            * centered as a one-off operation, by invoking the <code>center()</code> method,
2607
            * however it will not remain centered when the window is scrolled/resized.
2608
            * </dd>
2609
            * <dt>"contained"<dt>
2610
            * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2611
            * <p>However, unlike setting the property to <code>true</code>,
2612
            * when the property is set to <code>"contained"</code>, if the overlay is
2613
            * too big for the viewport, it will not get automatically centered when the
2614
            * user scrolls or resizes the window (until the window is large enough to contain the
2615
            * overlay). This is useful in cases where the Overlay has both header and footer
2616
            * UI controls which the user may need to access.
2617
            * </p>
2618
            * </dd>
2619
            * </dl>
2620
            *
2621
            * @config fixedcenter
2622
            * @type Boolean | String
2623
            * @default false
2624
            */
2625
            cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2626
                handler: this.configFixedCenter,
2627
                value: DEFAULT_CONFIG.FIXED_CENTER.value,
2628
                validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2629
                supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2630
            });
2631
 
2632
            /**
2633
            * CSS width of the Overlay.
2634
            * @config width
2635
            * @type String
2636
            * @default null
2637
            */
2638
            cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2639
                handler: this.configWidth,
2640
                suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2641
                supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2642
            });
2643
 
2644
            /**
2645
            * CSS height of the Overlay.
2646
            * @config height
2647
            * @type String
2648
            * @default null
2649
            */
2650
            cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2651
                handler: this.configHeight,
2652
                suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2653
                supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2654
            });
2655
 
2656
            /**
2657
            * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2658
            * Supported values are "header", "body", "footer".
2659
            *
2660
            * @config autofillheight
2661
            * @type String
2662
            * @default null
2663
            */
2664
            cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2665
                handler: this.configAutoFillHeight,
2666
                value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2667
                validator : this._validateAutoFill,
2668
                supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2669
            });
2670
 
2671
            /**
2672
            * CSS z-index of the Overlay.
2673
            * @config zIndex
2674
            * @type Number
2675
            * @default null
2676
            */
2677
            cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2678
                handler: this.configzIndex,
2679
                value: DEFAULT_CONFIG.ZINDEX.value
2680
            });
2681
 
2682
            /**
2683
            * True if the Overlay should be prevented from being positioned
2684
            * out of the viewport.
2685
            * @config constraintoviewport
2686
            * @type Boolean
2687
            * @default false
2688
            */
2689
            cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2690
 
2691
                handler: this.configConstrainToViewport,
2692
                value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2693
                validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2694
                supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2695
 
2696
            });
2697
 
2698
            /**
2699
            * @config iframe
2700
            * @description Boolean indicating whether or not the Overlay should
2701
            * have an IFRAME shim; used to prevent SELECT elements from
2702
            * poking through an Overlay instance in IE6.  When set to "true",
2703
            * the iframe shim is created when the Overlay instance is intially
2704
            * made visible.
2705
            * @type Boolean
2706
            * @default true for IE6 and below, false for all other browsers.
2707
            */
2708
            cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2709
 
2710
                handler: this.configIframe,
2711
                value: DEFAULT_CONFIG.IFRAME.value,
2712
                validator: DEFAULT_CONFIG.IFRAME.validator,
2713
                supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2714
 
2715
            });
2716
 
2717
            /**
2718
            * @config preventcontextoverlap
2719
            * @description Boolean indicating whether or not the Overlay should overlap its
2720
            * context element (defined using the "context" configuration property) when the
2721
            * "constraintoviewport" configuration property is set to "true".
2722
            * @type Boolean
2723
            * @default false
2724
            */
2725
            cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2726
                value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2727
                validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2728
                supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2729
            });
2730
        },
2731
 
2732
        /**
2733
        * Moves the Overlay to the specified position. This function is
2734
        * identical to calling this.cfg.setProperty("xy", [x,y]);
2735
        * @method moveTo
2736
        * @param {Number} x The Overlay's new x position
2737
        * @param {Number} y The Overlay's new y position
2738
        */
2739
        moveTo: function (x, y) {
2740
            this.cfg.setProperty("xy", [x, y]);
2741
        },
2742
 
2743
        /**
2744
        * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2745
        * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2746
        * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2747
        * @method hideMacGeckoScrollbars
2748
        */
2749
        hideMacGeckoScrollbars: function () {
2750
            Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2751
        },
2752
 
2753
        /**
2754
        * Adds a CSS class ("show-scrollbars") and removes a CSS class
2755
        * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2756
        * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2757
        * @method showMacGeckoScrollbars
2758
        */
2759
        showMacGeckoScrollbars: function () {
2760
            Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2761
        },
2762
 
2763
        /**
2764
         * Internal implementation to set the visibility of the overlay in the DOM.
2765
         *
2766
         * @method _setDomVisibility
2767
         * @param {boolean} visible Whether to show or hide the Overlay's outer element
2768
         * @protected
2769
         */
2770
        _setDomVisibility : function(show) {
2771
            Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2772
            var hiddenClass = Overlay.CSS_HIDDEN;
2773
 
2774
            if (show) {
2775
                Dom.removeClass(this.element, hiddenClass);
2776
            } else {
2777
                Dom.addClass(this.element, hiddenClass);
2778
            }
2779
        },
2780
 
2781
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2782
        /**
2783
        * The default event handler fired when the "visible" property is
2784
        * changed.  This method is responsible for firing showEvent
2785
        * and hideEvent.
2786
        * @method configVisible
2787
        * @param {String} type The CustomEvent type (usually the property name)
2788
        * @param {Object[]} args The CustomEvent arguments. For configuration
2789
        * handlers, args[0] will equal the newly applied value for the property.
2790
        * @param {Object} obj The scope object. For configuration handlers,
2791
        * this will usually equal the owner.
2792
        */
2793
        configVisible: function (type, args, obj) {
2794
 
2795
            var visible = args[0],
2796
                currentVis = Dom.getStyle(this.element, "visibility"),
2797
                effects = this._cachedEffects || this._createEffects(this.cfg.getProperty("effect")),
2798
                isMacGecko = (this.platform == "mac" && UA.gecko),
2799
                alreadySubscribed = Config.alreadySubscribed,
2800
                ei, e, j, k, h,
2801
                nEffectInstances;
2802
 
2803
            if (currentVis == "inherit") {
2804
                e = this.element.parentNode;
2805
 
2806
                while (e.nodeType != 9 && e.nodeType != 11) {
2807
                    currentVis = Dom.getStyle(e, "visibility");
2808
 
2809
                    if (currentVis != "inherit") {
2810
                        break;
2811
                    }
2812
 
2813
                    e = e.parentNode;
2814
                }
2815
 
2816
                if (currentVis == "inherit") {
2817
                    currentVis = "visible";
2818
                }
2819
            }
2820
 
2821
            if (visible) { // Show
2822
 
2823
                if (isMacGecko) {
2824
                    this.showMacGeckoScrollbars();
2825
                }
2826
 
2827
                if (effects) { // Animate in
2828
                    if (visible) { // Animate in if not showing
2829
 
2830
                         // Fading out is a bit of a hack, but didn't want to risk doing
2831
                         // something broader (e.g a generic this._animatingOut) for 2.9.0
2832
 
2833
                        if (currentVis != "visible" || currentVis === "" || this._fadingOut) {
2834
                            if (this.beforeShowEvent.fire()) {
2835
 
2836
                                nEffectInstances = effects.length;
2837
 
2838
                                for (j = 0; j < nEffectInstances; j++) {
2839
                                    ei = effects[j];
2840
                                    if (j === 0 && !alreadySubscribed(ei.animateInCompleteEvent, this.showEvent.fire, this.showEvent)) {
2841
                                        ei.animateInCompleteEvent.subscribe(this.showEvent.fire, this.showEvent, true);
2842
                                    }
2843
                                    ei.animateIn();
2844
                                }
2845
                            }
2846
                        }
2847
                    }
2848
                } else { // Show
2849
                    if (currentVis != "visible" || currentVis === "") {
2850
                        if (this.beforeShowEvent.fire()) {
2851
                            this._setDomVisibility(true);
2852
                            this.cfg.refireEvent("iframe");
2853
                            this.showEvent.fire();
2854
                        }
2855
                    } else {
2856
                        this._setDomVisibility(true);
2857
                    }
2858
                }
2859
            } else { // Hide
2860
 
2861
                if (isMacGecko) {
2862
                    this.hideMacGeckoScrollbars();
2863
                }
2864
 
2865
                if (effects) { // Animate out if showing
2866
                    if (currentVis == "visible" || this._fadingIn) {
2867
                        if (this.beforeHideEvent.fire()) {
2868
                            nEffectInstances = effects.length;
2869
                            for (k = 0; k < nEffectInstances; k++) {
2870
                                h = effects[k];
2871
 
2872
                                if (k === 0 && !alreadySubscribed(h.animateOutCompleteEvent, this.hideEvent.fire, this.hideEvent)) {
2873
                                    h.animateOutCompleteEvent.subscribe(this.hideEvent.fire, this.hideEvent, true);
2874
                                }
2875
                                h.animateOut();
2876
                            }
2877
                        }
2878
 
2879
                    } else if (currentVis === "") {
2880
                        this._setDomVisibility(false);
2881
                    }
2882
 
2883
                } else { // Simple hide
2884
 
2885
                    if (currentVis == "visible" || currentVis === "") {
2886
                        if (this.beforeHideEvent.fire()) {
2887
                            this._setDomVisibility(false);
2888
                            this.hideEvent.fire();
2889
                        }
2890
                    } else {
2891
                        this._setDomVisibility(false);
2892
                    }
2893
                }
2894
            }
2895
        },
2896
 
2897
        /**
2898
        * Fixed center event handler used for centering on scroll/resize, but only if
2899
        * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2900
        * the overlay fits within the viewport.
2901
        *
2902
        * @method doCenterOnDOMEvent
2903
        */
2904
        doCenterOnDOMEvent: function () {
2905
            var cfg = this.cfg,
2906
                fc = cfg.getProperty("fixedcenter");
2907
 
2908
            if (cfg.getProperty("visible")) {
2909
                if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2910
                    this.center();
2911
                }
2912
            }
2913
        },
2914
 
2915
        /**
2916
         * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2917
         * will fit entirely inside the viewport, in both dimensions - width and height.
2918
         *
2919
         * @method fitsInViewport
2920
         * @return boolean true if the Overlay will fit, false if not
2921
         */
2922
        fitsInViewport : function() {
2923
            var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2924
                element = this.element,
2925
                elementWidth = element.offsetWidth,
2926
                elementHeight = element.offsetHeight,
2927
                viewportWidth = Dom.getViewportWidth(),
2928
                viewportHeight = Dom.getViewportHeight();
2929
 
2930
            return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2931
        },
2932
 
2933
        /**
2934
        * The default event handler fired when the "fixedcenter" property
2935
        * is changed.
2936
        * @method configFixedCenter
2937
        * @param {String} type The CustomEvent type (usually the property name)
2938
        * @param {Object[]} args The CustomEvent arguments. For configuration
2939
        * handlers, args[0] will equal the newly applied value for the property.
2940
        * @param {Object} obj The scope object. For configuration handlers,
2941
        * this will usually equal the owner.
2942
        */
2943
        configFixedCenter: function (type, args, obj) {
2944
 
2945
            var val = args[0],
2946
                alreadySubscribed = Config.alreadySubscribed,
2947
                windowResizeEvent = Overlay.windowResizeEvent,
2948
                windowScrollEvent = Overlay.windowScrollEvent;
2949
 
2950
            if (val) {
2951
                this.center();
2952
 
2953
                if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2954
                    this.beforeShowEvent.subscribe(this.center);
2955
                }
2956
 
2957
                if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2958
                    windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2959
                }
2960
 
2961
                if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2962
                    windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2963
                }
2964
 
2965
            } else {
2966
                this.beforeShowEvent.unsubscribe(this.center);
2967
 
2968
                windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2969
                windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2970
            }
2971
        },
2972
 
2973
        /**
2974
        * The default event handler fired when the "height" property is changed.
2975
        * @method configHeight
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.
2981
        */
2982
        configHeight: function (type, args, obj) {
2983
 
2984
            var height = args[0],
2985
                el = this.element;
2986
 
2987
            Dom.setStyle(el, "height", height);
2988
            this.cfg.refireEvent("iframe");
2989
        },
2990
 
2991
        /**
2992
         * The default event handler fired when the "autofillheight" property is changed.
2993
         * @method configAutoFillHeight
2994
         *
2995
         * @param {String} type The CustomEvent type (usually the property name)
2996
         * @param {Object[]} args The CustomEvent arguments. For configuration
2997
         * handlers, args[0] will equal the newly applied value for the property.
2998
         * @param {Object} obj The scope object. For configuration handlers,
2999
         * this will usually equal the owner.
3000
         */
3001
        configAutoFillHeight: function (type, args, obj) {
3002
            var fillEl = args[0],
3003
                cfg = this.cfg,
3004
                autoFillHeight = "autofillheight",
3005
                height = "height",
3006
                currEl = cfg.getProperty(autoFillHeight),
3007
                autoFill = this._autoFillOnHeightChange;
3008
 
3009
            cfg.unsubscribeFromConfigEvent(height, autoFill);
3010
            Module.textResizeEvent.unsubscribe(autoFill);
3011
            this.changeContentEvent.unsubscribe(autoFill);
3012
 
3013
            if (currEl && fillEl !== currEl && this[currEl]) {
3014
                Dom.setStyle(this[currEl], height, "");
3015
            }
3016
 
3017
            if (fillEl) {
3018
                fillEl = Lang.trim(fillEl.toLowerCase());
3019
 
3020
                cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
3021
                Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
3022
                this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
3023
 
3024
                cfg.setProperty(autoFillHeight, fillEl, true);
3025
            }
3026
        },
3027
 
3028
        /**
3029
        * The default event handler fired when the "width" property is changed.
3030
        * @method configWidth
3031
        * @param {String} type The CustomEvent type (usually the property name)
3032
        * @param {Object[]} args The CustomEvent arguments. For configuration
3033
        * handlers, args[0] will equal the newly applied value for the property.
3034
        * @param {Object} obj The scope object. For configuration handlers,
3035
        * this will usually equal the owner.
3036
        */
3037
        configWidth: function (type, args, obj) {
3038
 
3039
            var width = args[0],
3040
                el = this.element;
3041
 
3042
            Dom.setStyle(el, "width", width);
3043
            this.cfg.refireEvent("iframe");
3044
        },
3045
 
3046
        /**
3047
        * The default event handler fired when the "zIndex" property is changed.
3048
        * @method configzIndex
3049
        * @param {String} type The CustomEvent type (usually the property name)
3050
        * @param {Object[]} args The CustomEvent arguments. For configuration
3051
        * handlers, args[0] will equal the newly applied value for the property.
3052
        * @param {Object} obj The scope object. For configuration handlers,
3053
        * this will usually equal the owner.
3054
        */
3055
        configzIndex: function (type, args, obj) {
3056
 
3057
            var zIndex = args[0],
3058
                el = this.element;
3059
 
3060
            if (! zIndex) {
3061
                zIndex = Dom.getStyle(el, "zIndex");
3062
                if (! zIndex || isNaN(zIndex)) {
3063
                    zIndex = 0;
3064
                }
3065
            }
3066
 
3067
            if (this.iframe || this.cfg.getProperty("iframe") === true) {
3068
                if (zIndex <= 0) {
3069
                    zIndex = 1;
3070
                }
3071
            }
3072
 
3073
            Dom.setStyle(el, "zIndex", zIndex);
3074
            this.cfg.setProperty("zIndex", zIndex, true);
3075
 
3076
            if (this.iframe) {
3077
                this.stackIframe();
3078
            }
3079
        },
3080
 
3081
        /**
3082
        * The default event handler fired when the "xy" property is changed.
3083
        * @method configXY
3084
        * @param {String} type The CustomEvent type (usually the property name)
3085
        * @param {Object[]} args The CustomEvent arguments. For configuration
3086
        * handlers, args[0] will equal the newly applied value for the property.
3087
        * @param {Object} obj The scope object. For configuration handlers,
3088
        * this will usually equal the owner.
3089
        */
3090
        configXY: function (type, args, obj) {
3091
 
3092
            var pos = args[0],
3093
                x = pos[0],
3094
                y = pos[1];
3095
 
3096
            this.cfg.setProperty("x", x);
3097
            this.cfg.setProperty("y", y);
3098
 
3099
            this.beforeMoveEvent.fire([x, y]);
3100
 
3101
            x = this.cfg.getProperty("x");
3102
            y = this.cfg.getProperty("y");
3103
 
3104
 
3105
            this.cfg.refireEvent("iframe");
3106
            this.moveEvent.fire([x, y]);
3107
        },
3108
 
3109
        /**
3110
        * The default event handler fired when the "x" property is changed.
3111
        * @method configX
3112
        * @param {String} type The CustomEvent type (usually the property name)
3113
        * @param {Object[]} args The CustomEvent arguments. For configuration
3114
        * handlers, args[0] will equal the newly applied value for the property.
3115
        * @param {Object} obj The scope object. For configuration handlers,
3116
        * this will usually equal the owner.
3117
        */
3118
        configX: function (type, args, obj) {
3119
 
3120
            var x = args[0],
3121
                y = this.cfg.getProperty("y");
3122
 
3123
            this.cfg.setProperty("x", x, true);
3124
            this.cfg.setProperty("y", y, true);
3125
 
3126
            this.beforeMoveEvent.fire([x, y]);
3127
 
3128
            x = this.cfg.getProperty("x");
3129
            y = this.cfg.getProperty("y");
3130
 
3131
            Dom.setX(this.element, x, true);
3132
 
3133
            this.cfg.setProperty("xy", [x, y], true);
3134
 
3135
            this.cfg.refireEvent("iframe");
3136
            this.moveEvent.fire([x, y]);
3137
        },
3138
 
3139
        /**
3140
        * The default event handler fired when the "y" property is changed.
3141
        * @method configY
3142
        * @param {String} type The CustomEvent type (usually the property name)
3143
        * @param {Object[]} args The CustomEvent arguments. For configuration
3144
        * handlers, args[0] will equal the newly applied value for the property.
3145
        * @param {Object} obj The scope object. For configuration handlers,
3146
        * this will usually equal the owner.
3147
        */
3148
        configY: function (type, args, obj) {
3149
 
3150
            var x = this.cfg.getProperty("x"),
3151
                y = args[0];
3152
 
3153
            this.cfg.setProperty("x", x, true);
3154
            this.cfg.setProperty("y", y, true);
3155
 
3156
            this.beforeMoveEvent.fire([x, y]);
3157
 
3158
            x = this.cfg.getProperty("x");
3159
            y = this.cfg.getProperty("y");
3160
 
3161
            Dom.setY(this.element, y, true);
3162
 
3163
            this.cfg.setProperty("xy", [x, y], true);
3164
 
3165
            this.cfg.refireEvent("iframe");
3166
            this.moveEvent.fire([x, y]);
3167
        },
3168
 
3169
        /**
3170
        * Shows the iframe shim, if it has been enabled.
3171
        * @method showIframe
3172
        */
3173
        showIframe: function () {
3174
 
3175
            var oIFrame = this.iframe,
3176
                oParentNode;
3177
 
3178
            if (oIFrame) {
3179
                oParentNode = this.element.parentNode;
3180
 
3181
                if (oParentNode != oIFrame.parentNode) {
3182
                    this._addToParent(oParentNode, oIFrame);
3183
                }
3184
                oIFrame.style.display = "block";
3185
            }
3186
        },
3187
 
3188
        /**
3189
        * Hides the iframe shim, if it has been enabled.
3190
        * @method hideIframe
3191
        */
3192
        hideIframe: function () {
3193
            if (this.iframe) {
3194
                this.iframe.style.display = "none";
3195
            }
3196
        },
3197
 
3198
        /**
3199
        * Syncronizes the size and position of iframe shim to that of its
3200
        * corresponding Overlay instance.
3201
        * @method syncIframe
3202
        */
3203
        syncIframe: function () {
3204
 
3205
            var oIFrame = this.iframe,
3206
                oElement = this.element,
3207
                nOffset = Overlay.IFRAME_OFFSET,
3208
                nDimensionOffset = (nOffset * 2),
3209
                aXY;
3210
 
3211
            if (oIFrame) {
3212
                // Size <iframe>
3213
                oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3214
                oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3215
 
3216
                // Position <iframe>
3217
                aXY = this.cfg.getProperty("xy");
3218
 
3219
                if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3220
                    this.syncPosition();
3221
                    aXY = this.cfg.getProperty("xy");
3222
                }
3223
                Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3224
            }
3225
        },
3226
 
3227
        /**
3228
         * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3229
         * the Overlay element. The zindex of the iframe is set to be one less
3230
         * than the Overlay element's zindex.
3231
         *
3232
         * <p>NOTE: This method will not bump up the zindex of the Overlay element
3233
         * to ensure that the iframe shim has a non-negative zindex.
3234
         * If you require the iframe zindex to be 0 or higher, the zindex of
3235
         * the Overlay element should be set to a value greater than 0, before
3236
         * this method is called.
3237
         * </p>
3238
         * @method stackIframe
3239
         */
3240
        stackIframe: function () {
3241
            if (this.iframe) {
3242
                var overlayZ = Dom.getStyle(this.element, "zIndex");
3243
                if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3244
                    Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3245
                }
3246
            }
3247
        },
3248
 
3249
        /**
3250
        * The default event handler fired when the "iframe" property is changed.
3251
        * @method configIframe
3252
        * @param {String} type The CustomEvent type (usually the property name)
3253
        * @param {Object[]} args The CustomEvent arguments. For configuration
3254
        * handlers, args[0] will equal the newly applied value for the property.
3255
        * @param {Object} obj The scope object. For configuration handlers,
3256
        * this will usually equal the owner.
3257
        */
3258
        configIframe: function (type, args, obj) {
3259
 
3260
            var bIFrame = args[0];
3261
 
3262
            function createIFrame() {
3263
 
3264
                var oIFrame = this.iframe,
3265
                    oElement = this.element,
3266
                    oParent;
3267
 
3268
                if (!oIFrame) {
3269
                    if (!m_oIFrameTemplate) {
3270
                        m_oIFrameTemplate = document.createElement("iframe");
3271
 
3272
                        if (this.isSecure) {
3273
                            m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3274
                        }
3275
 
3276
                        /*
3277
                            Set the opacity of the <iframe> to 0 so that it
3278
                            doesn't modify the opacity of any transparent
3279
                            elements that may be on top of it (like a shadow).
3280
                        */
3281
                        if (UA.ie) {
3282
                            m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3283
                            /*
3284
                                 Need to set the "frameBorder" property to 0
3285
                                 supress the default <iframe> border in IE.
3286
                                 Setting the CSS "border" property alone
3287
                                 doesn't supress it.
3288
                            */
3289
                            m_oIFrameTemplate.frameBorder = 0;
3290
                        }
3291
                        else {
3292
                            m_oIFrameTemplate.style.opacity = "0";
3293
                        }
3294
 
3295
                        m_oIFrameTemplate.style.position = "absolute";
3296
                        m_oIFrameTemplate.style.border = "none";
3297
                        m_oIFrameTemplate.style.margin = "0";
3298
                        m_oIFrameTemplate.style.padding = "0";
3299
                        m_oIFrameTemplate.style.display = "none";
3300
                        m_oIFrameTemplate.tabIndex = -1;
3301
                        m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3302
                    }
3303
 
3304
                    oIFrame = m_oIFrameTemplate.cloneNode(false);
3305
                    oIFrame.id = this.id + "_f";
3306
                    oParent = oElement.parentNode;
3307
 
3308
                    var parentNode = oParent || document.body;
3309
 
3310
                    this._addToParent(parentNode, oIFrame);
3311
                    this.iframe = oIFrame;
3312
                }
3313
 
3314
                /*
3315
                     Show the <iframe> before positioning it since the "setXY"
3316
                     method of DOM requires the element be in the document
3317
                     and visible.
3318
                */
3319
                this.showIframe();
3320
 
3321
                /*
3322
                     Syncronize the size and position of the <iframe> to that
3323
                     of the Overlay.
3324
                */
3325
                this.syncIframe();
3326
                this.stackIframe();
3327
 
3328
                // Add event listeners to update the <iframe> when necessary
3329
                if (!this._hasIframeEventListeners) {
3330
                    this.showEvent.subscribe(this.showIframe);
3331
                    this.hideEvent.subscribe(this.hideIframe);
3332
                    this.changeContentEvent.subscribe(this.syncIframe);
3333
 
3334
                    this._hasIframeEventListeners = true;
3335
                }
3336
            }
3337
 
3338
            function onBeforeShow() {
3339
                createIFrame.call(this);
3340
                this.beforeShowEvent.unsubscribe(onBeforeShow);
3341
                this._iframeDeferred = false;
3342
            }
3343
 
3344
            if (bIFrame) { // <iframe> shim is enabled
3345
 
3346
                if (this.cfg.getProperty("visible")) {
3347
                    createIFrame.call(this);
3348
                } else {
3349
                    if (!this._iframeDeferred) {
3350
                        this.beforeShowEvent.subscribe(onBeforeShow);
3351
                        this._iframeDeferred = true;
3352
                    }
3353
                }
3354
 
3355
            } else {    // <iframe> shim is disabled
3356
                this.hideIframe();
3357
 
3358
                if (this._hasIframeEventListeners) {
3359
                    this.showEvent.unsubscribe(this.showIframe);
3360
                    this.hideEvent.unsubscribe(this.hideIframe);
3361
                    this.changeContentEvent.unsubscribe(this.syncIframe);
3362
 
3363
                    this._hasIframeEventListeners = false;
3364
                }
3365
            }
3366
        },
3367
 
3368
        /**
3369
         * Set's the container's XY value from DOM if not already set.
3370
         *
3371
         * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3372
         * not already set. The method also refire's the XY config property event, so any
3373
         * beforeMove, Move event listeners are invoked.
3374
         *
3375
         * @method _primeXYFromDOM
3376
         * @protected
3377
         */
3378
        _primeXYFromDOM : function() {
3379
            if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3380
                // Set CFG XY based on DOM XY
3381
                this.syncPosition();
3382
                // Account for XY being set silently in syncPosition (no moveTo fired/called)
3383
                this.cfg.refireEvent("xy");
3384
                this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3385
            }
3386
        },
3387
 
3388
        /**
3389
        * The default event handler fired when the "constraintoviewport"
3390
        * property is changed.
3391
        * @method configConstrainToViewport
3392
        * @param {String} type The CustomEvent type (usually the property name)
3393
        * @param {Object[]} args The CustomEvent arguments. For configuration
3394
        * handlers, args[0] will equal the newly applied value for
3395
        * the property.
3396
        * @param {Object} obj The scope object. For configuration handlers,
3397
        * this will usually equal the owner.
3398
        */
3399
        configConstrainToViewport: function (type, args, obj) {
3400
            var val = args[0];
3401
 
3402
            if (val) {
3403
                if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3404
                    this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3405
                }
3406
                if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3407
                    this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3408
                }
3409
            } else {
3410
                this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3411
                this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3412
            }
3413
        },
3414
 
3415
         /**
3416
        * The default event handler fired when the "context" property
3417
        * is changed.
3418
        *
3419
        * @method configContext
3420
        * @param {String} type The CustomEvent type (usually the property name)
3421
        * @param {Object[]} args The CustomEvent arguments. For configuration
3422
        * handlers, args[0] will equal the newly applied value for the property.
3423
        * @param {Object} obj The scope object. For configuration handlers,
3424
        * this will usually equal the owner.
3425
        */
3426
        configContext: function (type, args, obj) {
3427
 
3428
            var contextArgs = args[0],
3429
                contextEl,
3430
                elementMagnetCorner,
3431
                contextMagnetCorner,
3432
                triggers,
3433
                offset,
3434
                defTriggers = this.CONTEXT_TRIGGERS;
3435
 
3436
            if (contextArgs) {
3437
 
3438
                contextEl = contextArgs[0];
3439
                elementMagnetCorner = contextArgs[1];
3440
                contextMagnetCorner = contextArgs[2];
3441
                triggers = contextArgs[3];
3442
                offset = contextArgs[4];
3443
 
3444
                if (defTriggers && defTriggers.length > 0) {
3445
                    triggers = (triggers || []).concat(defTriggers);
3446
                }
3447
 
3448
                if (contextEl) {
3449
                    if (typeof contextEl == "string") {
3450
                        this.cfg.setProperty("context", [
3451
                                document.getElementById(contextEl),
3452
                                elementMagnetCorner,
3453
                                contextMagnetCorner,
3454
                                triggers,
3455
                                offset],
3456
                                true);
3457
                    }
3458
 
3459
                    if (elementMagnetCorner && contextMagnetCorner) {
3460
                        this.align(elementMagnetCorner, contextMagnetCorner, offset);
3461
                    }
3462
 
3463
                    if (this._contextTriggers) {
3464
                        // Unsubscribe Old Set
3465
                        this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3466
                    }
3467
 
3468
                    if (triggers) {
3469
                        // Subscribe New Set
3470
                        this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3471
                        this._contextTriggers = triggers;
3472
                    }
3473
                }
3474
            }
3475
        },
3476
 
3477
        /**
3478
         * Custom Event handler for context alignment triggers. Invokes the align method
3479
         *
3480
         * @method _alignOnTrigger
3481
         * @protected
3482
         *
3483
         * @param {String} type The event type (not used by the default implementation)
3484
         * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3485
         */
3486
        _alignOnTrigger: function(type, args) {
3487
            this.align();
3488
        },
3489
 
3490
        /**
3491
         * Helper method to locate the custom event instance for the event name string
3492
         * passed in. As a convenience measure, any custom events passed in are returned.
3493
         *
3494
         * @method _findTriggerCE
3495
         * @private
3496
         *
3497
         * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3498
         * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3499
         */
3500
        _findTriggerCE : function(t) {
3501
            var tce = null;
3502
            if (t instanceof CustomEvent) {
3503
                tce = t;
3504
            } else if (Overlay._TRIGGER_MAP[t]) {
3505
                tce = Overlay._TRIGGER_MAP[t];
3506
            }
3507
            return tce;
3508
        },
3509
 
3510
        /**
3511
         * Utility method that subscribes or unsubscribes the given
3512
         * function from the list of trigger events provided.
3513
         *
3514
         * @method _processTriggers
3515
         * @protected
3516
         *
3517
         * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3518
         * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3519
         * subscribed/unsubscribed respectively.
3520
         *
3521
         * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3522
         * we are subscribing or unsubscribing trigger listeners
3523
         *
3524
         * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3525
         * Context is always set to the overlay instance, and no additional object argument
3526
         * get passed to the subscribed function.
3527
         */
3528
        _processTriggers : function(triggers, mode, fn) {
3529
            var t, tce;
3530
 
3531
            for (var i = 0, l = triggers.length; i < l; ++i) {
3532
                t = triggers[i];
3533
                tce = this._findTriggerCE(t);
3534
                if (tce) {
3535
                    tce[mode](fn, this, true);
3536
                } else {
3537
                    this[mode](t, fn);
3538
                }
3539
            }
3540
        },
3541
 
3542
        // END BUILT-IN PROPERTY EVENT HANDLERS //
3543
        /**
3544
        * Aligns the Overlay to its context element using the specified corner
3545
        * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3546
        * and BOTTOM_RIGHT.
3547
        * @method align
3548
        * @param {String} elementAlign  The String representing the corner of
3549
        * the Overlay that should be aligned to the context element
3550
        * @param {String} contextAlign  The corner of the context element
3551
        * that the elementAlign corner should stick to.
3552
        * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3553
        * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
3554
        * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3555
        */
3556
        align: function (elementAlign, contextAlign, xyOffset) {
3557
 
3558
            var contextArgs = this.cfg.getProperty("context"),
3559
                me = this,
3560
                context,
3561
                element,
3562
                contextRegion;
3563
 
3564
            function doAlign(v, h) {
3565
 
3566
                var alignX = null, alignY = null;
3567
 
3568
                switch (elementAlign) {
3569
 
3570
                    case Overlay.TOP_LEFT:
3571
                        alignX = h;
3572
                        alignY = v;
3573
                        break;
3574
 
3575
                    case Overlay.TOP_RIGHT:
3576
                        alignX = h - element.offsetWidth;
3577
                        alignY = v;
3578
                        break;
3579
 
3580
                    case Overlay.BOTTOM_LEFT:
3581
                        alignX = h;
3582
                        alignY = v - element.offsetHeight;
3583
                        break;
3584
 
3585
                    case Overlay.BOTTOM_RIGHT:
3586
                        alignX = h - element.offsetWidth;
3587
                        alignY = v - element.offsetHeight;
3588
                        break;
3589
                }
3590
 
3591
                if (alignX !== null && alignY !== null) {
3592
                    if (xyOffset) {
3593
                        alignX += xyOffset[0];
3594
                        alignY += xyOffset[1];
3595
                    }
3596
                    me.moveTo(alignX, alignY);
3597
                }
3598
            }
3599
 
3600
            if (contextArgs) {
3601
                context = contextArgs[0];
3602
                element = this.element;
3603
                me = this;
3604
 
3605
                if (! elementAlign) {
3606
                    elementAlign = contextArgs[1];
3607
                }
3608
 
3609
                if (! contextAlign) {
3610
                    contextAlign = contextArgs[2];
3611
                }
3612
 
3613
                if (!xyOffset && contextArgs[4]) {
3614
                    xyOffset = contextArgs[4];
3615
                }
3616
 
3617
                if (element && context) {
3618
                    contextRegion = Dom.getRegion(context);
3619
 
3620
                    switch (contextAlign) {
3621
 
3622
                        case Overlay.TOP_LEFT:
3623
                            doAlign(contextRegion.top, contextRegion.left);
3624
                            break;
3625
 
3626
                        case Overlay.TOP_RIGHT:
3627
                            doAlign(contextRegion.top, contextRegion.right);
3628
                            break;
3629
 
3630
                        case Overlay.BOTTOM_LEFT:
3631
                            doAlign(contextRegion.bottom, contextRegion.left);
3632
                            break;
3633
 
3634
                        case Overlay.BOTTOM_RIGHT:
3635
                            doAlign(contextRegion.bottom, contextRegion.right);
3636
                            break;
3637
                    }
3638
                }
3639
            }
3640
        },
3641
 
3642
        /**
3643
        * The default event handler executed when the moveEvent is fired, if the
3644
        * "constraintoviewport" is set to true.
3645
        * @method enforceConstraints
3646
        * @param {String} type The CustomEvent type (usually the property name)
3647
        * @param {Object[]} args The CustomEvent arguments. For configuration
3648
        * handlers, args[0] will equal the newly applied value for the property.
3649
        * @param {Object} obj The scope object. For configuration handlers,
3650
        * this will usually equal the owner.
3651
        */
3652
        enforceConstraints: function (type, args, obj) {
3653
            var pos = args[0];
3654
 
3655
            var cXY = this.getConstrainedXY(pos[0], pos[1]);
3656
            this.cfg.setProperty("x", cXY[0], true);
3657
            this.cfg.setProperty("y", cXY[1], true);
3658
            this.cfg.setProperty("xy", cXY, true);
3659
        },
3660
 
3661
        /**
3662
         * Shared implementation method for getConstrainedX and getConstrainedY.
3663
         *
3664
         * <p>
3665
         * Given a coordinate value, returns the calculated coordinate required to
3666
         * position the Overlay if it is to be constrained to the viewport, based on the
3667
         * current element size, viewport dimensions, scroll values and preventoverlap
3668
         * settings
3669
         * </p>
3670
         *
3671
         * @method _getConstrainedPos
3672
         * @protected
3673
         * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3674
         * @param {Number} The coordinate value which needs to be constrained
3675
         * @return {Number} The constrained coordinate value
3676
         */
3677
        _getConstrainedPos: function(pos, val) {
3678
 
3679
            var overlayEl = this.element,
3680
 
3681
                buffer = Overlay.VIEWPORT_OFFSET,
3682
 
3683
                x = (pos == "x"),
3684
 
3685
                overlaySize      = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3686
                viewportSize     = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3687
                docScroll        = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3688
                overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3689
 
3690
                context = this.cfg.getProperty("context"),
3691
 
3692
                bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3693
                bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3694
 
3695
                minConstraint = docScroll + buffer,
3696
                maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3697
 
3698
                constrainedVal = val;
3699
 
3700
            if (val < minConstraint || val > maxConstraint) {
3701
                if (bPreventContextOverlap) {
3702
                    constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3703
                } else {
3704
                    if (bOverlayFitsInViewport) {
3705
                        if (val < minConstraint) {
3706
                            constrainedVal = minConstraint;
3707
                        } else if (val > maxConstraint) {
3708
                            constrainedVal = maxConstraint;
3709
                        }
3710
                    } else {
3711
                        constrainedVal = minConstraint;
3712
                    }
3713
                }
3714
            }
3715
 
3716
            return constrainedVal;
3717
        },
3718
 
3719
        /**
3720
         * Helper method, used to position the Overlap to prevent overlap with the
3721
         * context element (used when preventcontextoverlap is enabled)
3722
         *
3723
         * @method _preventOverlap
3724
         * @protected
3725
         * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3726
         * @param {HTMLElement} contextEl The context element
3727
         * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3728
         * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3729
         * @param {Object} docScroll  The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3730
         *
3731
         * @return {Number} The new coordinate value which was set to prevent overlap
3732
         */
3733
        _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3734
 
3735
            var x = (pos == "x"),
3736
 
3737
                buffer = Overlay.VIEWPORT_OFFSET,
3738
 
3739
                overlay = this,
3740
 
3741
                contextElPos   = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3742
                contextElSize  = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3743
 
3744
                minRegionSize = contextElPos - buffer,
3745
                maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3746
 
3747
                bFlipped = false,
3748
 
3749
                flip = function () {
3750
                    var flippedVal;
3751
 
3752
                    if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3753
                        flippedVal = (contextElPos - overlaySize);
3754
                    } else {
3755
                        flippedVal = (contextElPos + contextElSize);
3756
                    }
3757
 
3758
                    overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3759
 
3760
                    return flippedVal;
3761
                },
3762
 
3763
                setPosition = function () {
3764
 
3765
                    var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3766
                        position;
3767
 
3768
                    if (overlaySize > displayRegionSize) {
3769
                        if (bFlipped) {
3770
                            /*
3771
                                 All possible positions and values have been
3772
                                 tried, but none were successful, so fall back
3773
                                 to the original size and position.
3774
                            */
3775
                            flip();
3776
                        } else {
3777
                            flip();
3778
                            bFlipped = true;
3779
                            position = setPosition();
3780
                        }
3781
                    }
3782
 
3783
                    return position;
3784
                };
3785
 
3786
            setPosition();
3787
 
3788
            return this.cfg.getProperty(pos);
3789
        },
3790
 
3791
        /**
3792
         * Given x coordinate value, returns the calculated x coordinate required to
3793
         * position the Overlay if it is to be constrained to the viewport, based on the
3794
         * current element size, viewport dimensions and scroll values.
3795
         *
3796
         * @param {Number} x The X coordinate value to be constrained
3797
         * @return {Number} The constrained x coordinate
3798
         */
3799
        getConstrainedX: function (x) {
3800
            return this._getConstrainedPos("x", x);
3801
        },
3802
 
3803
        /**
3804
         * Given y coordinate value, returns the calculated y coordinate required to
3805
         * position the Overlay if it is to be constrained to the viewport, based on the
3806
         * current element size, viewport dimensions and scroll values.
3807
         *
3808
         * @param {Number} y The Y coordinate value to be constrained
3809
         * @return {Number} The constrained y coordinate
3810
         */
3811
        getConstrainedY : function (y) {
3812
            return this._getConstrainedPos("y", y);
3813
        },
3814
 
3815
        /**
3816
         * Given x, y coordinate values, returns the calculated coordinates required to
3817
         * position the Overlay if it is to be constrained to the viewport, based on the
3818
         * current element size, viewport dimensions and scroll values.
3819
         *
3820
         * @param {Number} x The X coordinate value to be constrained
3821
         * @param {Number} y The Y coordinate value to be constrained
3822
         * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3823
         */
3824
        getConstrainedXY: function(x, y) {
3825
            return [this.getConstrainedX(x), this.getConstrainedY(y)];
3826
        },
3827
 
3828
        /**
3829
        * Centers the container in the viewport.
3830
        * @method center
3831
        */
3832
        center: function () {
3833
 
3834
            var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3835
                elementWidth = this.element.offsetWidth,
3836
                elementHeight = this.element.offsetHeight,
3837
                viewPortWidth = Dom.getViewportWidth(),
3838
                viewPortHeight = Dom.getViewportHeight(),
3839
                x,
3840
                y;
3841
 
3842
            if (elementWidth < viewPortWidth) {
3843
                x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3844
            } else {
3845
                x = nViewportOffset + Dom.getDocumentScrollLeft();
3846
            }
3847
 
3848
            if (elementHeight < viewPortHeight) {
3849
                y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3850
            } else {
3851
                y = nViewportOffset + Dom.getDocumentScrollTop();
3852
            }
3853
 
3854
            this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3855
            this.cfg.refireEvent("iframe");
3856
 
3857
            if (UA.webkit) {
3858
                this.forceContainerRedraw();
3859
            }
3860
        },
3861
 
3862
        /**
3863
        * Synchronizes the Panel's "xy", "x", and "y" properties with the
3864
        * Panel's position in the DOM. This is primarily used to update
3865
        * position information during drag & drop.
3866
        * @method syncPosition
3867
        */
3868
        syncPosition: function () {
3869
 
3870
            var pos = Dom.getXY(this.element);
3871
 
3872
            this.cfg.setProperty("x", pos[0], true);
3873
            this.cfg.setProperty("y", pos[1], true);
3874
            this.cfg.setProperty("xy", pos, true);
3875
 
3876
        },
3877
 
3878
        /**
3879
        * Event handler fired when the resize monitor element is resized.
3880
        * @method onDomResize
3881
        * @param {DOMEvent} e The resize DOM event
3882
        * @param {Object} obj The scope object
3883
        */
3884
        onDomResize: function (e, obj) {
3885
 
3886
            var me = this;
3887
 
3888
            Overlay.superclass.onDomResize.call(this, e, obj);
3889
 
3890
            setTimeout(function () {
3891
                me.syncPosition();
3892
                me.cfg.refireEvent("iframe");
3893
                me.cfg.refireEvent("context");
3894
            }, 0);
3895
        },
3896
 
3897
        /**
3898
         * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3899
         *
3900
         * @method _getComputedHeight
3901
         * @private
3902
         * @param {HTMLElement} el The element for which the content height needs to be determined
3903
         * @return {Number} The content box height of the given element, or null if it could not be determined.
3904
         */
3905
        _getComputedHeight : (function() {
3906
 
3907
            if (document.defaultView && document.defaultView.getComputedStyle) {
3908
                return function(el) {
3909
                    var height = null;
3910
                    if (el.ownerDocument && el.ownerDocument.defaultView) {
3911
                        var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3912
                        if (computed) {
3913
                            height = parseInt(computed.height, 10);
3914
                        }
3915
                    }
3916
                    return (Lang.isNumber(height)) ? height : null;
3917
                };
3918
            } else {
3919
                return function(el) {
3920
                    var height = null;
3921
                    if (el.style.pixelHeight) {
3922
                        height = el.style.pixelHeight;
3923
                    }
3924
                    return (Lang.isNumber(height)) ? height : null;
3925
                };
3926
            }
3927
        })(),
3928
 
3929
        /**
3930
         * autofillheight validator. Verifies that the autofill value is either null
3931
         * or one of the strings : "body", "header" or "footer".
3932
         *
3933
         * @method _validateAutoFillHeight
3934
         * @protected
3935
         * @param {String} val
3936
         * @return true, if valid, false otherwise
3937
         */
3938
        _validateAutoFillHeight : function(val) {
3939
            return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3940
        },
3941
 
3942
        /**
3943
         * The default custom event handler executed when the overlay's height is changed,
3944
         * if the autofillheight property has been set.
3945
         *
3946
         * @method _autoFillOnHeightChange
3947
         * @protected
3948
         * @param {String} type The event type
3949
         * @param {Array} args The array of arguments passed to event subscribers
3950
         * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3951
         * out the containers height
3952
         */
3953
        _autoFillOnHeightChange : function(type, args, el) {
3954
            var height = this.cfg.getProperty("height");
3955
            if ((height && height !== "auto") || (height === 0)) {
3956
                this.fillHeight(el);
3957
            }
3958
        },
3959
 
3960
        /**
3961
         * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3962
         * otherwise returns the offsetHeight
3963
         * @method _getPreciseHeight
3964
         * @private
3965
         * @param {HTMLElement} el
3966
         * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3967
         */
3968
        _getPreciseHeight : function(el) {
3969
            var height = el.offsetHeight;
3970
 
3971
            if (el.getBoundingClientRect) {
3972
                var rect = el.getBoundingClientRect();
3973
                height = rect.bottom - rect.top;
3974
            }
3975
 
3976
            return height;
3977
        },
3978
 
3979
        /**
3980
         * <p>
3981
         * Sets the height on the provided header, body or footer element to
3982
         * fill out the height of the container. It determines the height of the
3983
         * containers content box, based on it's configured height value, and
3984
         * sets the height of the autofillheight element to fill out any
3985
         * space remaining after the other standard module element heights
3986
         * have been accounted for.
3987
         * </p>
3988
         * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
3989
         * height has not been set on the container, since for an "auto" height container,
3990
         * the heights of the header/body/footer will drive the height of the container.</p>
3991
         *
3992
         * @method fillHeight
3993
         * @param {HTMLElement} el The element which should be resized to fill out the height
3994
         * of the container element.
3995
         */
3996
        fillHeight : function(el) {
3997
            if (el) {
3998
                var container = this.innerElement || this.element,
3999
                    containerEls = [this.header, this.body, this.footer],
4000
                    containerEl,
4001
                    total = 0,
4002
                    filled = 0,
4003
                    remaining = 0,
4004
                    validEl = false;
4005
 
4006
                for (var i = 0, l = containerEls.length; i < l; i++) {
4007
                    containerEl = containerEls[i];
4008
                    if (containerEl) {
4009
                        if (el !== containerEl) {
4010
                            filled += this._getPreciseHeight(containerEl);
4011
                        } else {
4012
                            validEl = true;
4013
                        }
4014
                    }
4015
                }
4016
 
4017
                if (validEl) {
4018
 
4019
                    if (UA.ie || UA.opera) {
4020
                        // Need to set height to 0, to allow height to be reduced
4021
                        Dom.setStyle(el, 'height', 0 + 'px');
4022
                    }
4023
 
4024
                    total = this._getComputedHeight(container);
4025
 
4026
                    // Fallback, if we can't get computed value for content height
4027
                    if (total === null) {
4028
                        Dom.addClass(container, "yui-override-padding");
4029
                        total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4030
                        Dom.removeClass(container, "yui-override-padding");
4031
                    }
4032
 
4033
                    remaining = Math.max(total - filled, 0);
4034
 
4035
                    Dom.setStyle(el, "height", remaining + "px");
4036
 
4037
                    // Re-adjust height if required, to account for el padding and border
4038
                    if (el.offsetHeight != remaining) {
4039
                        remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4040
                    }
4041
                    Dom.setStyle(el, "height", remaining + "px");
4042
                }
4043
            }
4044
        },
4045
 
4046
        /**
4047
        * Places the Overlay on top of all other instances of
4048
        * YAHOO.widget.Overlay.
4049
        * @method bringToTop
4050
        */
4051
        bringToTop: function () {
4052
 
4053
            var aOverlays = [],
4054
                oElement = this.element;
4055
 
4056
            function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4057
 
4058
                var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4059
                    sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4060
 
4061
                    nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4062
                    nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4063
 
4064
                if (nZIndex1 > nZIndex2) {
4065
                    return -1;
4066
                } else if (nZIndex1 < nZIndex2) {
4067
                    return 1;
4068
                } else {
4069
                    return 0;
4070
                }
4071
            }
4072
 
4073
            function isOverlayElement(p_oElement) {
4074
 
4075
                var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4076
                    Panel = YAHOO.widget.Panel;
4077
 
4078
                if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4079
                    if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4080
                        aOverlays[aOverlays.length] = p_oElement.parentNode;
4081
                    } else {
4082
                        aOverlays[aOverlays.length] = p_oElement;
4083
                    }
4084
                }
4085
            }
4086
 
4087
            Dom.getElementsBy(isOverlayElement, "div", document.body);
4088
 
4089
            aOverlays.sort(compareZIndexDesc);
4090
 
4091
            var oTopOverlay = aOverlays[0],
4092
                nTopZIndex;
4093
 
4094
            if (oTopOverlay) {
4095
                nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4096
 
4097
                if (!isNaN(nTopZIndex)) {
4098
                    var bRequiresBump = false;
4099
 
4100
                    if (oTopOverlay != oElement) {
4101
                        bRequiresBump = true;
4102
                    } else if (aOverlays.length > 1) {
4103
                        var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4104
                        // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4105
                        if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4106
                            bRequiresBump = true;
4107
                        }
4108
                    }
4109
                    if (bRequiresBump) {
4110
                        this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4111
                    }
4112
                }
4113
            }
4114
        },
4115
 
4116
        /**
4117
        * Removes the Overlay element from the DOM and sets all child
4118
        * elements to null.
4119
        * @method destroy
4120
        * @param {boolean} shallowPurge If true, only the parent element's DOM event listeners are purged. If false, or not provided, all children are also purged of DOM event listeners.
4121
        * NOTE: The flag is a "shallowPurge" flag, as opposed to what may be a more intuitive "purgeChildren" flag to maintain backwards compatibility with behavior prior to 2.9.0.
4122
        */
4123
        destroy: function (shallowPurge) {
4124
 
4125
            if (this.iframe) {
4126
                this.iframe.parentNode.removeChild(this.iframe);
4127
            }
4128
 
4129
            this.iframe = null;
4130
 
4131
            Overlay.windowResizeEvent.unsubscribe(
4132
                this.doCenterOnDOMEvent, this);
4133
 
4134
            Overlay.windowScrollEvent.unsubscribe(
4135
                this.doCenterOnDOMEvent, this);
4136
 
4137
            Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4138
 
4139
            if (this._contextTriggers) {
4140
                // Unsubscribe context triggers - to cover context triggers which listen for global
4141
                // events such as windowResize and windowScroll. Easier just to unsubscribe all
4142
                this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4143
            }
4144
 
4145
            Overlay.superclass.destroy.call(this, shallowPurge);
4146
        },
4147
 
4148
        /**
4149
         * Can be used to force the container to repaint/redraw it's contents.
4150
         * <p>
4151
         * By default applies and then removes a 1px bottom margin through the
4152
         * application/removal of a "yui-force-redraw" class.
4153
         * </p>
4154
         * <p>
4155
         * It is currently used by Overlay to force a repaint for webkit
4156
         * browsers, when centering.
4157
         * </p>
4158
         * @method forceContainerRedraw
4159
         */
4160
        forceContainerRedraw : function() {
4161
            var c = this;
4162
            Dom.addClass(c.element, "yui-force-redraw");
4163
            setTimeout(function() {
4164
                Dom.removeClass(c.element, "yui-force-redraw");
4165
            }, 0);
4166
        },
4167
 
4168
        /**
4169
        * Returns a String representation of the object.
4170
        * @method toString
4171
        * @return {String} The string representation of the Overlay.
4172
        */
4173
        toString: function () {
4174
            return "Overlay " + this.id;
4175
        }
4176
 
4177
    });
4178
}());
4179
(function () {
4180
 
4181
    /**
4182
    * OverlayManager is used for maintaining the focus status of
4183
    * multiple Overlays.
4184
    * @namespace YAHOO.widget
4185
    * @namespace YAHOO.widget
4186
    * @class OverlayManager
4187
    * @constructor
4188
    * @param {Array} overlays Optional. A collection of Overlays to register
4189
    * with the manager.
4190
    * @param {Object} userConfig  The object literal representing the user
4191
    * configuration of the OverlayManager
4192
    */
4193
    YAHOO.widget.OverlayManager = function (userConfig) {
4194
        this.init(userConfig);
4195
    };
4196
 
4197
    var Overlay = YAHOO.widget.Overlay,
4198
        Event = YAHOO.util.Event,
4199
        Dom = YAHOO.util.Dom,
4200
        Config = YAHOO.util.Config,
4201
        CustomEvent = YAHOO.util.CustomEvent,
4202
        OverlayManager = YAHOO.widget.OverlayManager;
4203
 
4204
    /**
4205
    * The CSS class representing a focused Overlay
4206
    * @property OverlayManager.CSS_FOCUSED
4207
    * @static
4208
    * @final
4209
    * @type String
4210
    */
4211
    OverlayManager.CSS_FOCUSED = "focused";
4212
 
4213
    OverlayManager.prototype = {
4214
 
4215
        /**
4216
        * The class's constructor function
4217
        * @property contructor
4218
        * @type Function
4219
        */
4220
        constructor: OverlayManager,
4221
 
4222
        /**
4223
        * The array of Overlays that are currently registered
4224
        * @property overlays
4225
        * @type YAHOO.widget.Overlay[]
4226
        */
4227
        overlays: null,
4228
 
4229
        /**
4230
        * Initializes the default configuration of the OverlayManager
4231
        * @method initDefaultConfig
4232
        */
4233
        initDefaultConfig: function () {
4234
            /**
4235
            * The collection of registered Overlays in use by
4236
            * the OverlayManager
4237
            * @config overlays
4238
            * @type YAHOO.widget.Overlay[]
4239
            * @default null
4240
            */
4241
            this.cfg.addProperty("overlays", { suppressEvent: true } );
4242
 
4243
            /**
4244
            * The default DOM event that should be used to focus an Overlay
4245
            * @config focusevent
4246
            * @type String
4247
            * @default "mousedown"
4248
            */
4249
            this.cfg.addProperty("focusevent", { value: "mousedown" } );
4250
        },
4251
 
4252
        /**
4253
        * Initializes the OverlayManager
4254
        * @method init
4255
        * @param {Overlay[]} overlays Optional. A collection of Overlays to
4256
        * register with the manager.
4257
        * @param {Object} userConfig  The object literal representing the user
4258
        * configuration of the OverlayManager
4259
        */
4260
        init: function (userConfig) {
4261
 
4262
            /**
4263
            * The OverlayManager's Config object used for monitoring
4264
            * configuration properties.
4265
            * @property cfg
4266
            * @type Config
4267
            */
4268
            this.cfg = new Config(this);
4269
 
4270
            this.initDefaultConfig();
4271
 
4272
            if (userConfig) {
4273
                this.cfg.applyConfig(userConfig, true);
4274
            }
4275
            this.cfg.fireQueue();
4276
 
4277
            /**
4278
            * The currently activated Overlay
4279
            * @property activeOverlay
4280
            * @private
4281
            * @type YAHOO.widget.Overlay
4282
            */
4283
            var activeOverlay = null;
4284
 
4285
            /**
4286
            * Returns the currently focused Overlay
4287
            * @method getActive
4288
            * @return {Overlay} The currently focused Overlay
4289
            */
4290
            this.getActive = function () {
4291
                return activeOverlay;
4292
            };
4293
 
4294
            /**
4295
            * Focuses the specified Overlay
4296
            * @method focus
4297
            * @param {Overlay} overlay The Overlay to focus
4298
            * @param {String} overlay The id of the Overlay to focus
4299
            */
4300
            this.focus = function (overlay) {
4301
                var o = this.find(overlay);
4302
                if (o) {
4303
                    o.focus();
4304
                }
4305
            };
4306
 
4307
            /**
4308
            * Removes the specified Overlay from the manager
4309
            * @method remove
4310
            * @param {Overlay} overlay The Overlay to remove
4311
            * @param {String} overlay The id of the Overlay to remove
4312
            */
4313
            this.remove = function (overlay) {
4314
 
4315
                var o = this.find(overlay),
4316
                        originalZ;
4317
 
4318
                if (o) {
4319
                    if (activeOverlay == o) {
4320
                        activeOverlay = null;
4321
                    }
4322
 
4323
                    var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4324
 
4325
                    if (!bDestroyed) {
4326
                        // Set it's zindex so that it's sorted to the end.
4327
                        originalZ = Dom.getStyle(o.element, "zIndex");
4328
                        o.cfg.setProperty("zIndex", -1000, true);
4329
                    }
4330
 
4331
                    this.overlays.sort(this.compareZIndexDesc);
4332
                    this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4333
 
4334
                    o.hideEvent.unsubscribe(o.blur);
4335
                    o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4336
                    o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4337
                    o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4338
 
4339
                    if (!bDestroyed) {
4340
                        Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4341
                        o.cfg.setProperty("zIndex", originalZ, true);
4342
                        o.cfg.setProperty("manager", null);
4343
                    }
4344
 
4345
                    /* _managed Flag for custom or existing. Don't want to remove existing */
4346
                    if (o.focusEvent._managed) { o.focusEvent = null; }
4347
                    if (o.blurEvent._managed) { o.blurEvent = null; }
4348
 
4349
                    if (o.focus._managed) { o.focus = null; }
4350
                    if (o.blur._managed) { o.blur = null; }
4351
                }
4352
            };
4353
 
4354
            /**
4355
            * Removes focus from all registered Overlays in the manager
4356
            * @method blurAll
4357
            */
4358
            this.blurAll = function () {
4359
 
4360
                var nOverlays = this.overlays.length,
4361
                    i;
4362
 
4363
                if (nOverlays > 0) {
4364
                    i = nOverlays - 1;
4365
                    do {
4366
                        this.overlays[i].blur();
4367
                    }
4368
                    while(i--);
4369
                }
4370
            };
4371
 
4372
            /**
4373
             * Updates the state of the OverlayManager and overlay, as a result of the overlay
4374
             * being blurred.
4375
             *
4376
             * @method _manageBlur
4377
             * @param {Overlay} overlay The overlay instance which got blurred.
4378
             * @protected
4379
             */
4380
            this._manageBlur = function (overlay) {
4381
                var changed = false;
4382
                if (activeOverlay == overlay) {
4383
                    Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4384
                    activeOverlay = null;
4385
                    changed = true;
4386
                }
4387
                return changed;
4388
            };
4389
 
4390
            /**
4391
             * Updates the state of the OverlayManager and overlay, as a result of the overlay
4392
             * receiving focus.
4393
             *
4394
             * @method _manageFocus
4395
             * @param {Overlay} overlay The overlay instance which got focus.
4396
             * @protected
4397
             */
4398
            this._manageFocus = function(overlay) {
4399
                var changed = false;
4400
                if (activeOverlay != overlay) {
4401
                    if (activeOverlay) {
4402
                        activeOverlay.blur();
4403
                    }
4404
                    activeOverlay = overlay;
4405
                    this.bringToTop(activeOverlay);
4406
                    Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4407
                    changed = true;
4408
                }
4409
                return changed;
4410
            };
4411
 
4412
            var overlays = this.cfg.getProperty("overlays");
4413
 
4414
            if (! this.overlays) {
4415
                this.overlays = [];
4416
            }
4417
 
4418
            if (overlays) {
4419
                this.register(overlays);
4420
                this.overlays.sort(this.compareZIndexDesc);
4421
            }
4422
        },
4423
 
4424
        /**
4425
        * @method _onOverlayElementFocus
4426
        * @description Event handler for the DOM event that is used to focus
4427
        * the Overlay instance as specified by the "focusevent"
4428
        * configuration property.
4429
        * @private
4430
        * @param {Event} p_oEvent Object representing the DOM event
4431
        * object passed back by the event utility (Event).
4432
        */
4433
        _onOverlayElementFocus: function (p_oEvent) {
4434
 
4435
            var oTarget = Event.getTarget(p_oEvent),
4436
                oClose = this.close;
4437
 
4438
            if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4439
                this.blur();
4440
            } else {
4441
                this.focus();
4442
            }
4443
        },
4444
 
4445
        /**
4446
        * @method _onOverlayDestroy
4447
        * @description "destroy" event handler for the Overlay.
4448
        * @private
4449
        * @param {String} p_sType String representing the name of the event
4450
        * that was fired.
4451
        * @param {Array} p_aArgs Array of arguments sent when the event
4452
        * was fired.
4453
        * @param {Overlay} p_oOverlay Object representing the overlay that
4454
        * fired the event.
4455
        */
4456
        _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4457
            this.remove(p_oOverlay);
4458
        },
4459
 
4460
        /**
4461
        * @method _onOverlayFocusHandler
4462
        *
4463
        * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4464
        *
4465
        * @private
4466
        * @param {String} p_sType String representing the name of the event
4467
        * that was fired.
4468
        * @param {Array} p_aArgs Array of arguments sent when the event
4469
        * was fired.
4470
        * @param {Overlay} p_oOverlay Object representing the overlay that
4471
        * fired the event.
4472
        */
4473
        _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4474
            this._manageFocus(p_oOverlay);
4475
        },
4476
 
4477
        /**
4478
        * @method _onOverlayBlurHandler
4479
        * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4480
        *
4481
        * @private
4482
        * @param {String} p_sType String representing the name of the event
4483
        * that was fired.
4484
        * @param {Array} p_aArgs Array of arguments sent when the event
4485
        * was fired.
4486
        * @param {Overlay} p_oOverlay Object representing the overlay that
4487
        * fired the event.
4488
        */
4489
        _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4490
            this._manageBlur(p_oOverlay);
4491
        },
4492
 
4493
        /**
4494
         * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4495
         * monitor focus state.
4496
         *
4497
         * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4498
         * to the existing focusEvent, however if a focusEvent or focus method does not exist
4499
         * on the instance, the _bindFocus method will add them, and the focus method will
4500
         * update the OverlayManager's state directly.
4501
         *
4502
         * @method _bindFocus
4503
         * @param {Overlay} overlay The overlay for which focus needs to be managed
4504
         * @protected
4505
         */
4506
        _bindFocus : function(overlay) {
4507
            var mgr = this;
4508
 
4509
            if (!overlay.focusEvent) {
4510
                overlay.focusEvent = overlay.createEvent("focus");
4511
                overlay.focusEvent.signature = CustomEvent.LIST;
4512
                overlay.focusEvent._managed = true;
4513
            } else {
4514
                overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4515
            }
4516
 
4517
            if (!overlay.focus) {
4518
                Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4519
                overlay.focus = function () {
4520
                    if (mgr._manageFocus(this)) {
4521
                        // For Panel/Dialog
4522
                        if (this.cfg.getProperty("visible") && this.focusFirst) {
4523
                            this.focusFirst();
4524
                        }
4525
                        this.focusEvent.fire();
4526
                    }
4527
                };
4528
                overlay.focus._managed = true;
4529
            }
4530
        },
4531
 
4532
        /**
4533
         * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4534
         * monitor blur state.
4535
         *
4536
         * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4537
         * to the existing blurEvent, however if a blurEvent or blur method does not exist
4538
         * on the instance, the _bindBlur method will add them, and the blur method
4539
         * update the OverlayManager's state directly.
4540
         *
4541
         * @method _bindBlur
4542
         * @param {Overlay} overlay The overlay for which blur needs to be managed
4543
         * @protected
4544
         */
4545
        _bindBlur : function(overlay) {
4546
            var mgr = this;
4547
 
4548
            if (!overlay.blurEvent) {
4549
                overlay.blurEvent = overlay.createEvent("blur");
4550
                overlay.blurEvent.signature = CustomEvent.LIST;
4551
                overlay.focusEvent._managed = true;
4552
            } else {
4553
                overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4554
            }
4555
 
4556
            if (!overlay.blur) {
4557
                overlay.blur = function () {
4558
                    if (mgr._manageBlur(this)) {
4559
                        this.blurEvent.fire();
4560
                    }
4561
                };
4562
                overlay.blur._managed = true;
4563
            }
4564
 
4565
            overlay.hideEvent.subscribe(overlay.blur);
4566
        },
4567
 
4568
        /**
4569
         * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4570
         * to be removed for the OverlayManager when destroyed.
4571
         *
4572
         * @method _bindDestroy
4573
         * @param {Overlay} overlay The overlay instance being managed
4574
         * @protected
4575
         */
4576
        _bindDestroy : function(overlay) {
4577
            var mgr = this;
4578
            overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4579
        },
4580
 
4581
        /**
4582
         * Ensures the zIndex configuration property on the managed overlay based instance
4583
         * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4584
         *
4585
         * @method _syncZIndex
4586
         * @param {Overlay} overlay The overlay instance being managed
4587
         * @protected
4588
         */
4589
        _syncZIndex : function(overlay) {
4590
            var zIndex = Dom.getStyle(overlay.element, "zIndex");
4591
            if (!isNaN(zIndex)) {
4592
                overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4593
            } else {
4594
                overlay.cfg.setProperty("zIndex", 0);
4595
            }
4596
        },
4597
 
4598
        /**
4599
        * Registers an Overlay or an array of Overlays with the manager. Upon
4600
        * registration, the Overlay receives functions for focus and blur,
4601
        * along with CustomEvents for each.
4602
        *
4603
        * @method register
4604
        * @param {Overlay} overlay  An Overlay to register with the manager.
4605
        * @param {Overlay[]} overlay  An array of Overlays to register with
4606
        * the manager.
4607
        * @return {boolean} true if any Overlays are registered.
4608
        */
4609
        register: function (overlay) {
4610
 
4611
            var registered = false,
4612
                i,
4613
                n;
4614
 
4615
            if (overlay instanceof Overlay) {
4616
 
4617
                overlay.cfg.addProperty("manager", { value: this } );
4618
 
4619
                this._bindFocus(overlay);
4620
                this._bindBlur(overlay);
4621
                this._bindDestroy(overlay);
4622
                this._syncZIndex(overlay);
4623
 
4624
                this.overlays.push(overlay);
4625
                this.bringToTop(overlay);
4626
 
4627
                registered = true;
4628
 
4629
            } else if (overlay instanceof Array) {
4630
 
4631
                for (i = 0, n = overlay.length; i < n; i++) {
4632
                    registered = this.register(overlay[i]) || registered;
4633
                }
4634
 
4635
            }
4636
 
4637
            return registered;
4638
        },
4639
 
4640
        /**
4641
        * Places the specified Overlay instance on top of all other
4642
        * Overlay instances.
4643
        * @method bringToTop
4644
        * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4645
        * Overlay instance.
4646
        * @param {String} p_oOverlay String representing the id of an
4647
        * Overlay instance.
4648
        */
4649
        bringToTop: function (p_oOverlay) {
4650
 
4651
            var oOverlay = this.find(p_oOverlay),
4652
                nTopZIndex,
4653
                oTopOverlay,
4654
                aOverlays;
4655
 
4656
            if (oOverlay) {
4657
 
4658
                aOverlays = this.overlays;
4659
                aOverlays.sort(this.compareZIndexDesc);
4660
 
4661
                oTopOverlay = aOverlays[0];
4662
 
4663
                if (oTopOverlay) {
4664
                    nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4665
 
4666
                    if (!isNaN(nTopZIndex)) {
4667
 
4668
                        var bRequiresBump = false;
4669
 
4670
                        if (oTopOverlay !== oOverlay) {
4671
                            bRequiresBump = true;
4672
                        } else if (aOverlays.length > 1) {
4673
                            var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4674
                            // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4675
                            if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4676
                                bRequiresBump = true;
4677
                            }
4678
                        }
4679
 
4680
                        if (bRequiresBump) {
4681
                            oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4682
                        }
4683
                    }
4684
                    aOverlays.sort(this.compareZIndexDesc);
4685
                }
4686
            }
4687
        },
4688
 
4689
        /**
4690
        * Attempts to locate an Overlay by instance or ID.
4691
        * @method find
4692
        * @param {Overlay} overlay  An Overlay to locate within the manager
4693
        * @param {String} overlay  An Overlay id to locate within the manager
4694
        * @return {Overlay} The requested Overlay, if found, or null if it
4695
        * cannot be located.
4696
        */
4697
        find: function (overlay) {
4698
 
4699
            var isInstance = overlay instanceof Overlay,
4700
                overlays = this.overlays,
4701
                n = overlays.length,
4702
                found = null,
4703
                o,
4704
                i;
4705
 
4706
            if (isInstance || typeof overlay == "string") {
4707
                for (i = n-1; i >= 0; i--) {
4708
                    o = overlays[i];
4709
                    if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4710
                        found = o;
4711
                        break;
4712
                    }
4713
                }
4714
            }
4715
 
4716
            return found;
4717
        },
4718
 
4719
        /**
4720
        * Used for sorting the manager's Overlays by z-index.
4721
        * @method compareZIndexDesc
4722
        * @private
4723
        * @return {Number} 0, 1, or -1, depending on where the Overlay should
4724
        * fall in the stacking order.
4725
        */
4726
        compareZIndexDesc: function (o1, o2) {
4727
 
4728
            var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4729
                zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4730
 
4731
            if (zIndex1 === null && zIndex2 === null) {
4732
                return 0;
4733
            } else if (zIndex1 === null){
4734
                return 1;
4735
            } else if (zIndex2 === null) {
4736
                return -1;
4737
            } else if (zIndex1 > zIndex2) {
4738
                return -1;
4739
            } else if (zIndex1 < zIndex2) {
4740
                return 1;
4741
            } else {
4742
                return 0;
4743
            }
4744
        },
4745
 
4746
        /**
4747
        * Shows all Overlays in the manager.
4748
        * @method showAll
4749
        */
4750
        showAll: function () {
4751
            var overlays = this.overlays,
4752
                n = overlays.length,
4753
                i;
4754
 
4755
            for (i = n - 1; i >= 0; i--) {
4756
                overlays[i].show();
4757
            }
4758
        },
4759
 
4760
        /**
4761
        * Hides all Overlays in the manager.
4762
        * @method hideAll
4763
        */
4764
        hideAll: function () {
4765
            var overlays = this.overlays,
4766
                n = overlays.length,
4767
                i;
4768
 
4769
            for (i = n - 1; i >= 0; i--) {
4770
                overlays[i].hide();
4771
            }
4772
        },
4773
 
4774
        /**
4775
        * Returns a string representation of the object.
4776
        * @method toString
4777
        * @return {String} The string representation of the OverlayManager
4778
        */
4779
        toString: function () {
4780
            return "OverlayManager";
4781
        }
4782
    };
4783
}());
4784
(function () {
4785
 
4786
    /**
4787
    * ContainerEffect encapsulates animation transitions that are executed when
4788
    * an Overlay is shown or hidden.
4789
    * @namespace YAHOO.widget
4790
    * @class ContainerEffect
4791
    * @constructor
4792
    * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
4793
    * should be associated with
4794
    * @param {Object} attrIn The object literal representing the animation
4795
    * arguments to be used for the animate-in transition. The arguments for
4796
    * this literal are: attributes(object, see YAHOO.util.Anim for description),
4797
    * duration(Number), and method(i.e. Easing.easeIn).
4798
    * @param {Object} attrOut The object literal representing the animation
4799
    * arguments to be used for the animate-out transition. The arguments for
4800
    * this literal are: attributes(object, see YAHOO.util.Anim for description),
4801
    * duration(Number), and method(i.e. Easing.easeIn).
4802
    * @param {HTMLElement} targetElement Optional. The target element that
4803
    * should be animated during the transition. Defaults to overlay.element.
4804
    * @param {class} Optional. The animation class to instantiate. Defaults to
4805
    * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
4806
    */
4807
    YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
4808
 
4809
        if (!animClass) {
4810
            animClass = YAHOO.util.Anim;
4811
        }
4812
 
4813
        /**
4814
        * The overlay to animate
4815
        * @property overlay
4816
        * @type YAHOO.widget.Overlay
4817
        */
4818
        this.overlay = overlay;
4819
 
4820
        /**
4821
        * The animation attributes to use when transitioning into view
4822
        * @property attrIn
4823
        * @type Object
4824
        */
4825
        this.attrIn = attrIn;
4826
 
4827
        /**
4828
        * The animation attributes to use when transitioning out of view
4829
        * @property attrOut
4830
        * @type Object
4831
        */
4832
        this.attrOut = attrOut;
4833
 
4834
        /**
4835
        * The target element to be animated
4836
        * @property targetElement
4837
        * @type HTMLElement
4838
        */
4839
        this.targetElement = targetElement || overlay.element;
4840
 
4841
        /**
4842
        * The animation class to use for animating the overlay
4843
        * @property animClass
4844
        * @type class
4845
        */
4846
        this.animClass = animClass;
4847
    };
4848
 
4849
    var Dom = YAHOO.util.Dom,
4850
        CustomEvent = YAHOO.util.CustomEvent,
4851
        ContainerEffect = YAHOO.widget.ContainerEffect;
4852
 
4853
    /**
4854
    * A pre-configured ContainerEffect instance that can be used for fading
4855
    * an overlay in and out.
4856
    * @method FADE
4857
    * @static
4858
    * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4859
    * @param {Number} dur The duration of the animation
4860
    * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4861
    */
4862
    ContainerEffect.FADE = function (overlay, dur) {
4863
 
4864
        var Easing = YAHOO.util.Easing,
4865
            fin = {
4866
                attributes: {opacity:{from:0, to:1}},
4867
                duration: dur,
4868
                method: Easing.easeIn
4869
            },
4870
            fout = {
4871
                attributes: {opacity:{to:0}},
4872
                duration: dur,
4873
                method: Easing.easeOut
4874
            },
4875
            fade = new ContainerEffect(overlay, fin, fout, overlay.element);
4876
 
4877
        fade.handleUnderlayStart = function() {
4878
            var underlay = this.overlay.underlay;
4879
            if (underlay && YAHOO.env.ua.ie) {
4880
                var hasFilters = (underlay.filters && underlay.filters.length > 0);
4881
                if(hasFilters) {
4882
                    Dom.addClass(overlay.element, "yui-effect-fade");
4883
                }
4884
            }
4885
        };
4886
 
4887
        fade.handleUnderlayComplete = function() {
4888
            var underlay = this.overlay.underlay;
4889
            if (underlay && YAHOO.env.ua.ie) {
4890
                Dom.removeClass(overlay.element, "yui-effect-fade");
4891
            }
4892
        };
4893
 
4894
        fade.handleStartAnimateIn = function (type, args, obj) {
4895
            obj.overlay._fadingIn = true;
4896
 
4897
            Dom.addClass(obj.overlay.element, "hide-select");
4898
 
4899
            if (!obj.overlay.underlay) {
4900
                obj.overlay.cfg.refireEvent("underlay");
4901
            }
4902
 
4903
            obj.handleUnderlayStart();
4904
 
4905
            obj.overlay._setDomVisibility(true);
4906
            Dom.setStyle(obj.overlay.element, "opacity", 0);
4907
        };
4908
 
4909
        fade.handleCompleteAnimateIn = function (type,args,obj) {
4910
            obj.overlay._fadingIn = false;
4911
 
4912
            Dom.removeClass(obj.overlay.element, "hide-select");
4913
 
4914
            if (obj.overlay.element.style.filter) {
4915
                obj.overlay.element.style.filter = null;
4916
            }
4917
 
4918
            obj.handleUnderlayComplete();
4919
 
4920
            obj.overlay.cfg.refireEvent("iframe");
4921
            obj.animateInCompleteEvent.fire();
4922
        };
4923
 
4924
        fade.handleStartAnimateOut = function (type, args, obj) {
4925
            obj.overlay._fadingOut = true;
4926
            Dom.addClass(obj.overlay.element, "hide-select");
4927
            obj.handleUnderlayStart();
4928
        };
4929
 
4930
        fade.handleCompleteAnimateOut =  function (type, args, obj) {
4931
            obj.overlay._fadingOut = false;
4932
            Dom.removeClass(obj.overlay.element, "hide-select");
4933
 
4934
            if (obj.overlay.element.style.filter) {
4935
                obj.overlay.element.style.filter = null;
4936
            }
4937
            obj.overlay._setDomVisibility(false);
4938
            Dom.setStyle(obj.overlay.element, "opacity", 1);
4939
 
4940
            obj.handleUnderlayComplete();
4941
 
4942
            obj.overlay.cfg.refireEvent("iframe");
4943
            obj.animateOutCompleteEvent.fire();
4944
        };
4945
 
4946
        fade.init();
4947
        return fade;
4948
    };
4949
 
4950
 
4951
    /**
4952
    * A pre-configured ContainerEffect instance that can be used for sliding an
4953
    * overlay in and out.
4954
    * @method SLIDE
4955
    * @static
4956
    * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
4957
    * @param {Number} dur The duration of the animation
4958
    * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
4959
    */
4960
    ContainerEffect.SLIDE = function (overlay, dur) {
4961
        var Easing = YAHOO.util.Easing,
4962
 
4963
            x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
4964
            y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
4965
            clientWidth = Dom.getClientWidth(),
4966
            offsetWidth = overlay.element.offsetWidth,
4967
 
4968
            sin =  {
4969
                attributes: { points: { to: [x, y] } },
4970
                duration: dur,
4971
                method: Easing.easeIn
4972
            },
4973
 
4974
            sout = {
4975
                attributes: { points: { to: [(clientWidth + 25), y] } },
4976
                duration: dur,
4977
                method: Easing.easeOut
4978
            },
4979
 
4980
            slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
4981
 
4982
        slide.handleStartAnimateIn = function (type,args,obj) {
4983
            obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
4984
            obj.overlay.element.style.top  = y + "px";
4985
        };
4986
 
4987
        slide.handleTweenAnimateIn = function (type, args, obj) {
4988
 
4989
            var pos = Dom.getXY(obj.overlay.element),
4990
                currentX = pos[0],
4991
                currentY = pos[1];
4992
 
4993
            if (Dom.getStyle(obj.overlay.element, "visibility") ==
4994
                "hidden" && currentX < x) {
4995
 
4996
                obj.overlay._setDomVisibility(true);
4997
 
4998
            }
4999
 
5000
            obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
5001
            obj.overlay.cfg.refireEvent("iframe");
5002
        };
5003
 
5004
        slide.handleCompleteAnimateIn = function (type, args, obj) {
5005
            obj.overlay.cfg.setProperty("xy", [x, y], true);
5006
            obj.startX = x;
5007
            obj.startY = y;
5008
            obj.overlay.cfg.refireEvent("iframe");
5009
            obj.animateInCompleteEvent.fire();
5010
        };
5011
 
5012
        slide.handleStartAnimateOut = function (type, args, obj) {
5013
 
5014
            var vw = Dom.getViewportWidth(),
5015
                pos = Dom.getXY(obj.overlay.element),
5016
                yso = pos[1];
5017
 
5018
            obj.animOut.attributes.points.to = [(vw + 25), yso];
5019
        };
5020
 
5021
        slide.handleTweenAnimateOut = function (type, args, obj) {
5022
 
5023
            var pos = Dom.getXY(obj.overlay.element),
5024
                xto = pos[0],
5025
                yto = pos[1];
5026
 
5027
            obj.overlay.cfg.setProperty("xy", [xto, yto], true);
5028
            obj.overlay.cfg.refireEvent("iframe");
5029
        };
5030
 
5031
        slide.handleCompleteAnimateOut = function (type, args, obj) {
5032
            obj.overlay._setDomVisibility(false);
5033
 
5034
            obj.overlay.cfg.setProperty("xy", [x, y]);
5035
            obj.animateOutCompleteEvent.fire();
5036
        };
5037
 
5038
        slide.init();
5039
        return slide;
5040
    };
5041
 
5042
    ContainerEffect.prototype = {
5043
 
5044
        /**
5045
        * Initializes the animation classes and events.
5046
        * @method init
5047
        */
5048
        init: function () {
5049
 
5050
            this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
5051
            this.beforeAnimateInEvent.signature = CustomEvent.LIST;
5052
 
5053
            this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
5054
            this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
5055
 
5056
            this.animateInCompleteEvent = this.createEvent("animateInComplete");
5057
            this.animateInCompleteEvent.signature = CustomEvent.LIST;
5058
 
5059
            this.animateOutCompleteEvent = this.createEvent("animateOutComplete");
5060
            this.animateOutCompleteEvent.signature = CustomEvent.LIST;
5061
 
5062
            this.animIn = new this.animClass(
5063
                this.targetElement,
5064
                this.attrIn.attributes,
5065
                this.attrIn.duration,
5066
                this.attrIn.method);
5067
 
5068
            this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
5069
            this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
5070
            this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);
5071
 
5072
            this.animOut = new this.animClass(
5073
                this.targetElement,
5074
                this.attrOut.attributes,
5075
                this.attrOut.duration,
5076
                this.attrOut.method);
5077
 
5078
            this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
5079
            this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
5080
            this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, this);
5081
 
5082
        },
5083
 
5084
        /**
5085
        * Triggers the in-animation.
5086
        * @method animateIn
5087
        */
5088
        animateIn: function () {
5089
            this._stopAnims(this.lastFrameOnStop);
5090
            this.beforeAnimateInEvent.fire();
5091
            this.animIn.animate();
5092
        },
5093
 
5094
        /**
5095
        * Triggers the out-animation.
5096
        * @method animateOut
5097
        */
5098
        animateOut: function () {
5099
            this._stopAnims(this.lastFrameOnStop);
5100
            this.beforeAnimateOutEvent.fire();
5101
            this.animOut.animate();
5102
        },
5103
 
5104
        /**
5105
         * Flag to define whether Anim should jump to the last frame,
5106
         * when animateIn or animateOut is stopped.
5107
         *
5108
         * @property lastFrameOnStop
5109
         * @default true
5110
         * @type boolean
5111
         */
5112
        lastFrameOnStop : true,
5113
 
5114
        /**
5115
         * Stops both animIn and animOut instances, if in progress.
5116
         *
5117
         * @method _stopAnims
5118
         * @param {boolean} finish If true, animation will jump to final frame.
5119
         * @protected
5120
         */
5121
        _stopAnims : function(finish) {
5122
            if (this.animOut && this.animOut.isAnimated()) {
5123
                this.animOut.stop(finish);
5124
            }
5125
 
5126
            if (this.animIn && this.animIn.isAnimated()) {
5127
                this.animIn.stop(finish);
5128
            }
5129
        },
5130
 
5131
        /**
5132
        * The default onStart handler for the in-animation.
5133
        * @method handleStartAnimateIn
5134
        * @param {String} type The CustomEvent type
5135
        * @param {Object[]} args The CustomEvent arguments
5136
        * @param {Object} obj The scope object
5137
        */
5138
        handleStartAnimateIn: function (type, args, obj) { },
5139
 
5140
        /**
5141
        * The default onTween handler for the in-animation.
5142
        * @method handleTweenAnimateIn
5143
        * @param {String} type The CustomEvent type
5144
        * @param {Object[]} args The CustomEvent arguments
5145
        * @param {Object} obj The scope object
5146
        */
5147
        handleTweenAnimateIn: function (type, args, obj) { },
5148
 
5149
        /**
5150
        * The default onComplete handler for the in-animation.
5151
        * @method handleCompleteAnimateIn
5152
        * @param {String} type The CustomEvent type
5153
        * @param {Object[]} args The CustomEvent arguments
5154
        * @param {Object} obj The scope object
5155
        */
5156
        handleCompleteAnimateIn: function (type, args, obj) { },
5157
 
5158
        /**
5159
        * The default onStart handler for the out-animation.
5160
        * @method handleStartAnimateOut
5161
        * @param {String} type The CustomEvent type
5162
        * @param {Object[]} args The CustomEvent arguments
5163
        * @param {Object} obj The scope object
5164
        */
5165
        handleStartAnimateOut: function (type, args, obj) { },
5166
 
5167
        /**
5168
        * The default onTween handler for the out-animation.
5169
        * @method handleTweenAnimateOut
5170
        * @param {String} type The CustomEvent type
5171
        * @param {Object[]} args The CustomEvent arguments
5172
        * @param {Object} obj The scope object
5173
        */
5174
        handleTweenAnimateOut: function (type, args, obj) { },
5175
 
5176
        /**
5177
        * The default onComplete handler for the out-animation.
5178
        * @method handleCompleteAnimateOut
5179
        * @param {String} type The CustomEvent type
5180
        * @param {Object[]} args The CustomEvent arguments
5181
        * @param {Object} obj The scope object
5182
        */
5183
        handleCompleteAnimateOut: function (type, args, obj) { },
5184
 
5185
        /**
5186
        * Returns a string representation of the object.
5187
        * @method toString
5188
        * @return {String} The string representation of the ContainerEffect
5189
        */
5190
        toString: function () {
5191
            var output = "ContainerEffect";
5192
            if (this.overlay) {
5193
                output += " [" + this.overlay.toString() + "]";
5194
            }
5195
            return output;
5196
        }
5197
    };
5198
 
5199
    YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
5200
 
5201
})();
5202
YAHOO.register("containercore", YAHOO.widget.Module, {version: "2.9.0", build: "2800"});
5203
 
5204
}, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event"]});