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