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) { Y.use('yui2-container'); }, '3.3.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event"]});
2
YUI.add('yui2-container', function(Y) {
3
    var YAHOO    = Y.YUI2;
4
    /*
5
Copyright (c) 2011, Yahoo! Inc. All rights reserved.
6
Code licensed under the BSD License:
7
http://developer.yahoo.com/yui/license.html
8
version: 2.9.0
9
*/
10
(function () {
11
 
12
    /**
13
    * Config is a utility used within an Object to allow the implementer to
14
    * maintain a list of local configuration properties and listen for changes
15
    * to those properties dynamically using CustomEvent. The initial values are
16
    * also maintained so that the configuration can be reset at any given point
17
    * to its initial state.
18
    * @namespace YAHOO.util
19
    * @class Config
20
    * @constructor
21
    * @param {Object} owner The owner Object to which this Config Object belongs
22
    */
23
    YAHOO.util.Config = function (owner) {
24
 
25
        if (owner) {
26
            this.init(owner);
27
        }
28
 
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
            var property = this.config[key];
157
 
158
            if (property && property.event) {
159
                property.event.fire(value);
160
            }
161
        },
162
 
163
        /**
164
        * Adds a property to the Config Object's private config hash.
165
        * @method addProperty
166
        * @param {String} key The configuration property's name
167
        * @param {Object} propertyObject The Object containing all of this
168
        * property's arguments
169
        */
170
        addProperty: function ( key, propertyObject ) {
171
            key = key.toLowerCase();
172
 
173
            this.config[key] = propertyObject;
174
 
175
            propertyObject.event = this.createEvent(key, { scope: this.owner });
176
            propertyObject.event.signature = CustomEvent.LIST;
177
 
178
 
179
            propertyObject.key = key;
180
 
181
            if (propertyObject.handler) {
182
                propertyObject.event.subscribe(propertyObject.handler,
183
                    this.owner);
184
            }
185
 
186
            this.setProperty(key, propertyObject.value, true);
187
 
188
            if (! propertyObject.suppressEvent) {
189
                this.queueProperty(key, propertyObject.value);
190
            }
191
 
192
        },
193
 
194
        /**
195
        * Returns a key-value configuration map of the values currently set in
196
        * the Config Object.
197
        * @method getConfig
198
        * @return {Object} The current config, represented in a key-value map
199
        */
200
        getConfig: function () {
201
 
202
            var cfg = {},
203
                currCfg = this.config,
204
                prop,
205
                property;
206
 
207
            for (prop in currCfg) {
208
                if (Lang.hasOwnProperty(currCfg, prop)) {
209
                    property = currCfg[prop];
210
                    if (property && property.event) {
211
                        cfg[prop] = property.value;
212
                    }
213
                }
214
            }
215
 
216
            return cfg;
217
        },
218
 
219
        /**
220
        * Returns the value of specified property.
221
        * @method getProperty
222
        * @param {String} key The name of the property
223
        * @return {Object}  The value of the specified property
224
        */
225
        getProperty: function (key) {
226
            var property = this.config[key.toLowerCase()];
227
            if (property && property.event) {
228
                return property.value;
229
            } else {
230
                return undefined;
231
            }
232
        },
233
 
234
        /**
235
        * Resets the specified property's value to its initial value.
236
        * @method resetProperty
237
        * @param {String} key The name of the property
238
        * @return {Boolean} True is the property was reset, false if not
239
        */
240
        resetProperty: function (key) {
241
            key = key.toLowerCase();
242
 
243
            var property = this.config[key];
244
 
245
            if (property && property.event) {
246
                if (key in this.initialConfig) {
247
                    this.setProperty(key, this.initialConfig[key]);
248
                    return true;
249
                }
250
            } else {
251
                return false;
252
            }
253
        },
254
 
255
        /**
256
        * Sets the value of a property. If the silent property is passed as
257
        * true, the property's event will not be fired.
258
        * @method setProperty
259
        * @param {String} key The name of the property
260
        * @param {String} value The value to set the property to
261
        * @param {Boolean} silent Whether the value should be set silently,
262
        * without firing the property event.
263
        * @return {Boolean} True, if the set was successful, false if it failed.
264
        */
265
        setProperty: function (key, value, silent) {
266
 
267
            var property;
268
 
269
            key = key.toLowerCase();
270
 
271
            if (this.queueInProgress && ! silent) {
272
                // Currently running through a queue...
273
                this.queueProperty(key,value);
274
                return true;
275
 
276
            } else {
277
                property = this.config[key];
278
                if (property && property.event) {
279
                    if (property.validator && !property.validator(value)) {
280
                        return false;
281
                    } else {
282
                        property.value = value;
283
                        if (! silent) {
284
                            this.fireEvent(key, value);
285
                            this.configChangedEvent.fire([key, value]);
286
                        }
287
                        return true;
288
                    }
289
                } else {
290
                    return false;
291
                }
292
            }
293
        },
294
 
295
        /**
296
        * Sets the value of a property and queues its event to execute. If the
297
        * event is already scheduled to execute, it is
298
        * moved from its current position to the end of the queue.
299
        * @method queueProperty
300
        * @param {String} key The name of the property
301
        * @param {String} value The value to set the property to
302
        * @return {Boolean}  true, if the set was successful, false if
303
        * it failed.
304
        */
305
        queueProperty: function (key, value) {
306
 
307
            key = key.toLowerCase();
308
 
309
            var property = this.config[key],
310
                foundDuplicate = false,
311
                iLen,
312
                queueItem,
313
                queueItemKey,
314
                queueItemValue,
315
                sLen,
316
                supercedesCheck,
317
                qLen,
318
                queueItemCheck,
319
                queueItemCheckKey,
320
                queueItemCheckValue,
321
                i,
322
                s,
323
                q;
324
 
325
            if (property && property.event) {
326
 
327
                if (!Lang.isUndefined(value) && property.validator &&
328
                    !property.validator(value)) { // validator
329
                    return false;
330
                } else {
331
 
332
                    if (!Lang.isUndefined(value)) {
333
                        property.value = value;
334
                    } else {
335
                        value = property.value;
336
                    }
337
 
338
                    foundDuplicate = false;
339
                    iLen = this.eventQueue.length;
340
 
341
                    for (i = 0; i < iLen; i++) {
342
                        queueItem = this.eventQueue[i];
343
 
344
                        if (queueItem) {
345
                            queueItemKey = queueItem[0];
346
                            queueItemValue = queueItem[1];
347
 
348
                            if (queueItemKey == key) {
349
 
350
                                /*
351
                                    found a dupe... push to end of queue, null
352
                                    current item, and break
353
                                */
354
 
355
                                this.eventQueue[i] = null;
356
 
357
                                this.eventQueue.push(
358
                                    [key, (!Lang.isUndefined(value) ?
359
                                    value : queueItemValue)]);
360
 
361
                                foundDuplicate = true;
362
                                break;
363
                            }
364
                        }
365
                    }
366
 
367
                    // this is a refire, or a new property in the queue
368
 
369
                    if (! foundDuplicate && !Lang.isUndefined(value)) {
370
                        this.eventQueue.push([key, value]);
371
                    }
372
                }
373
 
374
                if (property.supercedes) {
375
 
376
                    sLen = property.supercedes.length;
377
 
378
                    for (s = 0; s < sLen; s++) {
379
 
380
                        supercedesCheck = property.supercedes[s];
381
                        qLen = this.eventQueue.length;
382
 
383
                        for (q = 0; q < qLen; q++) {
384
                            queueItemCheck = this.eventQueue[q];
385
 
386
                            if (queueItemCheck) {
387
                                queueItemCheckKey = queueItemCheck[0];
388
                                queueItemCheckValue = queueItemCheck[1];
389
 
390
                                if (queueItemCheckKey ==
391
                                    supercedesCheck.toLowerCase() ) {
392
 
393
                                    this.eventQueue.push([queueItemCheckKey,
394
                                        queueItemCheckValue]);
395
 
396
                                    this.eventQueue[q] = null;
397
                                    break;
398
 
399
                                }
400
                            }
401
                        }
402
                    }
403
                }
404
 
405
 
406
                return true;
407
            } else {
408
                return false;
409
            }
410
        },
411
 
412
        /**
413
        * Fires the event for a property using the property's current value.
414
        * @method refireEvent
415
        * @param {String} key The name of the property
416
        */
417
        refireEvent: function (key) {
418
 
419
            key = key.toLowerCase();
420
 
421
            var property = this.config[key];
422
 
423
            if (property && property.event &&
424
 
425
                !Lang.isUndefined(property.value)) {
426
 
427
                if (this.queueInProgress) {
428
 
429
                    this.queueProperty(key);
430
 
431
                } else {
432
 
433
                    this.fireEvent(key, property.value);
434
 
435
                }
436
 
437
            }
438
        },
439
 
440
        /**
441
        * Applies a key-value Object literal to the configuration, replacing
442
        * any existing values, and queueing the property events.
443
        * Although the values will be set, fireQueue() must be called for their
444
        * associated events to execute.
445
        * @method applyConfig
446
        * @param {Object} userConfig The configuration Object literal
447
        * @param {Boolean} init  When set to true, the initialConfig will
448
        * be set to the userConfig passed in, so that calling a reset will
449
        * reset the properties to the passed values.
450
        */
451
        applyConfig: function (userConfig, init) {
452
 
453
            var sKey,
454
                oConfig;
455
 
456
            if (init) {
457
                oConfig = {};
458
                for (sKey in userConfig) {
459
                    if (Lang.hasOwnProperty(userConfig, sKey)) {
460
                        oConfig[sKey.toLowerCase()] = userConfig[sKey];
461
                    }
462
                }
463
                this.initialConfig = oConfig;
464
            }
465
 
466
            for (sKey in userConfig) {
467
                if (Lang.hasOwnProperty(userConfig, sKey)) {
468
                    this.queueProperty(sKey, userConfig[sKey]);
469
                }
470
            }
471
        },
472
 
473
        /**
474
        * Refires the events for all configuration properties using their
475
        * current values.
476
        * @method refresh
477
        */
478
        refresh: function () {
479
 
480
            var prop;
481
 
482
            for (prop in this.config) {
483
                if (Lang.hasOwnProperty(this.config, prop)) {
484
                    this.refireEvent(prop);
485
                }
486
            }
487
        },
488
 
489
        /**
490
        * Fires the normalized list of queued property change events
491
        * @method fireQueue
492
        */
493
        fireQueue: function () {
494
 
495
            var i,
496
                queueItem,
497
                key,
498
                value,
499
                property;
500
 
501
            this.queueInProgress = true;
502
            for (i = 0;i < this.eventQueue.length; i++) {
503
                queueItem = this.eventQueue[i];
504
                if (queueItem) {
505
 
506
                    key = queueItem[0];
507
                    value = queueItem[1];
508
                    property = this.config[key];
509
 
510
                    property.value = value;
511
 
512
                    // Clear out queue entry, to avoid it being
513
                    // re-added to the queue by any queueProperty/supercedes
514
                    // calls which are invoked during fireEvent
515
                    this.eventQueue[i] = null;
516
 
517
                    this.fireEvent(key,value);
518
                }
519
            }
520
 
521
            this.queueInProgress = false;
522
            this.eventQueue = [];
523
        },
524
 
525
        /**
526
        * Subscribes an external handler to the change event for any
527
        * given property.
528
        * @method subscribeToConfigEvent
529
        * @param {String} key The property name
530
        * @param {Function} handler The handler function to use subscribe to
531
        * the property's event
532
        * @param {Object} obj The Object to use for scoping the event handler
533
        * (see CustomEvent documentation)
534
        * @param {Boolean} overrideContext Optional. If true, will override
535
        * "this" within the handler to map to the scope Object passed into the
536
        * method.
537
        * @return {Boolean} True, if the subscription was successful,
538
        * otherwise false.
539
        */
540
        subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
541
 
542
            var property = this.config[key.toLowerCase()];
543
 
544
            if (property && property.event) {
545
                if (!Config.alreadySubscribed(property.event, handler, obj)) {
546
                    property.event.subscribe(handler, obj, overrideContext);
547
                }
548
                return true;
549
            } else {
550
                return false;
551
            }
552
 
553
        },
554
 
555
        /**
556
        * Unsubscribes an external handler from the change event for any
557
        * given property.
558
        * @method unsubscribeFromConfigEvent
559
        * @param {String} key The property name
560
        * @param {Function} handler The handler function to use subscribe to
561
        * the property's event
562
        * @param {Object} obj The Object to use for scoping the event
563
        * handler (see CustomEvent documentation)
564
        * @return {Boolean} True, if the unsubscription was successful,
565
        * otherwise false.
566
        */
567
        unsubscribeFromConfigEvent: function (key, handler, obj) {
568
            var property = this.config[key.toLowerCase()];
569
            if (property && property.event) {
570
                return property.event.unsubscribe(handler, obj);
571
            } else {
572
                return false;
573
            }
574
        },
575
 
576
        /**
577
        * Returns a string representation of the Config object
578
        * @method toString
579
        * @return {String} The Config object in string format.
580
        */
581
        toString: function () {
582
            var output = "Config";
583
            if (this.owner) {
584
                output += " [" + this.owner.toString() + "]";
585
            }
586
            return output;
587
        },
588
 
589
        /**
590
        * Returns a string representation of the Config object's current
591
        * CustomEvent queue
592
        * @method outputEventQueue
593
        * @return {String} The string list of CustomEvents currently queued
594
        * for execution
595
        */
596
        outputEventQueue: function () {
597
 
598
            var output = "",
599
                queueItem,
600
                q,
601
                nQueue = this.eventQueue.length;
602
 
603
            for (q = 0; q < nQueue; q++) {
604
                queueItem = this.eventQueue[q];
605
                if (queueItem) {
606
                    output += queueItem[0] + "=" + queueItem[1] + ", ";
607
                }
608
            }
609
            return output;
610
        },
611
 
612
        /**
613
        * Sets all properties to null, unsubscribes all listeners from each
614
        * property's change event and all listeners from the configChangedEvent.
615
        * @method destroy
616
        */
617
        destroy: function () {
618
 
619
            var oConfig = this.config,
620
                sProperty,
621
                oProperty;
622
 
623
 
624
            for (sProperty in oConfig) {
625
 
626
                if (Lang.hasOwnProperty(oConfig, sProperty)) {
627
 
628
                    oProperty = oConfig[sProperty];
629
 
630
                    oProperty.event.unsubscribeAll();
631
                    oProperty.event = null;
632
 
633
                }
634
 
635
            }
636
 
637
            this.configChangedEvent.unsubscribeAll();
638
 
639
            this.configChangedEvent = null;
640
            this.owner = null;
641
            this.config = null;
642
            this.initialConfig = null;
643
            this.eventQueue = null;
644
 
645
        }
646
 
647
    };
648
 
649
 
650
 
651
    /**
652
    * Checks to determine if a particular function/Object pair are already
653
    * subscribed to the specified CustomEvent
654
    * @method YAHOO.util.Config.alreadySubscribed
655
    * @static
656
    * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
657
    * the subscriptions
658
    * @param {Function} fn The function to look for in the subscribers list
659
    * @param {Object} obj The execution scope Object for the subscription
660
    * @return {Boolean} true, if the function/Object pair is already subscribed
661
    * to the CustomEvent passed in
662
    */
663
    Config.alreadySubscribed = function (evt, fn, obj) {
664
 
665
        var nSubscribers = evt.subscribers.length,
666
            subsc,
667
            i;
668
 
669
        if (nSubscribers > 0) {
670
            i = nSubscribers - 1;
671
            do {
672
                subsc = evt.subscribers[i];
673
                if (subsc && subsc.obj == obj && subsc.fn == fn) {
674
                    return true;
675
                }
676
            }
677
            while (i--);
678
        }
679
 
680
        return false;
681
 
682
    };
683
 
684
    YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
685
 
686
}());
687
(function () {
688
 
689
    /**
690
    * The Container family of components is designed to enable developers to
691
    * create different kinds of content-containing modules on the web. Module
692
    * and Overlay are the most basic containers, and they can be used directly
693
    * or extended to build custom containers. Also part of the Container family
694
    * are four UI controls that extend Module and Overlay: Tooltip, Panel,
695
    * Dialog, and SimpleDialog.
696
    * @module container
697
    * @title Container
698
    * @requires yahoo, dom, event
699
    * @optional dragdrop, animation, button
700
    */
701
 
702
    /**
703
    * Module is a JavaScript representation of the Standard Module Format.
704
    * Standard Module Format is a simple standard for markup containers where
705
    * child nodes representing the header, body, and footer of the content are
706
    * denoted using the CSS classes "hd", "bd", and "ft" respectively.
707
    * Module is the base class for all other classes in the YUI
708
    * Container package.
709
    * @namespace YAHOO.widget
710
    * @class Module
711
    * @constructor
712
    * @param {String} el The element ID representing the Module <em>OR</em>
713
    * @param {HTMLElement} el The element representing the Module
714
    * @param {Object} userConfig The configuration Object literal containing
715
    * the configuration that should be set for this module. See configuration
716
    * documentation for more details.
717
    */
718
    YAHOO.widget.Module = function (el, userConfig) {
719
        if (el) {
720
            this.init(el, userConfig);
721
        } else {
722
        }
723
    };
724
 
725
    var Dom = YAHOO.util.Dom,
726
        Config = YAHOO.util.Config,
727
        Event = YAHOO.util.Event,
728
        CustomEvent = YAHOO.util.CustomEvent,
729
        Module = YAHOO.widget.Module,
730
        UA = YAHOO.env.ua,
731
 
732
        m_oModuleTemplate,
733
        m_oHeaderTemplate,
734
        m_oBodyTemplate,
735
        m_oFooterTemplate,
736
 
737
        /**
738
        * Constant representing the name of the Module's events
739
        * @property EVENT_TYPES
740
        * @private
741
        * @final
742
        * @type Object
743
        */
744
        EVENT_TYPES = {
745
            "BEFORE_INIT": "beforeInit",
746
            "INIT": "init",
747
            "APPEND": "append",
748
            "BEFORE_RENDER": "beforeRender",
749
            "RENDER": "render",
750
            "CHANGE_HEADER": "changeHeader",
751
            "CHANGE_BODY": "changeBody",
752
            "CHANGE_FOOTER": "changeFooter",
753
            "CHANGE_CONTENT": "changeContent",
754
            "DESTROY": "destroy",
755
            "BEFORE_SHOW": "beforeShow",
756
            "SHOW": "show",
757
            "BEFORE_HIDE": "beforeHide",
758
            "HIDE": "hide"
759
        },
760
 
761
        /**
762
        * Constant representing the Module's configuration properties
763
        * @property DEFAULT_CONFIG
764
        * @private
765
        * @final
766
        * @type Object
767
        */
768
        DEFAULT_CONFIG = {
769
 
770
            "VISIBLE": {
771
                key: "visible",
772
                value: true,
773
                validator: YAHOO.lang.isBoolean
774
            },
775
 
776
            "EFFECT": {
777
                key: "effect",
778
                suppressEvent: true,
779
                supercedes: ["visible"]
780
            },
781
 
782
            "MONITOR_RESIZE": {
783
                key: "monitorresize",
784
                value: true
785
            },
786
 
787
            "APPEND_TO_DOCUMENT_BODY": {
788
                key: "appendtodocumentbody",
789
                value: false
790
            }
791
        };
792
 
793
    /**
794
    * Constant representing the prefix path to use for non-secure images
795
    * @property YAHOO.widget.Module.IMG_ROOT
796
    * @static
797
    * @final
798
    * @type String
799
    */
800
    Module.IMG_ROOT = null;
801
 
802
    /**
803
    * Constant representing the prefix path to use for securely served images
804
    * @property YAHOO.widget.Module.IMG_ROOT_SSL
805
    * @static
806
    * @final
807
    * @type String
808
    */
809
    Module.IMG_ROOT_SSL = null;
810
 
811
    /**
812
    * Constant for the default CSS class name that represents a Module
813
    * @property YAHOO.widget.Module.CSS_MODULE
814
    * @static
815
    * @final
816
    * @type String
817
    */
818
    Module.CSS_MODULE = "yui-module";
819
 
820
    /**
821
    * 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.
822
    * @property YAHOO.widget.Module.CSS_HEADER
823
    * @static
824
    * @final
825
    * @type String
826
    */
827
    Module.CSS_HEADER = "hd";
828
 
829
    /**
830
    * 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.
831
    * @property YAHOO.widget.Module.CSS_BODY
832
    * @static
833
    * @final
834
    * @type String
835
    */
836
    Module.CSS_BODY = "bd";
837
 
838
    /**
839
    * 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.
840
    * @property YAHOO.widget.Module.CSS_FOOTER
841
    * @static
842
    * @final
843
    * @type String
844
    */
845
    Module.CSS_FOOTER = "ft";
846
 
847
    /**
848
    * Constant representing the url for the "src" attribute of the iframe
849
    * used to monitor changes to the browser's base font size
850
    * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
851
    * @static
852
    * @final
853
    * @type String
854
    */
855
    Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
856
 
857
    /**
858
    * Constant representing the buffer amount (in pixels) to use when positioning
859
    * the text resize monitor offscreen. The resize monitor is positioned
860
    * offscreen by an amount eqaul to its offsetHeight + the buffer value.
861
    *
862
    * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
863
    * @static
864
    * @type Number
865
    */
866
    // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
867
    Module.RESIZE_MONITOR_BUFFER = 1;
868
 
869
    /**
870
    * Singleton CustomEvent fired when the font size is changed in the browser.
871
    * Opera's "zoom" functionality currently does not support text
872
    * size detection.
873
    * @event YAHOO.widget.Module.textResizeEvent
874
    */
875
    Module.textResizeEvent = new CustomEvent("textResize");
876
 
877
    /**
878
     * Helper utility method, which forces a document level
879
     * redraw for Opera, which can help remove repaint
880
     * irregularities after applying DOM changes.
881
     *
882
     * @method YAHOO.widget.Module.forceDocumentRedraw
883
     * @static
884
     */
885
    Module.forceDocumentRedraw = function() {
886
        var docEl = document.documentElement;
887
        if (docEl) {
888
            docEl.className += " ";
889
            docEl.className = YAHOO.lang.trim(docEl.className);
890
        }
891
    };
892
 
893
    function createModuleTemplate() {
894
 
895
        if (!m_oModuleTemplate) {
896
            m_oModuleTemplate = document.createElement("div");
897
 
898
            m_oModuleTemplate.innerHTML = ("<div class=\"" +
899
                Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
900
                Module.CSS_BODY + "\"></div><div class=\"" +
901
                Module.CSS_FOOTER + "\"></div>");
902
 
903
            m_oHeaderTemplate = m_oModuleTemplate.firstChild;
904
            m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
905
            m_oFooterTemplate = m_oBodyTemplate.nextSibling;
906
        }
907
 
908
        return m_oModuleTemplate;
909
    }
910
 
911
    function createHeader() {
912
        if (!m_oHeaderTemplate) {
913
            createModuleTemplate();
914
        }
915
        return (m_oHeaderTemplate.cloneNode(false));
916
    }
917
 
918
    function createBody() {
919
        if (!m_oBodyTemplate) {
920
            createModuleTemplate();
921
        }
922
        return (m_oBodyTemplate.cloneNode(false));
923
    }
924
 
925
    function createFooter() {
926
        if (!m_oFooterTemplate) {
927
            createModuleTemplate();
928
        }
929
        return (m_oFooterTemplate.cloneNode(false));
930
    }
931
 
932
    Module.prototype = {
933
 
934
        /**
935
        * The class's constructor function
936
        * @property contructor
937
        * @type Function
938
        */
939
        constructor: Module,
940
 
941
        /**
942
        * The main module element that contains the header, body, and footer
943
        * @property element
944
        * @type HTMLElement
945
        */
946
        element: null,
947
 
948
        /**
949
        * The header element, denoted with CSS class "hd"
950
        * @property header
951
        * @type HTMLElement
952
        */
953
        header: null,
954
 
955
        /**
956
        * The body element, denoted with CSS class "bd"
957
        * @property body
958
        * @type HTMLElement
959
        */
960
        body: null,
961
 
962
        /**
963
        * The footer element, denoted with CSS class "ft"
964
        * @property footer
965
        * @type HTMLElement
966
        */
967
        footer: null,
968
 
969
        /**
970
        * The id of the element
971
        * @property id
972
        * @type String
973
        */
974
        id: null,
975
 
976
        /**
977
        * A string representing the root path for all images created by
978
        * a Module instance.
979
        * @deprecated It is recommend that any images for a Module be applied
980
        * via CSS using the "background-image" property.
981
        * @property imageRoot
982
        * @type String
983
        */
984
        imageRoot: Module.IMG_ROOT,
985
 
986
        /**
987
        * Initializes the custom events for Module which are fired
988
        * automatically at appropriate times by the Module class.
989
        * @method initEvents
990
        */
991
        initEvents: function () {
992
 
993
            var SIGNATURE = CustomEvent.LIST;
994
 
995
            /**
996
            * CustomEvent fired prior to class initalization.
997
            * @event beforeInitEvent
998
            * @param {class} classRef class reference of the initializing
999
            * class, such as this.beforeInitEvent.fire(Module)
1000
            */
1001
            this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
1002
            this.beforeInitEvent.signature = SIGNATURE;
1003
 
1004
            /**
1005
            * CustomEvent fired after class initalization.
1006
            * @event initEvent
1007
            * @param {class} classRef class reference of the initializing
1008
            * class, such as this.beforeInitEvent.fire(Module)
1009
            */
1010
            this.initEvent = this.createEvent(EVENT_TYPES.INIT);
1011
            this.initEvent.signature = SIGNATURE;
1012
 
1013
            /**
1014
            * CustomEvent fired when the Module is appended to the DOM
1015
            * @event appendEvent
1016
            */
1017
            this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
1018
            this.appendEvent.signature = SIGNATURE;
1019
 
1020
            /**
1021
            * CustomEvent fired before the Module is rendered
1022
            * @event beforeRenderEvent
1023
            */
1024
            this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
1025
            this.beforeRenderEvent.signature = SIGNATURE;
1026
 
1027
            /**
1028
            * CustomEvent fired after the Module is rendered
1029
            * @event renderEvent
1030
            */
1031
            this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
1032
            this.renderEvent.signature = SIGNATURE;
1033
 
1034
            /**
1035
            * CustomEvent fired when the header content of the Module
1036
            * is modified
1037
            * @event changeHeaderEvent
1038
            * @param {String/HTMLElement} content String/element representing
1039
            * the new header content
1040
            */
1041
            this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
1042
            this.changeHeaderEvent.signature = SIGNATURE;
1043
 
1044
            /**
1045
            * CustomEvent fired when the body content of the Module is modified
1046
            * @event changeBodyEvent
1047
            * @param {String/HTMLElement} content String/element representing
1048
            * the new body content
1049
            */
1050
            this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
1051
            this.changeBodyEvent.signature = SIGNATURE;
1052
 
1053
            /**
1054
            * CustomEvent fired when the footer content of the Module
1055
            * is modified
1056
            * @event changeFooterEvent
1057
            * @param {String/HTMLElement} content String/element representing
1058
            * the new footer content
1059
            */
1060
            this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
1061
            this.changeFooterEvent.signature = SIGNATURE;
1062
 
1063
            /**
1064
            * CustomEvent fired when the content of the Module is modified
1065
            * @event changeContentEvent
1066
            */
1067
            this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
1068
            this.changeContentEvent.signature = SIGNATURE;
1069
 
1070
            /**
1071
            * CustomEvent fired when the Module is destroyed
1072
            * @event destroyEvent
1073
            */
1074
            this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
1075
            this.destroyEvent.signature = SIGNATURE;
1076
 
1077
            /**
1078
            * CustomEvent fired before the Module is shown
1079
            * @event beforeShowEvent
1080
            */
1081
            this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
1082
            this.beforeShowEvent.signature = SIGNATURE;
1083
 
1084
            /**
1085
            * CustomEvent fired after the Module is shown
1086
            * @event showEvent
1087
            */
1088
            this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
1089
            this.showEvent.signature = SIGNATURE;
1090
 
1091
            /**
1092
            * CustomEvent fired before the Module is hidden
1093
            * @event beforeHideEvent
1094
            */
1095
            this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
1096
            this.beforeHideEvent.signature = SIGNATURE;
1097
 
1098
            /**
1099
            * CustomEvent fired after the Module is hidden
1100
            * @event hideEvent
1101
            */
1102
            this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
1103
            this.hideEvent.signature = SIGNATURE;
1104
        },
1105
 
1106
        /**
1107
        * String identifying whether the current platform is windows or mac. This property
1108
        * currently only identifies these 2 platforms, and returns false otherwise.
1109
        * @property platform
1110
        * @deprecated Use YAHOO.env.ua
1111
        * @type {String|Boolean}
1112
        */
1113
        platform: function () {
1114
            var ua = navigator.userAgent.toLowerCase();
1115
 
1116
            if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
1117
                return "windows";
1118
            } else if (ua.indexOf("macintosh") != -1) {
1119
                return "mac";
1120
            } else {
1121
                return false;
1122
            }
1123
        }(),
1124
 
1125
        /**
1126
        * String representing the user-agent of the browser
1127
        * @deprecated Use YAHOO.env.ua
1128
        * @property browser
1129
        * @type {String|Boolean}
1130
        */
1131
        browser: function () {
1132
            var ua = navigator.userAgent.toLowerCase();
1133
            /*
1134
                 Check Opera first in case of spoof and check Safari before
1135
                 Gecko since Safari's user agent string includes "like Gecko"
1136
            */
1137
            if (ua.indexOf('opera') != -1) {
1138
                return 'opera';
1139
            } else if (ua.indexOf('msie 7') != -1) {
1140
                return 'ie7';
1141
            } else if (ua.indexOf('msie') != -1) {
1142
                return 'ie';
1143
            } else if (ua.indexOf('safari') != -1) {
1144
                return 'safari';
1145
            } else if (ua.indexOf('gecko') != -1) {
1146
                return 'gecko';
1147
            } else {
1148
                return false;
1149
            }
1150
        }(),
1151
 
1152
        /**
1153
        * Boolean representing whether or not the current browsing context is
1154
        * secure (https)
1155
        * @property isSecure
1156
        * @type Boolean
1157
        */
1158
        isSecure: function () {
1159
            if (window.location.href.toLowerCase().indexOf("https") === 0) {
1160
                return true;
1161
            } else {
1162
                return false;
1163
            }
1164
        }(),
1165
 
1166
        /**
1167
        * Initializes the custom events for Module which are fired
1168
        * automatically at appropriate times by the Module class.
1169
        */
1170
        initDefaultConfig: function () {
1171
            // Add properties //
1172
            /**
1173
            * Specifies whether the Module is visible on the page.
1174
            * @config visible
1175
            * @type Boolean
1176
            * @default true
1177
            */
1178
            this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
1179
                handler: this.configVisible,
1180
                value: DEFAULT_CONFIG.VISIBLE.value,
1181
                validator: DEFAULT_CONFIG.VISIBLE.validator
1182
            });
1183
 
1184
            /**
1185
            * <p>
1186
            * Object or array of objects representing the ContainerEffect
1187
            * classes that are active for animating the container.
1188
            * </p>
1189
            * <p>
1190
            * <strong>NOTE:</strong> Although this configuration
1191
            * property is introduced at the Module level, an out of the box
1192
            * implementation is not shipped for the Module class so setting
1193
            * the proroperty on the Module class has no effect. The Overlay
1194
            * class is the first class to provide out of the box ContainerEffect
1195
            * support.
1196
            * </p>
1197
            * @config effect
1198
            * @type Object
1199
            * @default null
1200
            */
1201
            this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
1202
                handler: this.configEffect,
1203
                suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
1204
                supercedes: DEFAULT_CONFIG.EFFECT.supercedes
1205
            });
1206
 
1207
            /**
1208
            * Specifies whether to create a special proxy iframe to monitor
1209
            * for user font resizing in the document
1210
            * @config monitorresize
1211
            * @type Boolean
1212
            * @default true
1213
            */
1214
            this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
1215
                handler: this.configMonitorResize,
1216
                value: DEFAULT_CONFIG.MONITOR_RESIZE.value
1217
            });
1218
 
1219
            /**
1220
            * Specifies if the module should be rendered as the first child
1221
            * of document.body or appended as the last child when render is called
1222
            * with document.body as the "appendToNode".
1223
            * <p>
1224
            * Appending to the body while the DOM is still being constructed can
1225
            * lead to Operation Aborted errors in IE hence this flag is set to
1226
            * false by default.
1227
            * </p>
1228
            *
1229
            * @config appendtodocumentbody
1230
            * @type Boolean
1231
            * @default false
1232
            */
1233
            this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
1234
                value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
1235
            });
1236
        },
1237
 
1238
        /**
1239
        * The Module class's initialization method, which is executed for
1240
        * Module and all of its subclasses. This method is automatically
1241
        * called by the constructor, and  sets up all DOM references for
1242
        * pre-existing markup, and creates required markup if it is not
1243
        * already present.
1244
        * <p>
1245
        * If the element passed in does not have an id, one will be generated
1246
        * for it.
1247
        * </p>
1248
        * @method init
1249
        * @param {String} el The element ID representing the Module <em>OR</em>
1250
        * @param {HTMLElement} el The element representing the Module
1251
        * @param {Object} userConfig The configuration Object literal
1252
        * containing the configuration that should be set for this module.
1253
        * See configuration documentation for more details.
1254
        */
1255
        init: function (el, userConfig) {
1256
 
1257
            var elId, child;
1258
 
1259
            this.initEvents();
1260
            this.beforeInitEvent.fire(Module);
1261
 
1262
            /**
1263
            * The Module's Config object used for monitoring
1264
            * configuration properties.
1265
            * @property cfg
1266
            * @type YAHOO.util.Config
1267
            */
1268
            this.cfg = new Config(this);
1269
 
1270
            if (this.isSecure) {
1271
                this.imageRoot = Module.IMG_ROOT_SSL;
1272
            }
1273
 
1274
            if (typeof el == "string") {
1275
                elId = el;
1276
                el = document.getElementById(el);
1277
                if (! el) {
1278
                    el = (createModuleTemplate()).cloneNode(false);
1279
                    el.id = elId;
1280
                }
1281
            }
1282
 
1283
            this.id = Dom.generateId(el);
1284
            this.element = el;
1285
 
1286
            child = this.element.firstChild;
1287
 
1288
            if (child) {
1289
                var fndHd = false, fndBd = false, fndFt = false;
1290
                do {
1291
                    // We're looking for elements
1292
                    if (1 == child.nodeType) {
1293
                        if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
1294
                            this.header = child;
1295
                            fndHd = true;
1296
                        } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
1297
                            this.body = child;
1298
                            fndBd = true;
1299
                        } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
1300
                            this.footer = child;
1301
                            fndFt = true;
1302
                        }
1303
                    }
1304
                } while ((child = child.nextSibling));
1305
            }
1306
 
1307
            this.initDefaultConfig();
1308
 
1309
            Dom.addClass(this.element, Module.CSS_MODULE);
1310
 
1311
            if (userConfig) {
1312
                this.cfg.applyConfig(userConfig, true);
1313
            }
1314
 
1315
            /*
1316
                Subscribe to the fireQueue() method of Config so that any
1317
                queued configuration changes are excecuted upon render of
1318
                the Module
1319
            */
1320
 
1321
            if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
1322
                this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
1323
            }
1324
 
1325
            this.initEvent.fire(Module);
1326
        },
1327
 
1328
        /**
1329
        * Initialize an empty IFRAME that is placed out of the visible area
1330
        * that can be used to detect text resize.
1331
        * @method initResizeMonitor
1332
        */
1333
        initResizeMonitor: function () {
1334
 
1335
            var isGeckoWin = (UA.gecko && this.platform == "windows");
1336
            if (isGeckoWin) {
1337
                // Help prevent spinning loading icon which
1338
                // started with FireFox 2.0.0.8/Win
1339
                var self = this;
1340
                setTimeout(function(){self._initResizeMonitor();}, 0);
1341
            } else {
1342
                this._initResizeMonitor();
1343
            }
1344
        },
1345
 
1346
        /**
1347
         * Create and initialize the text resize monitoring iframe.
1348
         *
1349
         * @protected
1350
         * @method _initResizeMonitor
1351
         */
1352
        _initResizeMonitor : function() {
1353
 
1354
            var oDoc,
1355
                oIFrame,
1356
                sHTML;
1357
 
1358
            function fireTextResize() {
1359
                Module.textResizeEvent.fire();
1360
            }
1361
 
1362
            if (!UA.opera) {
1363
                oIFrame = Dom.get("_yuiResizeMonitor");
1364
 
1365
                var supportsCWResize = this._supportsCWResize();
1366
 
1367
                if (!oIFrame) {
1368
                    oIFrame = document.createElement("iframe");
1369
 
1370
                    if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
1371
                        oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
1372
                    }
1373
 
1374
                    if (!supportsCWResize) {
1375
                        // Can't monitor on contentWindow, so fire from inside iframe
1376
                        sHTML = ["<html><head><script ",
1377
                                 "type=\"text/javascript\">",
1378
                                 "window.onresize=function(){window.parent.",
1379
                                 "YAHOO.widget.Module.textResizeEvent.",
1380
                                 "fire();};<",
1381
                                 "\/script></head>",
1382
                                 "<body></body></html>"].join('');
1383
 
1384
                        oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
1385
                    }
1386
 
1387
                    oIFrame.id = "_yuiResizeMonitor";
1388
                    oIFrame.title = "Text Resize Monitor";
1389
                    oIFrame.tabIndex = -1;
1390
                    oIFrame.setAttribute("role", "presentation");
1391
 
1392
                    /*
1393
                        Need to set "position" property before inserting the
1394
                        iframe into the document or Safari's status bar will
1395
                        forever indicate the iframe is loading
1396
                        (See YUILibrary bug #1723064)
1397
                    */
1398
                    oIFrame.style.position = "absolute";
1399
                    oIFrame.style.visibility = "hidden";
1400
 
1401
                    var db = document.body,
1402
                        fc = db.firstChild;
1403
                    if (fc) {
1404
                        db.insertBefore(oIFrame, fc);
1405
                    } else {
1406
                        db.appendChild(oIFrame);
1407
                    }
1408
 
1409
                    // Setting the background color fixes an issue with IE6/IE7, where
1410
                    // elements in the DOM, with -ve margin-top which positioned them
1411
                    // offscreen (so they would be overlapped by the iframe and its -ve top
1412
                    // setting), would have their -ve margin-top ignored, when the iframe
1413
                    // was added.
1414
                    oIFrame.style.backgroundColor = "transparent";
1415
 
1416
                    oIFrame.style.borderWidth = "0";
1417
                    oIFrame.style.width = "2em";
1418
                    oIFrame.style.height = "2em";
1419
                    oIFrame.style.left = "0";
1420
                    oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
1421
                    oIFrame.style.visibility = "visible";
1422
 
1423
                    /*
1424
                       Don't open/close the document for Gecko like we used to, since it
1425
                       leads to duplicate cookies. (See YUILibrary bug #1721755)
1426
                    */
1427
                    if (UA.webkit) {
1428
                        oDoc = oIFrame.contentWindow.document;
1429
                        oDoc.open();
1430
                        oDoc.close();
1431
                    }
1432
                }
1433
 
1434
                if (oIFrame && oIFrame.contentWindow) {
1435
                    Module.textResizeEvent.subscribe(this.onDomResize, this, true);
1436
 
1437
                    if (!Module.textResizeInitialized) {
1438
                        if (supportsCWResize) {
1439
                            if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
1440
                                /*
1441
                                     This will fail in IE if document.domain has
1442
                                     changed, so we must change the listener to
1443
                                     use the oIFrame element instead
1444
                                */
1445
                                Event.on(oIFrame, "resize", fireTextResize);
1446
                            }
1447
                        }
1448
                        Module.textResizeInitialized = true;
1449
                    }
1450
                    this.resizeMonitor = oIFrame;
1451
                }
1452
            }
1453
        },
1454
 
1455
        /**
1456
         * Text resize monitor helper method.
1457
         * Determines if the browser supports resize events on iframe content windows.
1458
         *
1459
         * @private
1460
         * @method _supportsCWResize
1461
         */
1462
        _supportsCWResize : function() {
1463
            /*
1464
                Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
1465
                Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
1466
 
1467
                We don't want to start sniffing for patch versions, so fire textResize the same
1468
                way on all FF2 flavors
1469
             */
1470
            var bSupported = true;
1471
            if (UA.gecko && UA.gecko <= 1.8) {
1472
                bSupported = false;
1473
            }
1474
            return bSupported;
1475
        },
1476
 
1477
        /**
1478
        * Event handler fired when the resize monitor element is resized.
1479
        * @method onDomResize
1480
        * @param {DOMEvent} e The DOM resize event
1481
        * @param {Object} obj The scope object passed to the handler
1482
        */
1483
        onDomResize: function (e, obj) {
1484
 
1485
            var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
1486
 
1487
            this.resizeMonitor.style.top = nTop + "px";
1488
            this.resizeMonitor.style.left = "0";
1489
        },
1490
 
1491
        /**
1492
        * Sets the Module's header content to the markup specified, or appends
1493
        * the passed element to the header.
1494
        *
1495
        * If no header is present, one will
1496
        * be automatically created. An empty string can be passed to the method
1497
        * to clear the contents of the header.
1498
        *
1499
        * @method setHeader
1500
        * @param {HTML} headerContent The markup used to set the header content.
1501
        * As a convenience, non HTMLElement objects can also be passed into
1502
        * the method, and will be treated as strings, with the header innerHTML
1503
        * set to their default toString implementations.
1504
        *
1505
        * <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>
1506
        *
1507
        * <em>OR</em>
1508
        * @param {HTMLElement} headerContent The HTMLElement to append to
1509
        * <em>OR</em>
1510
        * @param {DocumentFragment} headerContent The document fragment
1511
        * containing elements which are to be added to the header
1512
        */
1513
        setHeader: function (headerContent) {
1514
            var oHeader = this.header || (this.header = createHeader());
1515
 
1516
            if (headerContent.nodeName) {
1517
                oHeader.innerHTML = "";
1518
                oHeader.appendChild(headerContent);
1519
            } else {
1520
                oHeader.innerHTML = headerContent;
1521
            }
1522
 
1523
            if (this._rendered) {
1524
                this._renderHeader();
1525
            }
1526
 
1527
            this.changeHeaderEvent.fire(headerContent);
1528
            this.changeContentEvent.fire();
1529
 
1530
        },
1531
 
1532
        /**
1533
        * Appends the passed element to the header. If no header is present,
1534
        * one will be automatically created.
1535
        * @method appendToHeader
1536
        * @param {HTMLElement | DocumentFragment} element The element to
1537
        * append to the header. In the case of a document fragment, the
1538
        * children of the fragment will be appended to the header.
1539
        */
1540
        appendToHeader: function (element) {
1541
            var oHeader = this.header || (this.header = createHeader());
1542
 
1543
            oHeader.appendChild(element);
1544
 
1545
            this.changeHeaderEvent.fire(element);
1546
            this.changeContentEvent.fire();
1547
 
1548
        },
1549
 
1550
        /**
1551
        * Sets the Module's body content to the HTML specified.
1552
        *
1553
        * If no body is present, one will be automatically created.
1554
        *
1555
        * An empty string can be passed to the method to clear the contents of the body.
1556
        * @method setBody
1557
        * @param {HTML} bodyContent The HTML used to set the body content
1558
        * As a convenience, non HTMLElement objects can also be passed into
1559
        * the method, and will be treated as strings, with the body innerHTML
1560
        * set to their default toString implementations.
1561
        *
1562
        * <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>
1563
        *
1564
        * <em>OR</em>
1565
        * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
1566
        * child of the body element.
1567
        * <em>OR</em>
1568
        * @param {DocumentFragment} bodyContent The document fragment
1569
        * containing elements which are to be added to the body
1570
        */
1571
        setBody: function (bodyContent) {
1572
            var oBody = this.body || (this.body = createBody());
1573
 
1574
            if (bodyContent.nodeName) {
1575
                oBody.innerHTML = "";
1576
                oBody.appendChild(bodyContent);
1577
            } else {
1578
                oBody.innerHTML = bodyContent;
1579
            }
1580
 
1581
            if (this._rendered) {
1582
                this._renderBody();
1583
            }
1584
 
1585
            this.changeBodyEvent.fire(bodyContent);
1586
            this.changeContentEvent.fire();
1587
        },
1588
 
1589
        /**
1590
        * Appends the passed element to the body. If no body is present, one
1591
        * will be automatically created.
1592
        * @method appendToBody
1593
        * @param {HTMLElement | DocumentFragment} element The element to
1594
        * append to the body. In the case of a document fragment, the
1595
        * children of the fragment will be appended to the body.
1596
        *
1597
        */
1598
        appendToBody: function (element) {
1599
            var oBody = this.body || (this.body = createBody());
1600
 
1601
            oBody.appendChild(element);
1602
 
1603
            this.changeBodyEvent.fire(element);
1604
            this.changeContentEvent.fire();
1605
 
1606
        },
1607
 
1608
        /**
1609
        * Sets the Module's footer content to the HTML specified, or appends
1610
        * the passed element to the footer. If no footer is present, one will
1611
        * be automatically created. An empty string can be passed to the method
1612
        * to clear the contents of the footer.
1613
        * @method setFooter
1614
        * @param {HTML} footerContent The HTML used to set the footer
1615
        * As a convenience, non HTMLElement objects can also be passed into
1616
        * the method, and will be treated as strings, with the footer innerHTML
1617
        * set to their default toString implementations.
1618
        *
1619
        * <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>
1620
        *
1621
        * <em>OR</em>
1622
        * @param {HTMLElement} footerContent The HTMLElement to append to
1623
        * the footer
1624
        * <em>OR</em>
1625
        * @param {DocumentFragment} footerContent The document fragment containing
1626
        * elements which are to be added to the footer
1627
        */
1628
        setFooter: function (footerContent) {
1629
 
1630
            var oFooter = this.footer || (this.footer = createFooter());
1631
 
1632
            if (footerContent.nodeName) {
1633
                oFooter.innerHTML = "";
1634
                oFooter.appendChild(footerContent);
1635
            } else {
1636
                oFooter.innerHTML = footerContent;
1637
            }
1638
 
1639
            if (this._rendered) {
1640
                this._renderFooter();
1641
            }
1642
 
1643
            this.changeFooterEvent.fire(footerContent);
1644
            this.changeContentEvent.fire();
1645
        },
1646
 
1647
        /**
1648
        * Appends the passed element to the footer. If no footer is present,
1649
        * one will be automatically created.
1650
        * @method appendToFooter
1651
        * @param {HTMLElement | DocumentFragment} element The element to
1652
        * append to the footer. In the case of a document fragment, the
1653
        * children of the fragment will be appended to the footer
1654
        */
1655
        appendToFooter: function (element) {
1656
 
1657
            var oFooter = this.footer || (this.footer = createFooter());
1658
 
1659
            oFooter.appendChild(element);
1660
 
1661
            this.changeFooterEvent.fire(element);
1662
            this.changeContentEvent.fire();
1663
 
1664
        },
1665
 
1666
        /**
1667
        * Renders the Module by inserting the elements that are not already
1668
        * in the main Module into their correct places. Optionally appends
1669
        * the Module to the specified node prior to the render's execution.
1670
        * <p>
1671
        * For Modules without existing markup, the appendToNode argument
1672
        * is REQUIRED. If this argument is ommitted and the current element is
1673
        * not present in the document, the function will return false,
1674
        * indicating that the render was a failure.
1675
        * </p>
1676
        * <p>
1677
        * NOTE: As of 2.3.1, if the appendToNode is the document's body element
1678
        * then the module is rendered as the first child of the body element,
1679
        * and not appended to it, to avoid Operation Aborted errors in IE when
1680
        * rendering the module before window's load event is fired. You can
1681
        * use the appendtodocumentbody configuration property to change this
1682
        * to append to document.body if required.
1683
        * </p>
1684
        * @method render
1685
        * @param {String} appendToNode The element id to which the Module
1686
        * should be appended to prior to rendering <em>OR</em>
1687
        * @param {HTMLElement} appendToNode The element to which the Module
1688
        * should be appended to prior to rendering
1689
        * @param {HTMLElement} moduleElement OPTIONAL. The element that
1690
        * represents the actual Standard Module container.
1691
        * @return {Boolean} Success or failure of the render
1692
        */
1693
        render: function (appendToNode, moduleElement) {
1694
 
1695
            var me = this;
1696
 
1697
            function appendTo(parentNode) {
1698
                if (typeof parentNode == "string") {
1699
                    parentNode = document.getElementById(parentNode);
1700
                }
1701
 
1702
                if (parentNode) {
1703
                    me._addToParent(parentNode, me.element);
1704
                    me.appendEvent.fire();
1705
                }
1706
            }
1707
 
1708
            this.beforeRenderEvent.fire();
1709
 
1710
            if (! moduleElement) {
1711
                moduleElement = this.element;
1712
            }
1713
 
1714
            if (appendToNode) {
1715
                appendTo(appendToNode);
1716
            } else {
1717
                // No node was passed in. If the element is not already in the Dom, this fails
1718
                if (! Dom.inDocument(this.element)) {
1719
                    return false;
1720
                }
1721
            }
1722
 
1723
            this._renderHeader(moduleElement);
1724
            this._renderBody(moduleElement);
1725
            this._renderFooter(moduleElement);
1726
 
1727
            this._rendered = true;
1728
 
1729
            this.renderEvent.fire();
1730
            return true;
1731
        },
1732
 
1733
        /**
1734
         * Renders the currently set header into it's proper position under the
1735
         * module element. If the module element is not provided, "this.element"
1736
         * is used.
1737
         *
1738
         * @method _renderHeader
1739
         * @protected
1740
         * @param {HTMLElement} moduleElement Optional. A reference to the module element
1741
         */
1742
        _renderHeader: function(moduleElement){
1743
            moduleElement = moduleElement || this.element;
1744
 
1745
            // Need to get everything into the DOM if it isn't already
1746
            if (this.header && !Dom.inDocument(this.header)) {
1747
                // There is a header, but it's not in the DOM yet. Need to add it.
1748
                var firstChild = moduleElement.firstChild;
1749
                if (firstChild) {
1750
                    moduleElement.insertBefore(this.header, firstChild);
1751
                } else {
1752
                    moduleElement.appendChild(this.header);
1753
                }
1754
            }
1755
        },
1756
 
1757
        /**
1758
         * Renders the currently set body into it's proper position under the
1759
         * module element. If the module element is not provided, "this.element"
1760
         * is used.
1761
         *
1762
         * @method _renderBody
1763
         * @protected
1764
         * @param {HTMLElement} moduleElement Optional. A reference to the module element.
1765
         */
1766
        _renderBody: function(moduleElement){
1767
            moduleElement = moduleElement || this.element;
1768
 
1769
            if (this.body && !Dom.inDocument(this.body)) {
1770
                // There is a body, but it's not in the DOM yet. Need to add it.
1771
                if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
1772
                    moduleElement.insertBefore(this.body, this.footer);
1773
                } else {
1774
                    moduleElement.appendChild(this.body);
1775
                }
1776
            }
1777
        },
1778
 
1779
        /**
1780
         * Renders the currently set footer into it's proper position under the
1781
         * module element. If the module element is not provided, "this.element"
1782
         * is used.
1783
         *
1784
         * @method _renderFooter
1785
         * @protected
1786
         * @param {HTMLElement} moduleElement Optional. A reference to the module element
1787
         */
1788
        _renderFooter: function(moduleElement){
1789
            moduleElement = moduleElement || this.element;
1790
 
1791
            if (this.footer && !Dom.inDocument(this.footer)) {
1792
                // There is a footer, but it's not in the DOM yet. Need to add it.
1793
                moduleElement.appendChild(this.footer);
1794
            }
1795
        },
1796
 
1797
        /**
1798
        * Removes the Module element from the DOM, sets all child elements to null, and purges the bounding element of event listeners.
1799
        * @method destroy
1800
        * @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.
1801
        * 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.
1802
        */
1803
        destroy: function (shallowPurge) {
1804
 
1805
            var parent,
1806
                purgeChildren = !(shallowPurge);
1807
 
1808
            if (this.element) {
1809
                Event.purgeElement(this.element, purgeChildren);
1810
                parent = this.element.parentNode;
1811
            }
1812
 
1813
            if (parent) {
1814
                parent.removeChild(this.element);
1815
            }
1816
 
1817
            this.element = null;
1818
            this.header = null;
1819
            this.body = null;
1820
            this.footer = null;
1821
 
1822
            Module.textResizeEvent.unsubscribe(this.onDomResize, this);
1823
 
1824
            this.cfg.destroy();
1825
            this.cfg = null;
1826
 
1827
            this.destroyEvent.fire();
1828
        },
1829
 
1830
        /**
1831
        * Shows the Module element by setting the visible configuration
1832
        * property to true. Also fires two events: beforeShowEvent prior to
1833
        * the visibility change, and showEvent after.
1834
        * @method show
1835
        */
1836
        show: function () {
1837
            this.cfg.setProperty("visible", true);
1838
        },
1839
 
1840
        /**
1841
        * Hides the Module element by setting the visible configuration
1842
        * property to false. Also fires two events: beforeHideEvent prior to
1843
        * the visibility change, and hideEvent after.
1844
        * @method hide
1845
        */
1846
        hide: function () {
1847
            this.cfg.setProperty("visible", false);
1848
        },
1849
 
1850
        // BUILT-IN EVENT HANDLERS FOR MODULE //
1851
        /**
1852
        * Default event handler for changing the visibility property of a
1853
        * Module. By default, this is achieved by switching the "display" style
1854
        * between "block" and "none".
1855
        * This method is responsible for firing showEvent and hideEvent.
1856
        * @param {String} type The CustomEvent type (usually the property name)
1857
        * @param {Object[]} args The CustomEvent arguments. For configuration
1858
        * handlers, args[0] will equal the newly applied value for the property.
1859
        * @param {Object} obj The scope object. For configuration handlers,
1860
        * this will usually equal the owner.
1861
        * @method configVisible
1862
        */
1863
        configVisible: function (type, args, obj) {
1864
            var visible = args[0];
1865
            if (visible) {
1866
                if(this.beforeShowEvent.fire()) {
1867
                    Dom.setStyle(this.element, "display", "block");
1868
                    this.showEvent.fire();
1869
                }
1870
            } else {
1871
                if (this.beforeHideEvent.fire()) {
1872
                    Dom.setStyle(this.element, "display", "none");
1873
                    this.hideEvent.fire();
1874
                }
1875
            }
1876
        },
1877
 
1878
        /**
1879
        * Default event handler for the "effect" configuration property
1880
        * @param {String} type The CustomEvent type (usually the property name)
1881
        * @param {Object[]} args The CustomEvent arguments. For configuration
1882
        * handlers, args[0] will equal the newly applied value for the property.
1883
        * @param {Object} obj The scope object. For configuration handlers,
1884
        * this will usually equal the owner.
1885
        * @method configEffect
1886
        */
1887
        configEffect: function (type, args, obj) {
1888
            this._cachedEffects = (this.cacheEffects) ? this._createEffects(args[0]) : null;
1889
        },
1890
 
1891
        /**
1892
         * If true, ContainerEffects (and Anim instances) are cached when "effect" is set, and reused.
1893
         * If false, new instances are created each time the container is hidden or shown, as was the
1894
         * behavior prior to 2.9.0.
1895
         *
1896
         * @property cacheEffects
1897
         * @since 2.9.0
1898
         * @default true
1899
         * @type boolean
1900
         */
1901
        cacheEffects : true,
1902
 
1903
        /**
1904
         * Creates an array of ContainerEffect instances from the provided configs
1905
         *
1906
         * @method _createEffects
1907
         * @param {Array|Object} effectCfg An effect configuration or array of effect configurations
1908
         * @return {Array} An array of ContainerEffect instances.
1909
         * @protected
1910
         */
1911
        _createEffects: function(effectCfg) {
1912
            var effectInstances = null,
1913
                n,
1914
                i,
1915
                eff;
1916
 
1917
            if (effectCfg) {
1918
                if (effectCfg instanceof Array) {
1919
                    effectInstances = [];
1920
                    n = effectCfg.length;
1921
                    for (i = 0; i < n; i++) {
1922
                        eff = effectCfg[i];
1923
                        if (eff.effect) {
1924
                            effectInstances[effectInstances.length] = eff.effect(this, eff.duration);
1925
                        }
1926
                    }
1927
                } else if (effectCfg.effect) {
1928
                    effectInstances = [effectCfg.effect(this, effectCfg.duration)];
1929
                }
1930
            }
1931
 
1932
            return effectInstances;
1933
        },
1934
 
1935
        /**
1936
        * Default event handler for the "monitorresize" configuration property
1937
        * @param {String} type The CustomEvent type (usually the property name)
1938
        * @param {Object[]} args The CustomEvent arguments. For configuration
1939
        * handlers, args[0] will equal the newly applied value for the property.
1940
        * @param {Object} obj The scope object. For configuration handlers,
1941
        * this will usually equal the owner.
1942
        * @method configMonitorResize
1943
        */
1944
        configMonitorResize: function (type, args, obj) {
1945
            var monitor = args[0];
1946
            if (monitor) {
1947
                this.initResizeMonitor();
1948
            } else {
1949
                Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
1950
                this.resizeMonitor = null;
1951
            }
1952
        },
1953
 
1954
        /**
1955
         * This method is a protected helper, used when constructing the DOM structure for the module
1956
         * to account for situations which may cause Operation Aborted errors in IE. It should not
1957
         * be used for general DOM construction.
1958
         * <p>
1959
         * If the parentNode is not document.body, the element is appended as the last element.
1960
         * </p>
1961
         * <p>
1962
         * If the parentNode is document.body the element is added as the first child to help
1963
         * prevent Operation Aborted errors in IE.
1964
         * </p>
1965
         *
1966
         * @param {parentNode} The HTML element to which the element will be added
1967
         * @param {element} The HTML element to be added to parentNode's children
1968
         * @method _addToParent
1969
         * @protected
1970
         */
1971
        _addToParent: function(parentNode, element) {
1972
            if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
1973
                parentNode.insertBefore(element, parentNode.firstChild);
1974
            } else {
1975
                parentNode.appendChild(element);
1976
            }
1977
        },
1978
 
1979
        /**
1980
        * Returns a String representation of the Object.
1981
        * @method toString
1982
        * @return {String} The string representation of the Module
1983
        */
1984
        toString: function () {
1985
            return "Module " + this.id;
1986
        }
1987
    };
1988
 
1989
    YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
1990
 
1991
}());
1992
(function () {
1993
 
1994
    /**
1995
    * Overlay is a Module that is absolutely positioned above the page flow. It
1996
    * has convenience methods for positioning and sizing, as well as options for
1997
    * controlling zIndex and constraining the Overlay's position to the current
1998
    * visible viewport. Overlay also contains a dynamicly generated IFRAME which
1999
    * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
2000
    * properly rendered above SELECT elements.
2001
    * @namespace YAHOO.widget
2002
    * @class Overlay
2003
    * @extends YAHOO.widget.Module
2004
    * @param {String} el The element ID representing the Overlay <em>OR</em>
2005
    * @param {HTMLElement} el The element representing the Overlay
2006
    * @param {Object} userConfig The configuration object literal containing
2007
    * the configuration that should be set for this Overlay. See configuration
2008
    * documentation for more details.
2009
    * @constructor
2010
    */
2011
    YAHOO.widget.Overlay = function (el, userConfig) {
2012
        YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
2013
    };
2014
 
2015
    var Lang = YAHOO.lang,
2016
        CustomEvent = YAHOO.util.CustomEvent,
2017
        Module = YAHOO.widget.Module,
2018
        Event = YAHOO.util.Event,
2019
        Dom = YAHOO.util.Dom,
2020
        Config = YAHOO.util.Config,
2021
        UA = YAHOO.env.ua,
2022
        Overlay = YAHOO.widget.Overlay,
2023
 
2024
        _SUBSCRIBE = "subscribe",
2025
        _UNSUBSCRIBE = "unsubscribe",
2026
        _CONTAINED = "contained",
2027
 
2028
        m_oIFrameTemplate,
2029
 
2030
        /**
2031
        * Constant representing the name of the Overlay's events
2032
        * @property EVENT_TYPES
2033
        * @private
2034
        * @final
2035
        * @type Object
2036
        */
2037
        EVENT_TYPES = {
2038
            "BEFORE_MOVE": "beforeMove",
2039
            "MOVE": "move"
2040
        },
2041
 
2042
        /**
2043
        * Constant representing the Overlay's configuration properties
2044
        * @property DEFAULT_CONFIG
2045
        * @private
2046
        * @final
2047
        * @type Object
2048
        */
2049
        DEFAULT_CONFIG = {
2050
 
2051
            "X": {
2052
                key: "x",
2053
                validator: Lang.isNumber,
2054
                suppressEvent: true,
2055
                supercedes: ["iframe"]
2056
            },
2057
 
2058
            "Y": {
2059
                key: "y",
2060
                validator: Lang.isNumber,
2061
                suppressEvent: true,
2062
                supercedes: ["iframe"]
2063
            },
2064
 
2065
            "XY": {
2066
                key: "xy",
2067
                suppressEvent: true,
2068
                supercedes: ["iframe"]
2069
            },
2070
 
2071
            "CONTEXT": {
2072
                key: "context",
2073
                suppressEvent: true,
2074
                supercedes: ["iframe"]
2075
            },
2076
 
2077
            "FIXED_CENTER": {
2078
                key: "fixedcenter",
2079
                value: false,
2080
                supercedes: ["iframe", "visible"]
2081
            },
2082
 
2083
            "WIDTH": {
2084
                key: "width",
2085
                suppressEvent: true,
2086
                supercedes: ["context", "fixedcenter", "iframe"]
2087
            },
2088
 
2089
            "HEIGHT": {
2090
                key: "height",
2091
                suppressEvent: true,
2092
                supercedes: ["context", "fixedcenter", "iframe"]
2093
            },
2094
 
2095
            "AUTO_FILL_HEIGHT" : {
2096
                key: "autofillheight",
2097
                supercedes: ["height"],
2098
                value:"body"
2099
            },
2100
 
2101
            "ZINDEX": {
2102
                key: "zindex",
2103
                value: null
2104
            },
2105
 
2106
            "CONSTRAIN_TO_VIEWPORT": {
2107
                key: "constraintoviewport",
2108
                value: false,
2109
                validator: Lang.isBoolean,
2110
                supercedes: ["iframe", "x", "y", "xy"]
2111
            },
2112
 
2113
            "IFRAME": {
2114
                key: "iframe",
2115
                value: (UA.ie == 6 ? true : false),
2116
                validator: Lang.isBoolean,
2117
                supercedes: ["zindex"]
2118
            },
2119
 
2120
            "PREVENT_CONTEXT_OVERLAP": {
2121
                key: "preventcontextoverlap",
2122
                value: false,
2123
                validator: Lang.isBoolean,
2124
                supercedes: ["constraintoviewport"]
2125
            }
2126
 
2127
        };
2128
 
2129
    /**
2130
    * The URL that will be placed in the iframe
2131
    * @property YAHOO.widget.Overlay.IFRAME_SRC
2132
    * @static
2133
    * @final
2134
    * @type String
2135
    */
2136
    Overlay.IFRAME_SRC = "javascript:false;";
2137
 
2138
    /**
2139
    * Number representing how much the iframe shim should be offset from each
2140
    * side of an Overlay instance, in pixels.
2141
    * @property YAHOO.widget.Overlay.IFRAME_SRC
2142
    * @default 3
2143
    * @static
2144
    * @final
2145
    * @type Number
2146
    */
2147
    Overlay.IFRAME_OFFSET = 3;
2148
 
2149
    /**
2150
    * Number representing the minimum distance an Overlay instance should be
2151
    * positioned relative to the boundaries of the browser's viewport, in pixels.
2152
    * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
2153
    * @default 10
2154
    * @static
2155
    * @final
2156
    * @type Number
2157
    */
2158
    Overlay.VIEWPORT_OFFSET = 10;
2159
 
2160
    /**
2161
    * Constant representing the top left corner of an element, used for
2162
    * configuring the context element alignment
2163
    * @property YAHOO.widget.Overlay.TOP_LEFT
2164
    * @static
2165
    * @final
2166
    * @type String
2167
    */
2168
    Overlay.TOP_LEFT = "tl";
2169
 
2170
    /**
2171
    * Constant representing the top right corner of an element, used for
2172
    * configuring the context element alignment
2173
    * @property YAHOO.widget.Overlay.TOP_RIGHT
2174
    * @static
2175
    * @final
2176
    * @type String
2177
    */
2178
    Overlay.TOP_RIGHT = "tr";
2179
 
2180
    /**
2181
    * Constant representing the top bottom left corner of an element, used for
2182
    * configuring the context element alignment
2183
    * @property YAHOO.widget.Overlay.BOTTOM_LEFT
2184
    * @static
2185
    * @final
2186
    * @type String
2187
    */
2188
    Overlay.BOTTOM_LEFT = "bl";
2189
 
2190
    /**
2191
    * Constant representing the bottom right corner of an element, used for
2192
    * configuring the context element alignment
2193
    * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
2194
    * @static
2195
    * @final
2196
    * @type String
2197
    */
2198
    Overlay.BOTTOM_RIGHT = "br";
2199
 
2200
    Overlay.PREVENT_OVERLAP_X = {
2201
        "tltr": true,
2202
        "blbr": true,
2203
        "brbl": true,
2204
        "trtl": true
2205
    };
2206
 
2207
    Overlay.PREVENT_OVERLAP_Y = {
2208
        "trbr": true,
2209
        "tlbl": true,
2210
        "bltl": true,
2211
        "brtr": true
2212
    };
2213
 
2214
    /**
2215
    * Constant representing the default CSS class used for an Overlay
2216
    * @property YAHOO.widget.Overlay.CSS_OVERLAY
2217
    * @static
2218
    * @final
2219
    * @type String
2220
    */
2221
    Overlay.CSS_OVERLAY = "yui-overlay";
2222
 
2223
    /**
2224
    * Constant representing the default hidden CSS class used for an Overlay. This class is
2225
    * applied to the overlay's outer DIV whenever it's hidden.
2226
    *
2227
    * @property YAHOO.widget.Overlay.CSS_HIDDEN
2228
    * @static
2229
    * @final
2230
    * @type String
2231
    */
2232
    Overlay.CSS_HIDDEN = "yui-overlay-hidden";
2233
 
2234
    /**
2235
    * Constant representing the default CSS class used for an Overlay iframe shim.
2236
    *
2237
    * @property YAHOO.widget.Overlay.CSS_IFRAME
2238
    * @static
2239
    * @final
2240
    * @type String
2241
    */
2242
    Overlay.CSS_IFRAME = "yui-overlay-iframe";
2243
 
2244
    /**
2245
     * Constant representing the names of the standard module elements
2246
     * used in the overlay.
2247
     * @property YAHOO.widget.Overlay.STD_MOD_RE
2248
     * @static
2249
     * @final
2250
     * @type RegExp
2251
     */
2252
    Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
2253
 
2254
    /**
2255
    * A singleton CustomEvent used for reacting to the DOM event for
2256
    * window scroll
2257
    * @event YAHOO.widget.Overlay.windowScrollEvent
2258
    */
2259
    Overlay.windowScrollEvent = new CustomEvent("windowScroll");
2260
 
2261
    /**
2262
    * A singleton CustomEvent used for reacting to the DOM event for
2263
    * window resize
2264
    * @event YAHOO.widget.Overlay.windowResizeEvent
2265
    */
2266
    Overlay.windowResizeEvent = new CustomEvent("windowResize");
2267
 
2268
    /**
2269
    * The DOM event handler used to fire the CustomEvent for window scroll
2270
    * @method YAHOO.widget.Overlay.windowScrollHandler
2271
    * @static
2272
    * @param {DOMEvent} e The DOM scroll event
2273
    */
2274
    Overlay.windowScrollHandler = function (e) {
2275
        var t = Event.getTarget(e);
2276
 
2277
        // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
2278
        // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
2279
        // - IE doesn't recognize scroll registered on the document.
2280
        //
2281
        // Also, when document view is scrolled, IE doesn't provide a target,
2282
        // rest of the browsers set target to window.document, apart from opera
2283
        // which sets target to window.
2284
        if (!t || t === window || t === window.document) {
2285
            if (UA.ie) {
2286
 
2287
                if (! window.scrollEnd) {
2288
                    window.scrollEnd = -1;
2289
                }
2290
 
2291
                clearTimeout(window.scrollEnd);
2292
 
2293
                window.scrollEnd = setTimeout(function () {
2294
                    Overlay.windowScrollEvent.fire();
2295
                }, 1);
2296
 
2297
            } else {
2298
                Overlay.windowScrollEvent.fire();
2299
            }
2300
        }
2301
    };
2302
 
2303
    /**
2304
    * The DOM event handler used to fire the CustomEvent for window resize
2305
    * @method YAHOO.widget.Overlay.windowResizeHandler
2306
    * @static
2307
    * @param {DOMEvent} e The DOM resize event
2308
    */
2309
    Overlay.windowResizeHandler = function (e) {
2310
 
2311
        if (UA.ie) {
2312
            if (! window.resizeEnd) {
2313
                window.resizeEnd = -1;
2314
            }
2315
 
2316
            clearTimeout(window.resizeEnd);
2317
 
2318
            window.resizeEnd = setTimeout(function () {
2319
                Overlay.windowResizeEvent.fire();
2320
            }, 100);
2321
        } else {
2322
            Overlay.windowResizeEvent.fire();
2323
        }
2324
    };
2325
 
2326
    /**
2327
    * A boolean that indicated whether the window resize and scroll events have
2328
    * already been subscribed to.
2329
    * @property YAHOO.widget.Overlay._initialized
2330
    * @private
2331
    * @type Boolean
2332
    */
2333
    Overlay._initialized = null;
2334
 
2335
    if (Overlay._initialized === null) {
2336
        Event.on(window, "scroll", Overlay.windowScrollHandler);
2337
        Event.on(window, "resize", Overlay.windowResizeHandler);
2338
        Overlay._initialized = true;
2339
    }
2340
 
2341
    /**
2342
     * Internal map of special event types, which are provided
2343
     * by the instance. It maps the event type to the custom event
2344
     * instance. Contains entries for the "windowScroll", "windowResize" and
2345
     * "textResize" static container events.
2346
     *
2347
     * @property YAHOO.widget.Overlay._TRIGGER_MAP
2348
     * @type Object
2349
     * @static
2350
     * @private
2351
     */
2352
    Overlay._TRIGGER_MAP = {
2353
        "windowScroll" : Overlay.windowScrollEvent,
2354
        "windowResize" : Overlay.windowResizeEvent,
2355
        "textResize"   : Module.textResizeEvent
2356
    };
2357
 
2358
    YAHOO.extend(Overlay, Module, {
2359
 
2360
        /**
2361
         * <p>
2362
         * Array of default event types which will trigger
2363
         * context alignment for the Overlay class.
2364
         * </p>
2365
         * <p>The array is empty by default for Overlay,
2366
         * but maybe populated in future releases, so classes extending
2367
         * Overlay which need to define their own set of CONTEXT_TRIGGERS
2368
         * should concatenate their super class's prototype.CONTEXT_TRIGGERS
2369
         * value with their own array of values.
2370
         * </p>
2371
         * <p>
2372
         * E.g.:
2373
         * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
2374
         * </p>
2375
         *
2376
         * @property CONTEXT_TRIGGERS
2377
         * @type Array
2378
         * @final
2379
         */
2380
        CONTEXT_TRIGGERS : [],
2381
 
2382
        /**
2383
        * The Overlay initialization method, which is executed for Overlay and
2384
        * all of its subclasses. This method is automatically called by the
2385
        * constructor, and  sets up all DOM references for pre-existing markup,
2386
        * and creates required markup if it is not already present.
2387
        * @method init
2388
        * @param {String} el The element ID representing the Overlay <em>OR</em>
2389
        * @param {HTMLElement} el The element representing the Overlay
2390
        * @param {Object} userConfig The configuration object literal
2391
        * containing the configuration that should be set for this Overlay.
2392
        * See configuration documentation for more details.
2393
        */
2394
        init: function (el, userConfig) {
2395
 
2396
            /*
2397
                 Note that we don't pass the user config in here yet because we
2398
                 only want it executed once, at the lowest subclass level
2399
            */
2400
 
2401
            Overlay.superclass.init.call(this, el/*, userConfig*/);
2402
 
2403
            this.beforeInitEvent.fire(Overlay);
2404
 
2405
            Dom.addClass(this.element, Overlay.CSS_OVERLAY);
2406
 
2407
            if (userConfig) {
2408
                this.cfg.applyConfig(userConfig, true);
2409
            }
2410
 
2411
            if (this.platform == "mac" && UA.gecko) {
2412
 
2413
                if (! Config.alreadySubscribed(this.showEvent,
2414
                    this.showMacGeckoScrollbars, this)) {
2415
 
2416
                    this.showEvent.subscribe(this.showMacGeckoScrollbars,
2417
                        this, true);
2418
 
2419
                }
2420
 
2421
                if (! Config.alreadySubscribed(this.hideEvent,
2422
                    this.hideMacGeckoScrollbars, this)) {
2423
 
2424
                    this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
2425
                        this, true);
2426
 
2427
                }
2428
            }
2429
 
2430
            this.initEvent.fire(Overlay);
2431
        },
2432
 
2433
        /**
2434
        * Initializes the custom events for Overlay which are fired
2435
        * automatically at appropriate times by the Overlay class.
2436
        * @method initEvents
2437
        */
2438
        initEvents: function () {
2439
 
2440
            Overlay.superclass.initEvents.call(this);
2441
 
2442
            var SIGNATURE = CustomEvent.LIST;
2443
 
2444
            /**
2445
            * CustomEvent fired before the Overlay is moved.
2446
            * @event beforeMoveEvent
2447
            * @param {Number} x x coordinate
2448
            * @param {Number} y y coordinate
2449
            */
2450
            this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
2451
            this.beforeMoveEvent.signature = SIGNATURE;
2452
 
2453
            /**
2454
            * CustomEvent fired after the Overlay is moved.
2455
            * @event moveEvent
2456
            * @param {Number} x x coordinate
2457
            * @param {Number} y y coordinate
2458
            */
2459
            this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
2460
            this.moveEvent.signature = SIGNATURE;
2461
 
2462
        },
2463
 
2464
        /**
2465
        * Initializes the class's configurable properties which can be changed
2466
        * using the Overlay's Config object (cfg).
2467
        * @method initDefaultConfig
2468
        */
2469
        initDefaultConfig: function () {
2470
 
2471
            Overlay.superclass.initDefaultConfig.call(this);
2472
 
2473
            var cfg = this.cfg;
2474
 
2475
            // Add overlay config properties //
2476
 
2477
            /**
2478
            * The absolute x-coordinate position of the Overlay
2479
            * @config x
2480
            * @type Number
2481
            * @default null
2482
            */
2483
            cfg.addProperty(DEFAULT_CONFIG.X.key, {
2484
 
2485
                handler: this.configX,
2486
                validator: DEFAULT_CONFIG.X.validator,
2487
                suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
2488
                supercedes: DEFAULT_CONFIG.X.supercedes
2489
 
2490
            });
2491
 
2492
            /**
2493
            * The absolute y-coordinate position of the Overlay
2494
            * @config y
2495
            * @type Number
2496
            * @default null
2497
            */
2498
            cfg.addProperty(DEFAULT_CONFIG.Y.key, {
2499
 
2500
                handler: this.configY,
2501
                validator: DEFAULT_CONFIG.Y.validator,
2502
                suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
2503
                supercedes: DEFAULT_CONFIG.Y.supercedes
2504
 
2505
            });
2506
 
2507
            /**
2508
            * An array with the absolute x and y positions of the Overlay
2509
            * @config xy
2510
            * @type Number[]
2511
            * @default null
2512
            */
2513
            cfg.addProperty(DEFAULT_CONFIG.XY.key, {
2514
                handler: this.configXY,
2515
                suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
2516
                supercedes: DEFAULT_CONFIG.XY.supercedes
2517
            });
2518
 
2519
            /**
2520
            * <p>
2521
            * The array of context arguments for context-sensitive positioning.
2522
            * </p>
2523
            *
2524
            * <p>
2525
            * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
2526
            * the 5 array elements described in detail below:
2527
            * </p>
2528
            *
2529
            * <dl>
2530
            * <dt>contextElementOrId &#60;String|HTMLElement&#62;</dt>
2531
            * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
2532
            * <dt>overlayCorner &#60;String&#62;</dt>
2533
            * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
2534
            * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
2535
            * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
2536
            * <dt>contextCorner &#60;String&#62;</dt>
2537
            * <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>
2538
            * <dt>arrayOfTriggerEvents (optional) &#60;Array[String|CustomEvent]&#62;</dt>
2539
            * <dd>
2540
            * <p>
2541
            * 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>
2542
            * 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.
2543
            * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
2544
            * </p>
2545
            * <p>
2546
            * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
2547
            * 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).
2548
            * </p>
2549
            * </dd>
2550
            * <dt>xyOffset &#60;Number[]&#62;</dt>
2551
            * <dd>
2552
            * 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.
2553
            * 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.
2554
            * </dd>
2555
            * </dl>
2556
            *
2557
            * <p>
2558
            * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
2559
            * align the Overlay's top left corner to the bottom left corner of the
2560
            * context element with id "img1".
2561
            * </p>
2562
            * <p>
2563
            * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
2564
            * align the Overlay's top left corner to the bottom left corner of the
2565
            * 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).
2566
            * </p>
2567
            * <p>
2568
            * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
2569
            * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
2570
            * </p>
2571
            *
2572
            * @config context
2573
            * @type Array
2574
            * @default null
2575
            */
2576
            cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
2577
                handler: this.configContext,
2578
                suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
2579
                supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
2580
            });
2581
 
2582
            /**
2583
            * Determines whether or not the Overlay should be anchored
2584
            * to the center of the viewport.
2585
            *
2586
            * <p>This property can be set to:</p>
2587
            *
2588
            * <dl>
2589
            * <dt>true</dt>
2590
            * <dd>
2591
            * To enable fixed center positioning
2592
            * <p>
2593
            * When enabled, the overlay will
2594
            * be positioned in the center of viewport when initially displayed, and
2595
            * will remain in the center of the viewport whenever the window is
2596
            * scrolled or resized.
2597
            * </p>
2598
            * <p>
2599
            * If the overlay is too big for the viewport,
2600
            * it's top left corner will be aligned with the top left corner of the viewport.
2601
            * </p>
2602
            * </dd>
2603
            * <dt>false</dt>
2604
            * <dd>
2605
            * To disable fixed center positioning.
2606
            * <p>In this case the overlay can still be
2607
            * centered as a one-off operation, by invoking the <code>center()</code> method,
2608
            * however it will not remain centered when the window is scrolled/resized.
2609
            * </dd>
2610
            * <dt>"contained"<dt>
2611
            * <dd>To enable fixed center positioning, as with the <code>true</code> option.
2612
            * <p>However, unlike setting the property to <code>true</code>,
2613
            * when the property is set to <code>"contained"</code>, if the overlay is
2614
            * too big for the viewport, it will not get automatically centered when the
2615
            * user scrolls or resizes the window (until the window is large enough to contain the
2616
            * overlay). This is useful in cases where the Overlay has both header and footer
2617
            * UI controls which the user may need to access.
2618
            * </p>
2619
            * </dd>
2620
            * </dl>
2621
            *
2622
            * @config fixedcenter
2623
            * @type Boolean | String
2624
            * @default false
2625
            */
2626
            cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
2627
                handler: this.configFixedCenter,
2628
                value: DEFAULT_CONFIG.FIXED_CENTER.value,
2629
                validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
2630
                supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
2631
            });
2632
 
2633
            /**
2634
            * CSS width of the Overlay.
2635
            * @config width
2636
            * @type String
2637
            * @default null
2638
            */
2639
            cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
2640
                handler: this.configWidth,
2641
                suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
2642
                supercedes: DEFAULT_CONFIG.WIDTH.supercedes
2643
            });
2644
 
2645
            /**
2646
            * CSS height of the Overlay.
2647
            * @config height
2648
            * @type String
2649
            * @default null
2650
            */
2651
            cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
2652
                handler: this.configHeight,
2653
                suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
2654
                supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
2655
            });
2656
 
2657
            /**
2658
            * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
2659
            * Supported values are "header", "body", "footer".
2660
            *
2661
            * @config autofillheight
2662
            * @type String
2663
            * @default null
2664
            */
2665
            cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
2666
                handler: this.configAutoFillHeight,
2667
                value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
2668
                validator : this._validateAutoFill,
2669
                supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
2670
            });
2671
 
2672
            /**
2673
            * CSS z-index of the Overlay.
2674
            * @config zIndex
2675
            * @type Number
2676
            * @default null
2677
            */
2678
            cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
2679
                handler: this.configzIndex,
2680
                value: DEFAULT_CONFIG.ZINDEX.value
2681
            });
2682
 
2683
            /**
2684
            * True if the Overlay should be prevented from being positioned
2685
            * out of the viewport.
2686
            * @config constraintoviewport
2687
            * @type Boolean
2688
            * @default false
2689
            */
2690
            cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
2691
 
2692
                handler: this.configConstrainToViewport,
2693
                value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
2694
                validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
2695
                supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
2696
 
2697
            });
2698
 
2699
            /**
2700
            * @config iframe
2701
            * @description Boolean indicating whether or not the Overlay should
2702
            * have an IFRAME shim; used to prevent SELECT elements from
2703
            * poking through an Overlay instance in IE6.  When set to "true",
2704
            * the iframe shim is created when the Overlay instance is intially
2705
            * made visible.
2706
            * @type Boolean
2707
            * @default true for IE6 and below, false for all other browsers.
2708
            */
2709
            cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
2710
 
2711
                handler: this.configIframe,
2712
                value: DEFAULT_CONFIG.IFRAME.value,
2713
                validator: DEFAULT_CONFIG.IFRAME.validator,
2714
                supercedes: DEFAULT_CONFIG.IFRAME.supercedes
2715
 
2716
            });
2717
 
2718
            /**
2719
            * @config preventcontextoverlap
2720
            * @description Boolean indicating whether or not the Overlay should overlap its
2721
            * context element (defined using the "context" configuration property) when the
2722
            * "constraintoviewport" configuration property is set to "true".
2723
            * @type Boolean
2724
            * @default false
2725
            */
2726
            cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
2727
                value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
2728
                validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
2729
                supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
2730
            });
2731
        },
2732
 
2733
        /**
2734
        * Moves the Overlay to the specified position. This function is
2735
        * identical to calling this.cfg.setProperty("xy", [x,y]);
2736
        * @method moveTo
2737
        * @param {Number} x The Overlay's new x position
2738
        * @param {Number} y The Overlay's new y position
2739
        */
2740
        moveTo: function (x, y) {
2741
            this.cfg.setProperty("xy", [x, y]);
2742
        },
2743
 
2744
        /**
2745
        * Adds a CSS class ("hide-scrollbars") and removes a CSS class
2746
        * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2747
        * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2748
        * @method hideMacGeckoScrollbars
2749
        */
2750
        hideMacGeckoScrollbars: function () {
2751
            Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
2752
        },
2753
 
2754
        /**
2755
        * Adds a CSS class ("show-scrollbars") and removes a CSS class
2756
        * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
2757
        * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
2758
        * @method showMacGeckoScrollbars
2759
        */
2760
        showMacGeckoScrollbars: function () {
2761
            Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
2762
        },
2763
 
2764
        /**
2765
         * Internal implementation to set the visibility of the overlay in the DOM.
2766
         *
2767
         * @method _setDomVisibility
2768
         * @param {boolean} visible Whether to show or hide the Overlay's outer element
2769
         * @protected
2770
         */
2771
        _setDomVisibility : function(show) {
2772
            Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
2773
            var hiddenClass = Overlay.CSS_HIDDEN;
2774
 
2775
            if (show) {
2776
                Dom.removeClass(this.element, hiddenClass);
2777
            } else {
2778
                Dom.addClass(this.element, hiddenClass);
2779
            }
2780
        },
2781
 
2782
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
2783
        /**
2784
        * The default event handler fired when the "visible" property is
2785
        * changed.  This method is responsible for firing showEvent
2786
        * and hideEvent.
2787
        * @method configVisible
2788
        * @param {String} type The CustomEvent type (usually the property name)
2789
        * @param {Object[]} args The CustomEvent arguments. For configuration
2790
        * handlers, args[0] will equal the newly applied value for the property.
2791
        * @param {Object} obj The scope object. For configuration handlers,
2792
        * this will usually equal the owner.
2793
        */
2794
        configVisible: function (type, args, obj) {
2795
 
2796
            var visible = args[0],
2797
                currentVis = Dom.getStyle(this.element, "visibility"),
2798
                effects = this._cachedEffects || this._createEffects(this.cfg.getProperty("effect")),
2799
                isMacGecko = (this.platform == "mac" && UA.gecko),
2800
                alreadySubscribed = Config.alreadySubscribed,
2801
                ei, e, j, k, h,
2802
                nEffectInstances;
2803
 
2804
            if (currentVis == "inherit") {
2805
                e = this.element.parentNode;
2806
 
2807
                while (e.nodeType != 9 && e.nodeType != 11) {
2808
                    currentVis = Dom.getStyle(e, "visibility");
2809
 
2810
                    if (currentVis != "inherit") {
2811
                        break;
2812
                    }
2813
 
2814
                    e = e.parentNode;
2815
                }
2816
 
2817
                if (currentVis == "inherit") {
2818
                    currentVis = "visible";
2819
                }
2820
            }
2821
 
2822
            if (visible) { // Show
2823
 
2824
                if (isMacGecko) {
2825
                    this.showMacGeckoScrollbars();
2826
                }
2827
 
2828
                if (effects) { // Animate in
2829
                    if (visible) { // Animate in if not showing
2830
 
2831
                         // Fading out is a bit of a hack, but didn't want to risk doing
2832
                         // something broader (e.g a generic this._animatingOut) for 2.9.0
2833
 
2834
                        if (currentVis != "visible" || currentVis === "" || this._fadingOut) {
2835
                            if (this.beforeShowEvent.fire()) {
2836
 
2837
                                nEffectInstances = effects.length;
2838
 
2839
                                for (j = 0; j < nEffectInstances; j++) {
2840
                                    ei = effects[j];
2841
                                    if (j === 0 && !alreadySubscribed(ei.animateInCompleteEvent, this.showEvent.fire, this.showEvent)) {
2842
                                        ei.animateInCompleteEvent.subscribe(this.showEvent.fire, this.showEvent, true);
2843
                                    }
2844
                                    ei.animateIn();
2845
                                }
2846
                            }
2847
                        }
2848
                    }
2849
                } else { // Show
2850
                    if (currentVis != "visible" || currentVis === "") {
2851
                        if (this.beforeShowEvent.fire()) {
2852
                            this._setDomVisibility(true);
2853
                            this.cfg.refireEvent("iframe");
2854
                            this.showEvent.fire();
2855
                        }
2856
                    } else {
2857
                        this._setDomVisibility(true);
2858
                    }
2859
                }
2860
            } else { // Hide
2861
 
2862
                if (isMacGecko) {
2863
                    this.hideMacGeckoScrollbars();
2864
                }
2865
 
2866
                if (effects) { // Animate out if showing
2867
                    if (currentVis == "visible" || this._fadingIn) {
2868
                        if (this.beforeHideEvent.fire()) {
2869
                            nEffectInstances = effects.length;
2870
                            for (k = 0; k < nEffectInstances; k++) {
2871
                                h = effects[k];
2872
 
2873
                                if (k === 0 && !alreadySubscribed(h.animateOutCompleteEvent, this.hideEvent.fire, this.hideEvent)) {
2874
                                    h.animateOutCompleteEvent.subscribe(this.hideEvent.fire, this.hideEvent, true);
2875
                                }
2876
                                h.animateOut();
2877
                            }
2878
                        }
2879
 
2880
                    } else if (currentVis === "") {
2881
                        this._setDomVisibility(false);
2882
                    }
2883
 
2884
                } else { // Simple hide
2885
 
2886
                    if (currentVis == "visible" || currentVis === "") {
2887
                        if (this.beforeHideEvent.fire()) {
2888
                            this._setDomVisibility(false);
2889
                            this.hideEvent.fire();
2890
                        }
2891
                    } else {
2892
                        this._setDomVisibility(false);
2893
                    }
2894
                }
2895
            }
2896
        },
2897
 
2898
        /**
2899
        * Fixed center event handler used for centering on scroll/resize, but only if
2900
        * the overlay is visible and, if "fixedcenter" is set to "contained", only if
2901
        * the overlay fits within the viewport.
2902
        *
2903
        * @method doCenterOnDOMEvent
2904
        */
2905
        doCenterOnDOMEvent: function () {
2906
            var cfg = this.cfg,
2907
                fc = cfg.getProperty("fixedcenter");
2908
 
2909
            if (cfg.getProperty("visible")) {
2910
                if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
2911
                    this.center();
2912
                }
2913
            }
2914
        },
2915
 
2916
        /**
2917
         * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
2918
         * will fit entirely inside the viewport, in both dimensions - width and height.
2919
         *
2920
         * @method fitsInViewport
2921
         * @return boolean true if the Overlay will fit, false if not
2922
         */
2923
        fitsInViewport : function() {
2924
            var nViewportOffset = Overlay.VIEWPORT_OFFSET,
2925
                element = this.element,
2926
                elementWidth = element.offsetWidth,
2927
                elementHeight = element.offsetHeight,
2928
                viewportWidth = Dom.getViewportWidth(),
2929
                viewportHeight = Dom.getViewportHeight();
2930
 
2931
            return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
2932
        },
2933
 
2934
        /**
2935
        * The default event handler fired when the "fixedcenter" property
2936
        * is changed.
2937
        * @method configFixedCenter
2938
        * @param {String} type The CustomEvent type (usually the property name)
2939
        * @param {Object[]} args The CustomEvent arguments. For configuration
2940
        * handlers, args[0] will equal the newly applied value for the property.
2941
        * @param {Object} obj The scope object. For configuration handlers,
2942
        * this will usually equal the owner.
2943
        */
2944
        configFixedCenter: function (type, args, obj) {
2945
 
2946
            var val = args[0],
2947
                alreadySubscribed = Config.alreadySubscribed,
2948
                windowResizeEvent = Overlay.windowResizeEvent,
2949
                windowScrollEvent = Overlay.windowScrollEvent;
2950
 
2951
            if (val) {
2952
                this.center();
2953
 
2954
                if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
2955
                    this.beforeShowEvent.subscribe(this.center);
2956
                }
2957
 
2958
                if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
2959
                    windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2960
                }
2961
 
2962
                if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
2963
                    windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
2964
                }
2965
 
2966
            } else {
2967
                this.beforeShowEvent.unsubscribe(this.center);
2968
 
2969
                windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2970
                windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
2971
            }
2972
        },
2973
 
2974
        /**
2975
        * The default event handler fired when the "height" property is changed.
2976
        * @method configHeight
2977
        * @param {String} type The CustomEvent type (usually the property name)
2978
        * @param {Object[]} args The CustomEvent arguments. For configuration
2979
        * handlers, args[0] will equal the newly applied value for the property.
2980
        * @param {Object} obj The scope object. For configuration handlers,
2981
        * this will usually equal the owner.
2982
        */
2983
        configHeight: function (type, args, obj) {
2984
 
2985
            var height = args[0],
2986
                el = this.element;
2987
 
2988
            Dom.setStyle(el, "height", height);
2989
            this.cfg.refireEvent("iframe");
2990
        },
2991
 
2992
        /**
2993
         * The default event handler fired when the "autofillheight" property is changed.
2994
         * @method configAutoFillHeight
2995
         *
2996
         * @param {String} type The CustomEvent type (usually the property name)
2997
         * @param {Object[]} args The CustomEvent arguments. For configuration
2998
         * handlers, args[0] will equal the newly applied value for the property.
2999
         * @param {Object} obj The scope object. For configuration handlers,
3000
         * this will usually equal the owner.
3001
         */
3002
        configAutoFillHeight: function (type, args, obj) {
3003
            var fillEl = args[0],
3004
                cfg = this.cfg,
3005
                autoFillHeight = "autofillheight",
3006
                height = "height",
3007
                currEl = cfg.getProperty(autoFillHeight),
3008
                autoFill = this._autoFillOnHeightChange;
3009
 
3010
            cfg.unsubscribeFromConfigEvent(height, autoFill);
3011
            Module.textResizeEvent.unsubscribe(autoFill);
3012
            this.changeContentEvent.unsubscribe(autoFill);
3013
 
3014
            if (currEl && fillEl !== currEl && this[currEl]) {
3015
                Dom.setStyle(this[currEl], height, "");
3016
            }
3017
 
3018
            if (fillEl) {
3019
                fillEl = Lang.trim(fillEl.toLowerCase());
3020
 
3021
                cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
3022
                Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
3023
                this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
3024
 
3025
                cfg.setProperty(autoFillHeight, fillEl, true);
3026
            }
3027
        },
3028
 
3029
        /**
3030
        * The default event handler fired when the "width" property is changed.
3031
        * @method configWidth
3032
        * @param {String} type The CustomEvent type (usually the property name)
3033
        * @param {Object[]} args The CustomEvent arguments. For configuration
3034
        * handlers, args[0] will equal the newly applied value for the property.
3035
        * @param {Object} obj The scope object. For configuration handlers,
3036
        * this will usually equal the owner.
3037
        */
3038
        configWidth: function (type, args, obj) {
3039
 
3040
            var width = args[0],
3041
                el = this.element;
3042
 
3043
            Dom.setStyle(el, "width", width);
3044
            this.cfg.refireEvent("iframe");
3045
        },
3046
 
3047
        /**
3048
        * The default event handler fired when the "zIndex" property is changed.
3049
        * @method configzIndex
3050
        * @param {String} type The CustomEvent type (usually the property name)
3051
        * @param {Object[]} args The CustomEvent arguments. For configuration
3052
        * handlers, args[0] will equal the newly applied value for the property.
3053
        * @param {Object} obj The scope object. For configuration handlers,
3054
        * this will usually equal the owner.
3055
        */
3056
        configzIndex: function (type, args, obj) {
3057
 
3058
            var zIndex = args[0],
3059
                el = this.element;
3060
 
3061
            if (! zIndex) {
3062
                zIndex = Dom.getStyle(el, "zIndex");
3063
                if (! zIndex || isNaN(zIndex)) {
3064
                    zIndex = 0;
3065
                }
3066
            }
3067
 
3068
            if (this.iframe || this.cfg.getProperty("iframe") === true) {
3069
                if (zIndex <= 0) {
3070
                    zIndex = 1;
3071
                }
3072
            }
3073
 
3074
            Dom.setStyle(el, "zIndex", zIndex);
3075
            this.cfg.setProperty("zIndex", zIndex, true);
3076
 
3077
            if (this.iframe) {
3078
                this.stackIframe();
3079
            }
3080
        },
3081
 
3082
        /**
3083
        * The default event handler fired when the "xy" property is changed.
3084
        * @method configXY
3085
        * @param {String} type The CustomEvent type (usually the property name)
3086
        * @param {Object[]} args The CustomEvent arguments. For configuration
3087
        * handlers, args[0] will equal the newly applied value for the property.
3088
        * @param {Object} obj The scope object. For configuration handlers,
3089
        * this will usually equal the owner.
3090
        */
3091
        configXY: function (type, args, obj) {
3092
 
3093
            var pos = args[0],
3094
                x = pos[0],
3095
                y = pos[1];
3096
 
3097
            this.cfg.setProperty("x", x);
3098
            this.cfg.setProperty("y", y);
3099
 
3100
            this.beforeMoveEvent.fire([x, y]);
3101
 
3102
            x = this.cfg.getProperty("x");
3103
            y = this.cfg.getProperty("y");
3104
 
3105
 
3106
            this.cfg.refireEvent("iframe");
3107
            this.moveEvent.fire([x, y]);
3108
        },
3109
 
3110
        /**
3111
        * The default event handler fired when the "x" property is changed.
3112
        * @method configX
3113
        * @param {String} type The CustomEvent type (usually the property name)
3114
        * @param {Object[]} args The CustomEvent arguments. For configuration
3115
        * handlers, args[0] will equal the newly applied value for the property.
3116
        * @param {Object} obj The scope object. For configuration handlers,
3117
        * this will usually equal the owner.
3118
        */
3119
        configX: function (type, args, obj) {
3120
 
3121
            var x = args[0],
3122
                y = this.cfg.getProperty("y");
3123
 
3124
            this.cfg.setProperty("x", x, true);
3125
            this.cfg.setProperty("y", y, true);
3126
 
3127
            this.beforeMoveEvent.fire([x, y]);
3128
 
3129
            x = this.cfg.getProperty("x");
3130
            y = this.cfg.getProperty("y");
3131
 
3132
            Dom.setX(this.element, x, true);
3133
 
3134
            this.cfg.setProperty("xy", [x, y], true);
3135
 
3136
            this.cfg.refireEvent("iframe");
3137
            this.moveEvent.fire([x, y]);
3138
        },
3139
 
3140
        /**
3141
        * The default event handler fired when the "y" property is changed.
3142
        * @method configY
3143
        * @param {String} type The CustomEvent type (usually the property name)
3144
        * @param {Object[]} args The CustomEvent arguments. For configuration
3145
        * handlers, args[0] will equal the newly applied value for the property.
3146
        * @param {Object} obj The scope object. For configuration handlers,
3147
        * this will usually equal the owner.
3148
        */
3149
        configY: function (type, args, obj) {
3150
 
3151
            var x = this.cfg.getProperty("x"),
3152
                y = args[0];
3153
 
3154
            this.cfg.setProperty("x", x, true);
3155
            this.cfg.setProperty("y", y, true);
3156
 
3157
            this.beforeMoveEvent.fire([x, y]);
3158
 
3159
            x = this.cfg.getProperty("x");
3160
            y = this.cfg.getProperty("y");
3161
 
3162
            Dom.setY(this.element, y, true);
3163
 
3164
            this.cfg.setProperty("xy", [x, y], true);
3165
 
3166
            this.cfg.refireEvent("iframe");
3167
            this.moveEvent.fire([x, y]);
3168
        },
3169
 
3170
        /**
3171
        * Shows the iframe shim, if it has been enabled.
3172
        * @method showIframe
3173
        */
3174
        showIframe: function () {
3175
 
3176
            var oIFrame = this.iframe,
3177
                oParentNode;
3178
 
3179
            if (oIFrame) {
3180
                oParentNode = this.element.parentNode;
3181
 
3182
                if (oParentNode != oIFrame.parentNode) {
3183
                    this._addToParent(oParentNode, oIFrame);
3184
                }
3185
                oIFrame.style.display = "block";
3186
            }
3187
        },
3188
 
3189
        /**
3190
        * Hides the iframe shim, if it has been enabled.
3191
        * @method hideIframe
3192
        */
3193
        hideIframe: function () {
3194
            if (this.iframe) {
3195
                this.iframe.style.display = "none";
3196
            }
3197
        },
3198
 
3199
        /**
3200
        * Syncronizes the size and position of iframe shim to that of its
3201
        * corresponding Overlay instance.
3202
        * @method syncIframe
3203
        */
3204
        syncIframe: function () {
3205
 
3206
            var oIFrame = this.iframe,
3207
                oElement = this.element,
3208
                nOffset = Overlay.IFRAME_OFFSET,
3209
                nDimensionOffset = (nOffset * 2),
3210
                aXY;
3211
 
3212
            if (oIFrame) {
3213
                // Size <iframe>
3214
                oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
3215
                oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
3216
 
3217
                // Position <iframe>
3218
                aXY = this.cfg.getProperty("xy");
3219
 
3220
                if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
3221
                    this.syncPosition();
3222
                    aXY = this.cfg.getProperty("xy");
3223
                }
3224
                Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
3225
            }
3226
        },
3227
 
3228
        /**
3229
         * Sets the zindex of the iframe shim, if it exists, based on the zindex of
3230
         * the Overlay element. The zindex of the iframe is set to be one less
3231
         * than the Overlay element's zindex.
3232
         *
3233
         * <p>NOTE: This method will not bump up the zindex of the Overlay element
3234
         * to ensure that the iframe shim has a non-negative zindex.
3235
         * If you require the iframe zindex to be 0 or higher, the zindex of
3236
         * the Overlay element should be set to a value greater than 0, before
3237
         * this method is called.
3238
         * </p>
3239
         * @method stackIframe
3240
         */
3241
        stackIframe: function () {
3242
            if (this.iframe) {
3243
                var overlayZ = Dom.getStyle(this.element, "zIndex");
3244
                if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
3245
                    Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
3246
                }
3247
            }
3248
        },
3249
 
3250
        /**
3251
        * The default event handler fired when the "iframe" property is changed.
3252
        * @method configIframe
3253
        * @param {String} type The CustomEvent type (usually the property name)
3254
        * @param {Object[]} args The CustomEvent arguments. For configuration
3255
        * handlers, args[0] will equal the newly applied value for the property.
3256
        * @param {Object} obj The scope object. For configuration handlers,
3257
        * this will usually equal the owner.
3258
        */
3259
        configIframe: function (type, args, obj) {
3260
 
3261
            var bIFrame = args[0];
3262
 
3263
            function createIFrame() {
3264
 
3265
                var oIFrame = this.iframe,
3266
                    oElement = this.element,
3267
                    oParent;
3268
 
3269
                if (!oIFrame) {
3270
                    if (!m_oIFrameTemplate) {
3271
                        m_oIFrameTemplate = document.createElement("iframe");
3272
 
3273
                        if (this.isSecure) {
3274
                            m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
3275
                        }
3276
 
3277
                        /*
3278
                            Set the opacity of the <iframe> to 0 so that it
3279
                            doesn't modify the opacity of any transparent
3280
                            elements that may be on top of it (like a shadow).
3281
                        */
3282
                        if (UA.ie) {
3283
                            m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
3284
                            /*
3285
                                 Need to set the "frameBorder" property to 0
3286
                                 supress the default <iframe> border in IE.
3287
                                 Setting the CSS "border" property alone
3288
                                 doesn't supress it.
3289
                            */
3290
                            m_oIFrameTemplate.frameBorder = 0;
3291
                        }
3292
                        else {
3293
                            m_oIFrameTemplate.style.opacity = "0";
3294
                        }
3295
 
3296
                        m_oIFrameTemplate.style.position = "absolute";
3297
                        m_oIFrameTemplate.style.border = "none";
3298
                        m_oIFrameTemplate.style.margin = "0";
3299
                        m_oIFrameTemplate.style.padding = "0";
3300
                        m_oIFrameTemplate.style.display = "none";
3301
                        m_oIFrameTemplate.tabIndex = -1;
3302
                        m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
3303
                    }
3304
 
3305
                    oIFrame = m_oIFrameTemplate.cloneNode(false);
3306
                    oIFrame.id = this.id + "_f";
3307
                    oParent = oElement.parentNode;
3308
 
3309
                    var parentNode = oParent || document.body;
3310
 
3311
                    this._addToParent(parentNode, oIFrame);
3312
                    this.iframe = oIFrame;
3313
                }
3314
 
3315
                /*
3316
                     Show the <iframe> before positioning it since the "setXY"
3317
                     method of DOM requires the element be in the document
3318
                     and visible.
3319
                */
3320
                this.showIframe();
3321
 
3322
                /*
3323
                     Syncronize the size and position of the <iframe> to that
3324
                     of the Overlay.
3325
                */
3326
                this.syncIframe();
3327
                this.stackIframe();
3328
 
3329
                // Add event listeners to update the <iframe> when necessary
3330
                if (!this._hasIframeEventListeners) {
3331
                    this.showEvent.subscribe(this.showIframe);
3332
                    this.hideEvent.subscribe(this.hideIframe);
3333
                    this.changeContentEvent.subscribe(this.syncIframe);
3334
 
3335
                    this._hasIframeEventListeners = true;
3336
                }
3337
            }
3338
 
3339
            function onBeforeShow() {
3340
                createIFrame.call(this);
3341
                this.beforeShowEvent.unsubscribe(onBeforeShow);
3342
                this._iframeDeferred = false;
3343
            }
3344
 
3345
            if (bIFrame) { // <iframe> shim is enabled
3346
 
3347
                if (this.cfg.getProperty("visible")) {
3348
                    createIFrame.call(this);
3349
                } else {
3350
                    if (!this._iframeDeferred) {
3351
                        this.beforeShowEvent.subscribe(onBeforeShow);
3352
                        this._iframeDeferred = true;
3353
                    }
3354
                }
3355
 
3356
            } else {    // <iframe> shim is disabled
3357
                this.hideIframe();
3358
 
3359
                if (this._hasIframeEventListeners) {
3360
                    this.showEvent.unsubscribe(this.showIframe);
3361
                    this.hideEvent.unsubscribe(this.hideIframe);
3362
                    this.changeContentEvent.unsubscribe(this.syncIframe);
3363
 
3364
                    this._hasIframeEventListeners = false;
3365
                }
3366
            }
3367
        },
3368
 
3369
        /**
3370
         * Set's the container's XY value from DOM if not already set.
3371
         *
3372
         * Differs from syncPosition, in that the XY value is only sync'd with DOM if
3373
         * not already set. The method also refire's the XY config property event, so any
3374
         * beforeMove, Move event listeners are invoked.
3375
         *
3376
         * @method _primeXYFromDOM
3377
         * @protected
3378
         */
3379
        _primeXYFromDOM : function() {
3380
            if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
3381
                // Set CFG XY based on DOM XY
3382
                this.syncPosition();
3383
                // Account for XY being set silently in syncPosition (no moveTo fired/called)
3384
                this.cfg.refireEvent("xy");
3385
                this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3386
            }
3387
        },
3388
 
3389
        /**
3390
        * The default event handler fired when the "constraintoviewport"
3391
        * property is changed.
3392
        * @method configConstrainToViewport
3393
        * @param {String} type The CustomEvent type (usually the property name)
3394
        * @param {Object[]} args The CustomEvent arguments. For configuration
3395
        * handlers, args[0] will equal the newly applied value for
3396
        * the property.
3397
        * @param {Object} obj The scope object. For configuration handlers,
3398
        * this will usually equal the owner.
3399
        */
3400
        configConstrainToViewport: function (type, args, obj) {
3401
            var val = args[0];
3402
 
3403
            if (val) {
3404
                if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
3405
                    this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
3406
                }
3407
                if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
3408
                    this.beforeShowEvent.subscribe(this._primeXYFromDOM);
3409
                }
3410
            } else {
3411
                this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
3412
                this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
3413
            }
3414
        },
3415
 
3416
         /**
3417
        * The default event handler fired when the "context" property
3418
        * is changed.
3419
        *
3420
        * @method configContext
3421
        * @param {String} type The CustomEvent type (usually the property name)
3422
        * @param {Object[]} args The CustomEvent arguments. For configuration
3423
        * handlers, args[0] will equal the newly applied value for the property.
3424
        * @param {Object} obj The scope object. For configuration handlers,
3425
        * this will usually equal the owner.
3426
        */
3427
        configContext: function (type, args, obj) {
3428
 
3429
            var contextArgs = args[0],
3430
                contextEl,
3431
                elementMagnetCorner,
3432
                contextMagnetCorner,
3433
                triggers,
3434
                offset,
3435
                defTriggers = this.CONTEXT_TRIGGERS;
3436
 
3437
            if (contextArgs) {
3438
 
3439
                contextEl = contextArgs[0];
3440
                elementMagnetCorner = contextArgs[1];
3441
                contextMagnetCorner = contextArgs[2];
3442
                triggers = contextArgs[3];
3443
                offset = contextArgs[4];
3444
 
3445
                if (defTriggers && defTriggers.length > 0) {
3446
                    triggers = (triggers || []).concat(defTriggers);
3447
                }
3448
 
3449
                if (contextEl) {
3450
                    if (typeof contextEl == "string") {
3451
                        this.cfg.setProperty("context", [
3452
                                document.getElementById(contextEl),
3453
                                elementMagnetCorner,
3454
                                contextMagnetCorner,
3455
                                triggers,
3456
                                offset],
3457
                                true);
3458
                    }
3459
 
3460
                    if (elementMagnetCorner && contextMagnetCorner) {
3461
                        this.align(elementMagnetCorner, contextMagnetCorner, offset);
3462
                    }
3463
 
3464
                    if (this._contextTriggers) {
3465
                        // Unsubscribe Old Set
3466
                        this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
3467
                    }
3468
 
3469
                    if (triggers) {
3470
                        // Subscribe New Set
3471
                        this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
3472
                        this._contextTriggers = triggers;
3473
                    }
3474
                }
3475
            }
3476
        },
3477
 
3478
        /**
3479
         * Custom Event handler for context alignment triggers. Invokes the align method
3480
         *
3481
         * @method _alignOnTrigger
3482
         * @protected
3483
         *
3484
         * @param {String} type The event type (not used by the default implementation)
3485
         * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
3486
         */
3487
        _alignOnTrigger: function(type, args) {
3488
            this.align();
3489
        },
3490
 
3491
        /**
3492
         * Helper method to locate the custom event instance for the event name string
3493
         * passed in. As a convenience measure, any custom events passed in are returned.
3494
         *
3495
         * @method _findTriggerCE
3496
         * @private
3497
         *
3498
         * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
3499
         * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
3500
         */
3501
        _findTriggerCE : function(t) {
3502
            var tce = null;
3503
            if (t instanceof CustomEvent) {
3504
                tce = t;
3505
            } else if (Overlay._TRIGGER_MAP[t]) {
3506
                tce = Overlay._TRIGGER_MAP[t];
3507
            }
3508
            return tce;
3509
        },
3510
 
3511
        /**
3512
         * Utility method that subscribes or unsubscribes the given
3513
         * function from the list of trigger events provided.
3514
         *
3515
         * @method _processTriggers
3516
         * @protected
3517
         *
3518
         * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
3519
         * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
3520
         * subscribed/unsubscribed respectively.
3521
         *
3522
         * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
3523
         * we are subscribing or unsubscribing trigger listeners
3524
         *
3525
         * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
3526
         * Context is always set to the overlay instance, and no additional object argument
3527
         * get passed to the subscribed function.
3528
         */
3529
        _processTriggers : function(triggers, mode, fn) {
3530
            var t, tce;
3531
 
3532
            for (var i = 0, l = triggers.length; i < l; ++i) {
3533
                t = triggers[i];
3534
                tce = this._findTriggerCE(t);
3535
                if (tce) {
3536
                    tce[mode](fn, this, true);
3537
                } else {
3538
                    this[mode](t, fn);
3539
                }
3540
            }
3541
        },
3542
 
3543
        // END BUILT-IN PROPERTY EVENT HANDLERS //
3544
        /**
3545
        * Aligns the Overlay to its context element using the specified corner
3546
        * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
3547
        * and BOTTOM_RIGHT.
3548
        * @method align
3549
        * @param {String} elementAlign  The String representing the corner of
3550
        * the Overlay that should be aligned to the context element
3551
        * @param {String} contextAlign  The corner of the context element
3552
        * that the elementAlign corner should stick to.
3553
        * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
3554
        * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
3555
        * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
3556
        */
3557
        align: function (elementAlign, contextAlign, xyOffset) {
3558
 
3559
            var contextArgs = this.cfg.getProperty("context"),
3560
                me = this,
3561
                context,
3562
                element,
3563
                contextRegion;
3564
 
3565
            function doAlign(v, h) {
3566
 
3567
                var alignX = null, alignY = null;
3568
 
3569
                switch (elementAlign) {
3570
 
3571
                    case Overlay.TOP_LEFT:
3572
                        alignX = h;
3573
                        alignY = v;
3574
                        break;
3575
 
3576
                    case Overlay.TOP_RIGHT:
3577
                        alignX = h - element.offsetWidth;
3578
                        alignY = v;
3579
                        break;
3580
 
3581
                    case Overlay.BOTTOM_LEFT:
3582
                        alignX = h;
3583
                        alignY = v - element.offsetHeight;
3584
                        break;
3585
 
3586
                    case Overlay.BOTTOM_RIGHT:
3587
                        alignX = h - element.offsetWidth;
3588
                        alignY = v - element.offsetHeight;
3589
                        break;
3590
                }
3591
 
3592
                if (alignX !== null && alignY !== null) {
3593
                    if (xyOffset) {
3594
                        alignX += xyOffset[0];
3595
                        alignY += xyOffset[1];
3596
                    }
3597
                    me.moveTo(alignX, alignY);
3598
                }
3599
            }
3600
 
3601
            if (contextArgs) {
3602
                context = contextArgs[0];
3603
                element = this.element;
3604
                me = this;
3605
 
3606
                if (! elementAlign) {
3607
                    elementAlign = contextArgs[1];
3608
                }
3609
 
3610
                if (! contextAlign) {
3611
                    contextAlign = contextArgs[2];
3612
                }
3613
 
3614
                if (!xyOffset && contextArgs[4]) {
3615
                    xyOffset = contextArgs[4];
3616
                }
3617
 
3618
                if (element && context) {
3619
                    contextRegion = Dom.getRegion(context);
3620
 
3621
                    switch (contextAlign) {
3622
 
3623
                        case Overlay.TOP_LEFT:
3624
                            doAlign(contextRegion.top, contextRegion.left);
3625
                            break;
3626
 
3627
                        case Overlay.TOP_RIGHT:
3628
                            doAlign(contextRegion.top, contextRegion.right);
3629
                            break;
3630
 
3631
                        case Overlay.BOTTOM_LEFT:
3632
                            doAlign(contextRegion.bottom, contextRegion.left);
3633
                            break;
3634
 
3635
                        case Overlay.BOTTOM_RIGHT:
3636
                            doAlign(contextRegion.bottom, contextRegion.right);
3637
                            break;
3638
                    }
3639
                }
3640
            }
3641
        },
3642
 
3643
        /**
3644
        * The default event handler executed when the moveEvent is fired, if the
3645
        * "constraintoviewport" is set to true.
3646
        * @method enforceConstraints
3647
        * @param {String} type The CustomEvent type (usually the property name)
3648
        * @param {Object[]} args The CustomEvent arguments. For configuration
3649
        * handlers, args[0] will equal the newly applied value for the property.
3650
        * @param {Object} obj The scope object. For configuration handlers,
3651
        * this will usually equal the owner.
3652
        */
3653
        enforceConstraints: function (type, args, obj) {
3654
            var pos = args[0];
3655
 
3656
            var cXY = this.getConstrainedXY(pos[0], pos[1]);
3657
            this.cfg.setProperty("x", cXY[0], true);
3658
            this.cfg.setProperty("y", cXY[1], true);
3659
            this.cfg.setProperty("xy", cXY, true);
3660
        },
3661
 
3662
        /**
3663
         * Shared implementation method for getConstrainedX and getConstrainedY.
3664
         *
3665
         * <p>
3666
         * Given a coordinate value, returns the calculated coordinate required to
3667
         * position the Overlay if it is to be constrained to the viewport, based on the
3668
         * current element size, viewport dimensions, scroll values and preventoverlap
3669
         * settings
3670
         * </p>
3671
         *
3672
         * @method _getConstrainedPos
3673
         * @protected
3674
         * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
3675
         * @param {Number} The coordinate value which needs to be constrained
3676
         * @return {Number} The constrained coordinate value
3677
         */
3678
        _getConstrainedPos: function(pos, val) {
3679
 
3680
            var overlayEl = this.element,
3681
 
3682
                buffer = Overlay.VIEWPORT_OFFSET,
3683
 
3684
                x = (pos == "x"),
3685
 
3686
                overlaySize      = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
3687
                viewportSize     = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
3688
                docScroll        = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
3689
                overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
3690
 
3691
                context = this.cfg.getProperty("context"),
3692
 
3693
                bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
3694
                bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
3695
 
3696
                minConstraint = docScroll + buffer,
3697
                maxConstraint = docScroll + viewportSize - overlaySize - buffer,
3698
 
3699
                constrainedVal = val;
3700
 
3701
            if (val < minConstraint || val > maxConstraint) {
3702
                if (bPreventContextOverlap) {
3703
                    constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
3704
                } else {
3705
                    if (bOverlayFitsInViewport) {
3706
                        if (val < minConstraint) {
3707
                            constrainedVal = minConstraint;
3708
                        } else if (val > maxConstraint) {
3709
                            constrainedVal = maxConstraint;
3710
                        }
3711
                    } else {
3712
                        constrainedVal = minConstraint;
3713
                    }
3714
                }
3715
            }
3716
 
3717
            return constrainedVal;
3718
        },
3719
 
3720
        /**
3721
         * Helper method, used to position the Overlap to prevent overlap with the
3722
         * context element (used when preventcontextoverlap is enabled)
3723
         *
3724
         * @method _preventOverlap
3725
         * @protected
3726
         * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
3727
         * @param {HTMLElement} contextEl The context element
3728
         * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
3729
         * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
3730
         * @param {Object} docScroll  The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
3731
         *
3732
         * @return {Number} The new coordinate value which was set to prevent overlap
3733
         */
3734
        _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
3735
 
3736
            var x = (pos == "x"),
3737
 
3738
                buffer = Overlay.VIEWPORT_OFFSET,
3739
 
3740
                overlay = this,
3741
 
3742
                contextElPos   = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
3743
                contextElSize  = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
3744
 
3745
                minRegionSize = contextElPos - buffer,
3746
                maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
3747
 
3748
                bFlipped = false,
3749
 
3750
                flip = function () {
3751
                    var flippedVal;
3752
 
3753
                    if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
3754
                        flippedVal = (contextElPos - overlaySize);
3755
                    } else {
3756
                        flippedVal = (contextElPos + contextElSize);
3757
                    }
3758
 
3759
                    overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
3760
 
3761
                    return flippedVal;
3762
                },
3763
 
3764
                setPosition = function () {
3765
 
3766
                    var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
3767
                        position;
3768
 
3769
                    if (overlaySize > displayRegionSize) {
3770
                        if (bFlipped) {
3771
                            /*
3772
                                 All possible positions and values have been
3773
                                 tried, but none were successful, so fall back
3774
                                 to the original size and position.
3775
                            */
3776
                            flip();
3777
                        } else {
3778
                            flip();
3779
                            bFlipped = true;
3780
                            position = setPosition();
3781
                        }
3782
                    }
3783
 
3784
                    return position;
3785
                };
3786
 
3787
            setPosition();
3788
 
3789
            return this.cfg.getProperty(pos);
3790
        },
3791
 
3792
        /**
3793
         * Given x coordinate value, returns the calculated x coordinate required to
3794
         * position the Overlay if it is to be constrained to the viewport, based on the
3795
         * current element size, viewport dimensions and scroll values.
3796
         *
3797
         * @param {Number} x The X coordinate value to be constrained
3798
         * @return {Number} The constrained x coordinate
3799
         */
3800
        getConstrainedX: function (x) {
3801
            return this._getConstrainedPos("x", x);
3802
        },
3803
 
3804
        /**
3805
         * Given y coordinate value, returns the calculated y coordinate required to
3806
         * position the Overlay if it is to be constrained to the viewport, based on the
3807
         * current element size, viewport dimensions and scroll values.
3808
         *
3809
         * @param {Number} y The Y coordinate value to be constrained
3810
         * @return {Number} The constrained y coordinate
3811
         */
3812
        getConstrainedY : function (y) {
3813
            return this._getConstrainedPos("y", y);
3814
        },
3815
 
3816
        /**
3817
         * Given x, y coordinate values, returns the calculated coordinates required to
3818
         * position the Overlay if it is to be constrained to the viewport, based on the
3819
         * current element size, viewport dimensions and scroll values.
3820
         *
3821
         * @param {Number} x The X coordinate value to be constrained
3822
         * @param {Number} y The Y coordinate value to be constrained
3823
         * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
3824
         */
3825
        getConstrainedXY: function(x, y) {
3826
            return [this.getConstrainedX(x), this.getConstrainedY(y)];
3827
        },
3828
 
3829
        /**
3830
        * Centers the container in the viewport.
3831
        * @method center
3832
        */
3833
        center: function () {
3834
 
3835
            var nViewportOffset = Overlay.VIEWPORT_OFFSET,
3836
                elementWidth = this.element.offsetWidth,
3837
                elementHeight = this.element.offsetHeight,
3838
                viewPortWidth = Dom.getViewportWidth(),
3839
                viewPortHeight = Dom.getViewportHeight(),
3840
                x,
3841
                y;
3842
 
3843
            if (elementWidth < viewPortWidth) {
3844
                x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
3845
            } else {
3846
                x = nViewportOffset + Dom.getDocumentScrollLeft();
3847
            }
3848
 
3849
            if (elementHeight < viewPortHeight) {
3850
                y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
3851
            } else {
3852
                y = nViewportOffset + Dom.getDocumentScrollTop();
3853
            }
3854
 
3855
            this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
3856
            this.cfg.refireEvent("iframe");
3857
 
3858
            if (UA.webkit) {
3859
                this.forceContainerRedraw();
3860
            }
3861
        },
3862
 
3863
        /**
3864
        * Synchronizes the Panel's "xy", "x", and "y" properties with the
3865
        * Panel's position in the DOM. This is primarily used to update
3866
        * position information during drag & drop.
3867
        * @method syncPosition
3868
        */
3869
        syncPosition: function () {
3870
 
3871
            var pos = Dom.getXY(this.element);
3872
 
3873
            this.cfg.setProperty("x", pos[0], true);
3874
            this.cfg.setProperty("y", pos[1], true);
3875
            this.cfg.setProperty("xy", pos, true);
3876
 
3877
        },
3878
 
3879
        /**
3880
        * Event handler fired when the resize monitor element is resized.
3881
        * @method onDomResize
3882
        * @param {DOMEvent} e The resize DOM event
3883
        * @param {Object} obj The scope object
3884
        */
3885
        onDomResize: function (e, obj) {
3886
 
3887
            var me = this;
3888
 
3889
            Overlay.superclass.onDomResize.call(this, e, obj);
3890
 
3891
            setTimeout(function () {
3892
                me.syncPosition();
3893
                me.cfg.refireEvent("iframe");
3894
                me.cfg.refireEvent("context");
3895
            }, 0);
3896
        },
3897
 
3898
        /**
3899
         * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
3900
         *
3901
         * @method _getComputedHeight
3902
         * @private
3903
         * @param {HTMLElement} el The element for which the content height needs to be determined
3904
         * @return {Number} The content box height of the given element, or null if it could not be determined.
3905
         */
3906
        _getComputedHeight : (function() {
3907
 
3908
            if (document.defaultView && document.defaultView.getComputedStyle) {
3909
                return function(el) {
3910
                    var height = null;
3911
                    if (el.ownerDocument && el.ownerDocument.defaultView) {
3912
                        var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
3913
                        if (computed) {
3914
                            height = parseInt(computed.height, 10);
3915
                        }
3916
                    }
3917
                    return (Lang.isNumber(height)) ? height : null;
3918
                };
3919
            } else {
3920
                return function(el) {
3921
                    var height = null;
3922
                    if (el.style.pixelHeight) {
3923
                        height = el.style.pixelHeight;
3924
                    }
3925
                    return (Lang.isNumber(height)) ? height : null;
3926
                };
3927
            }
3928
        })(),
3929
 
3930
        /**
3931
         * autofillheight validator. Verifies that the autofill value is either null
3932
         * or one of the strings : "body", "header" or "footer".
3933
         *
3934
         * @method _validateAutoFillHeight
3935
         * @protected
3936
         * @param {String} val
3937
         * @return true, if valid, false otherwise
3938
         */
3939
        _validateAutoFillHeight : function(val) {
3940
            return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
3941
        },
3942
 
3943
        /**
3944
         * The default custom event handler executed when the overlay's height is changed,
3945
         * if the autofillheight property has been set.
3946
         *
3947
         * @method _autoFillOnHeightChange
3948
         * @protected
3949
         * @param {String} type The event type
3950
         * @param {Array} args The array of arguments passed to event subscribers
3951
         * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
3952
         * out the containers height
3953
         */
3954
        _autoFillOnHeightChange : function(type, args, el) {
3955
            var height = this.cfg.getProperty("height");
3956
            if ((height && height !== "auto") || (height === 0)) {
3957
                this.fillHeight(el);
3958
            }
3959
        },
3960
 
3961
        /**
3962
         * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
3963
         * otherwise returns the offsetHeight
3964
         * @method _getPreciseHeight
3965
         * @private
3966
         * @param {HTMLElement} el
3967
         * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
3968
         */
3969
        _getPreciseHeight : function(el) {
3970
            var height = el.offsetHeight;
3971
 
3972
            if (el.getBoundingClientRect) {
3973
                var rect = el.getBoundingClientRect();
3974
                height = rect.bottom - rect.top;
3975
            }
3976
 
3977
            return height;
3978
        },
3979
 
3980
        /**
3981
         * <p>
3982
         * Sets the height on the provided header, body or footer element to
3983
         * fill out the height of the container. It determines the height of the
3984
         * containers content box, based on it's configured height value, and
3985
         * sets the height of the autofillheight element to fill out any
3986
         * space remaining after the other standard module element heights
3987
         * have been accounted for.
3988
         * </p>
3989
         * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
3990
         * height has not been set on the container, since for an "auto" height container,
3991
         * the heights of the header/body/footer will drive the height of the container.</p>
3992
         *
3993
         * @method fillHeight
3994
         * @param {HTMLElement} el The element which should be resized to fill out the height
3995
         * of the container element.
3996
         */
3997
        fillHeight : function(el) {
3998
            if (el) {
3999
                var container = this.innerElement || this.element,
4000
                    containerEls = [this.header, this.body, this.footer],
4001
                    containerEl,
4002
                    total = 0,
4003
                    filled = 0,
4004
                    remaining = 0,
4005
                    validEl = false;
4006
 
4007
                for (var i = 0, l = containerEls.length; i < l; i++) {
4008
                    containerEl = containerEls[i];
4009
                    if (containerEl) {
4010
                        if (el !== containerEl) {
4011
                            filled += this._getPreciseHeight(containerEl);
4012
                        } else {
4013
                            validEl = true;
4014
                        }
4015
                    }
4016
                }
4017
 
4018
                if (validEl) {
4019
 
4020
                    if (UA.ie || UA.opera) {
4021
                        // Need to set height to 0, to allow height to be reduced
4022
                        Dom.setStyle(el, 'height', 0 + 'px');
4023
                    }
4024
 
4025
                    total = this._getComputedHeight(container);
4026
 
4027
                    // Fallback, if we can't get computed value for content height
4028
                    if (total === null) {
4029
                        Dom.addClass(container, "yui-override-padding");
4030
                        total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
4031
                        Dom.removeClass(container, "yui-override-padding");
4032
                    }
4033
 
4034
                    remaining = Math.max(total - filled, 0);
4035
 
4036
                    Dom.setStyle(el, "height", remaining + "px");
4037
 
4038
                    // Re-adjust height if required, to account for el padding and border
4039
                    if (el.offsetHeight != remaining) {
4040
                        remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
4041
                    }
4042
                    Dom.setStyle(el, "height", remaining + "px");
4043
                }
4044
            }
4045
        },
4046
 
4047
        /**
4048
        * Places the Overlay on top of all other instances of
4049
        * YAHOO.widget.Overlay.
4050
        * @method bringToTop
4051
        */
4052
        bringToTop: function () {
4053
 
4054
            var aOverlays = [],
4055
                oElement = this.element;
4056
 
4057
            function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
4058
 
4059
                var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
4060
                    sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
4061
 
4062
                    nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
4063
                    nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
4064
 
4065
                if (nZIndex1 > nZIndex2) {
4066
                    return -1;
4067
                } else if (nZIndex1 < nZIndex2) {
4068
                    return 1;
4069
                } else {
4070
                    return 0;
4071
                }
4072
            }
4073
 
4074
            function isOverlayElement(p_oElement) {
4075
 
4076
                var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
4077
                    Panel = YAHOO.widget.Panel;
4078
 
4079
                if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
4080
                    if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
4081
                        aOverlays[aOverlays.length] = p_oElement.parentNode;
4082
                    } else {
4083
                        aOverlays[aOverlays.length] = p_oElement;
4084
                    }
4085
                }
4086
            }
4087
 
4088
            Dom.getElementsBy(isOverlayElement, "div", document.body);
4089
 
4090
            aOverlays.sort(compareZIndexDesc);
4091
 
4092
            var oTopOverlay = aOverlays[0],
4093
                nTopZIndex;
4094
 
4095
            if (oTopOverlay) {
4096
                nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
4097
 
4098
                if (!isNaN(nTopZIndex)) {
4099
                    var bRequiresBump = false;
4100
 
4101
                    if (oTopOverlay != oElement) {
4102
                        bRequiresBump = true;
4103
                    } else if (aOverlays.length > 1) {
4104
                        var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
4105
                        // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4106
                        if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4107
                            bRequiresBump = true;
4108
                        }
4109
                    }
4110
                    if (bRequiresBump) {
4111
                        this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4112
                    }
4113
                }
4114
            }
4115
        },
4116
 
4117
        /**
4118
        * Removes the Overlay element from the DOM and sets all child
4119
        * elements to null.
4120
        * @method destroy
4121
        * @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.
4122
        * 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.
4123
        */
4124
        destroy: function (shallowPurge) {
4125
 
4126
            if (this.iframe) {
4127
                this.iframe.parentNode.removeChild(this.iframe);
4128
            }
4129
 
4130
            this.iframe = null;
4131
 
4132
            Overlay.windowResizeEvent.unsubscribe(
4133
                this.doCenterOnDOMEvent, this);
4134
 
4135
            Overlay.windowScrollEvent.unsubscribe(
4136
                this.doCenterOnDOMEvent, this);
4137
 
4138
            Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
4139
 
4140
            if (this._contextTriggers) {
4141
                // Unsubscribe context triggers - to cover context triggers which listen for global
4142
                // events such as windowResize and windowScroll. Easier just to unsubscribe all
4143
                this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
4144
            }
4145
 
4146
            Overlay.superclass.destroy.call(this, shallowPurge);
4147
        },
4148
 
4149
        /**
4150
         * Can be used to force the container to repaint/redraw it's contents.
4151
         * <p>
4152
         * By default applies and then removes a 1px bottom margin through the
4153
         * application/removal of a "yui-force-redraw" class.
4154
         * </p>
4155
         * <p>
4156
         * It is currently used by Overlay to force a repaint for webkit
4157
         * browsers, when centering.
4158
         * </p>
4159
         * @method forceContainerRedraw
4160
         */
4161
        forceContainerRedraw : function() {
4162
            var c = this;
4163
            Dom.addClass(c.element, "yui-force-redraw");
4164
            setTimeout(function() {
4165
                Dom.removeClass(c.element, "yui-force-redraw");
4166
            }, 0);
4167
        },
4168
 
4169
        /**
4170
        * Returns a String representation of the object.
4171
        * @method toString
4172
        * @return {String} The string representation of the Overlay.
4173
        */
4174
        toString: function () {
4175
            return "Overlay " + this.id;
4176
        }
4177
 
4178
    });
4179
}());
4180
(function () {
4181
 
4182
    /**
4183
    * OverlayManager is used for maintaining the focus status of
4184
    * multiple Overlays.
4185
    * @namespace YAHOO.widget
4186
    * @namespace YAHOO.widget
4187
    * @class OverlayManager
4188
    * @constructor
4189
    * @param {Array} overlays Optional. A collection of Overlays to register
4190
    * with the manager.
4191
    * @param {Object} userConfig  The object literal representing the user
4192
    * configuration of the OverlayManager
4193
    */
4194
    YAHOO.widget.OverlayManager = function (userConfig) {
4195
        this.init(userConfig);
4196
    };
4197
 
4198
    var Overlay = YAHOO.widget.Overlay,
4199
        Event = YAHOO.util.Event,
4200
        Dom = YAHOO.util.Dom,
4201
        Config = YAHOO.util.Config,
4202
        CustomEvent = YAHOO.util.CustomEvent,
4203
        OverlayManager = YAHOO.widget.OverlayManager;
4204
 
4205
    /**
4206
    * The CSS class representing a focused Overlay
4207
    * @property OverlayManager.CSS_FOCUSED
4208
    * @static
4209
    * @final
4210
    * @type String
4211
    */
4212
    OverlayManager.CSS_FOCUSED = "focused";
4213
 
4214
    OverlayManager.prototype = {
4215
 
4216
        /**
4217
        * The class's constructor function
4218
        * @property contructor
4219
        * @type Function
4220
        */
4221
        constructor: OverlayManager,
4222
 
4223
        /**
4224
        * The array of Overlays that are currently registered
4225
        * @property overlays
4226
        * @type YAHOO.widget.Overlay[]
4227
        */
4228
        overlays: null,
4229
 
4230
        /**
4231
        * Initializes the default configuration of the OverlayManager
4232
        * @method initDefaultConfig
4233
        */
4234
        initDefaultConfig: function () {
4235
            /**
4236
            * The collection of registered Overlays in use by
4237
            * the OverlayManager
4238
            * @config overlays
4239
            * @type YAHOO.widget.Overlay[]
4240
            * @default null
4241
            */
4242
            this.cfg.addProperty("overlays", { suppressEvent: true } );
4243
 
4244
            /**
4245
            * The default DOM event that should be used to focus an Overlay
4246
            * @config focusevent
4247
            * @type String
4248
            * @default "mousedown"
4249
            */
4250
            this.cfg.addProperty("focusevent", { value: "mousedown" } );
4251
        },
4252
 
4253
        /**
4254
        * Initializes the OverlayManager
4255
        * @method init
4256
        * @param {Overlay[]} overlays Optional. A collection of Overlays to
4257
        * register with the manager.
4258
        * @param {Object} userConfig  The object literal representing the user
4259
        * configuration of the OverlayManager
4260
        */
4261
        init: function (userConfig) {
4262
 
4263
            /**
4264
            * The OverlayManager's Config object used for monitoring
4265
            * configuration properties.
4266
            * @property cfg
4267
            * @type Config
4268
            */
4269
            this.cfg = new Config(this);
4270
 
4271
            this.initDefaultConfig();
4272
 
4273
            if (userConfig) {
4274
                this.cfg.applyConfig(userConfig, true);
4275
            }
4276
            this.cfg.fireQueue();
4277
 
4278
            /**
4279
            * The currently activated Overlay
4280
            * @property activeOverlay
4281
            * @private
4282
            * @type YAHOO.widget.Overlay
4283
            */
4284
            var activeOverlay = null;
4285
 
4286
            /**
4287
            * Returns the currently focused Overlay
4288
            * @method getActive
4289
            * @return {Overlay} The currently focused Overlay
4290
            */
4291
            this.getActive = function () {
4292
                return activeOverlay;
4293
            };
4294
 
4295
            /**
4296
            * Focuses the specified Overlay
4297
            * @method focus
4298
            * @param {Overlay} overlay The Overlay to focus
4299
            * @param {String} overlay The id of the Overlay to focus
4300
            */
4301
            this.focus = function (overlay) {
4302
                var o = this.find(overlay);
4303
                if (o) {
4304
                    o.focus();
4305
                }
4306
            };
4307
 
4308
            /**
4309
            * Removes the specified Overlay from the manager
4310
            * @method remove
4311
            * @param {Overlay} overlay The Overlay to remove
4312
            * @param {String} overlay The id of the Overlay to remove
4313
            */
4314
            this.remove = function (overlay) {
4315
 
4316
                var o = this.find(overlay),
4317
                        originalZ;
4318
 
4319
                if (o) {
4320
                    if (activeOverlay == o) {
4321
                        activeOverlay = null;
4322
                    }
4323
 
4324
                    var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
4325
 
4326
                    if (!bDestroyed) {
4327
                        // Set it's zindex so that it's sorted to the end.
4328
                        originalZ = Dom.getStyle(o.element, "zIndex");
4329
                        o.cfg.setProperty("zIndex", -1000, true);
4330
                    }
4331
 
4332
                    this.overlays.sort(this.compareZIndexDesc);
4333
                    this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
4334
 
4335
                    o.hideEvent.unsubscribe(o.blur);
4336
                    o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
4337
                    o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
4338
                    o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
4339
 
4340
                    if (!bDestroyed) {
4341
                        Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
4342
                        o.cfg.setProperty("zIndex", originalZ, true);
4343
                        o.cfg.setProperty("manager", null);
4344
                    }
4345
 
4346
                    /* _managed Flag for custom or existing. Don't want to remove existing */
4347
                    if (o.focusEvent._managed) { o.focusEvent = null; }
4348
                    if (o.blurEvent._managed) { o.blurEvent = null; }
4349
 
4350
                    if (o.focus._managed) { o.focus = null; }
4351
                    if (o.blur._managed) { o.blur = null; }
4352
                }
4353
            };
4354
 
4355
            /**
4356
            * Removes focus from all registered Overlays in the manager
4357
            * @method blurAll
4358
            */
4359
            this.blurAll = function () {
4360
 
4361
                var nOverlays = this.overlays.length,
4362
                    i;
4363
 
4364
                if (nOverlays > 0) {
4365
                    i = nOverlays - 1;
4366
                    do {
4367
                        this.overlays[i].blur();
4368
                    }
4369
                    while(i--);
4370
                }
4371
            };
4372
 
4373
            /**
4374
             * Updates the state of the OverlayManager and overlay, as a result of the overlay
4375
             * being blurred.
4376
             *
4377
             * @method _manageBlur
4378
             * @param {Overlay} overlay The overlay instance which got blurred.
4379
             * @protected
4380
             */
4381
            this._manageBlur = function (overlay) {
4382
                var changed = false;
4383
                if (activeOverlay == overlay) {
4384
                    Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4385
                    activeOverlay = null;
4386
                    changed = true;
4387
                }
4388
                return changed;
4389
            };
4390
 
4391
            /**
4392
             * Updates the state of the OverlayManager and overlay, as a result of the overlay
4393
             * receiving focus.
4394
             *
4395
             * @method _manageFocus
4396
             * @param {Overlay} overlay The overlay instance which got focus.
4397
             * @protected
4398
             */
4399
            this._manageFocus = function(overlay) {
4400
                var changed = false;
4401
                if (activeOverlay != overlay) {
4402
                    if (activeOverlay) {
4403
                        activeOverlay.blur();
4404
                    }
4405
                    activeOverlay = overlay;
4406
                    this.bringToTop(activeOverlay);
4407
                    Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
4408
                    changed = true;
4409
                }
4410
                return changed;
4411
            };
4412
 
4413
            var overlays = this.cfg.getProperty("overlays");
4414
 
4415
            if (! this.overlays) {
4416
                this.overlays = [];
4417
            }
4418
 
4419
            if (overlays) {
4420
                this.register(overlays);
4421
                this.overlays.sort(this.compareZIndexDesc);
4422
            }
4423
        },
4424
 
4425
        /**
4426
        * @method _onOverlayElementFocus
4427
        * @description Event handler for the DOM event that is used to focus
4428
        * the Overlay instance as specified by the "focusevent"
4429
        * configuration property.
4430
        * @private
4431
        * @param {Event} p_oEvent Object representing the DOM event
4432
        * object passed back by the event utility (Event).
4433
        */
4434
        _onOverlayElementFocus: function (p_oEvent) {
4435
 
4436
            var oTarget = Event.getTarget(p_oEvent),
4437
                oClose = this.close;
4438
 
4439
            if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
4440
                this.blur();
4441
            } else {
4442
                this.focus();
4443
            }
4444
        },
4445
 
4446
        /**
4447
        * @method _onOverlayDestroy
4448
        * @description "destroy" event handler for the Overlay.
4449
        * @private
4450
        * @param {String} p_sType String representing the name of the event
4451
        * that was fired.
4452
        * @param {Array} p_aArgs Array of arguments sent when the event
4453
        * was fired.
4454
        * @param {Overlay} p_oOverlay Object representing the overlay that
4455
        * fired the event.
4456
        */
4457
        _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
4458
            this.remove(p_oOverlay);
4459
        },
4460
 
4461
        /**
4462
        * @method _onOverlayFocusHandler
4463
        *
4464
        * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
4465
        *
4466
        * @private
4467
        * @param {String} p_sType String representing the name of the event
4468
        * that was fired.
4469
        * @param {Array} p_aArgs Array of arguments sent when the event
4470
        * was fired.
4471
        * @param {Overlay} p_oOverlay Object representing the overlay that
4472
        * fired the event.
4473
        */
4474
        _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
4475
            this._manageFocus(p_oOverlay);
4476
        },
4477
 
4478
        /**
4479
        * @method _onOverlayBlurHandler
4480
        * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
4481
        *
4482
        * @private
4483
        * @param {String} p_sType String representing the name of the event
4484
        * that was fired.
4485
        * @param {Array} p_aArgs Array of arguments sent when the event
4486
        * was fired.
4487
        * @param {Overlay} p_oOverlay Object representing the overlay that
4488
        * fired the event.
4489
        */
4490
        _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
4491
            this._manageBlur(p_oOverlay);
4492
        },
4493
 
4494
        /**
4495
         * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
4496
         * monitor focus state.
4497
         *
4498
         * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
4499
         * to the existing focusEvent, however if a focusEvent or focus method does not exist
4500
         * on the instance, the _bindFocus method will add them, and the focus method will
4501
         * update the OverlayManager's state directly.
4502
         *
4503
         * @method _bindFocus
4504
         * @param {Overlay} overlay The overlay for which focus needs to be managed
4505
         * @protected
4506
         */
4507
        _bindFocus : function(overlay) {
4508
            var mgr = this;
4509
 
4510
            if (!overlay.focusEvent) {
4511
                overlay.focusEvent = overlay.createEvent("focus");
4512
                overlay.focusEvent.signature = CustomEvent.LIST;
4513
                overlay.focusEvent._managed = true;
4514
            } else {
4515
                overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
4516
            }
4517
 
4518
            if (!overlay.focus) {
4519
                Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
4520
                overlay.focus = function () {
4521
                    if (mgr._manageFocus(this)) {
4522
                        // For Panel/Dialog
4523
                        if (this.cfg.getProperty("visible") && this.focusFirst) {
4524
                            this.focusFirst();
4525
                        }
4526
                        this.focusEvent.fire();
4527
                    }
4528
                };
4529
                overlay.focus._managed = true;
4530
            }
4531
        },
4532
 
4533
        /**
4534
         * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
4535
         * monitor blur state.
4536
         *
4537
         * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
4538
         * to the existing blurEvent, however if a blurEvent or blur method does not exist
4539
         * on the instance, the _bindBlur method will add them, and the blur method
4540
         * update the OverlayManager's state directly.
4541
         *
4542
         * @method _bindBlur
4543
         * @param {Overlay} overlay The overlay for which blur needs to be managed
4544
         * @protected
4545
         */
4546
        _bindBlur : function(overlay) {
4547
            var mgr = this;
4548
 
4549
            if (!overlay.blurEvent) {
4550
                overlay.blurEvent = overlay.createEvent("blur");
4551
                overlay.blurEvent.signature = CustomEvent.LIST;
4552
                overlay.focusEvent._managed = true;
4553
            } else {
4554
                overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
4555
            }
4556
 
4557
            if (!overlay.blur) {
4558
                overlay.blur = function () {
4559
                    if (mgr._manageBlur(this)) {
4560
                        this.blurEvent.fire();
4561
                    }
4562
                };
4563
                overlay.blur._managed = true;
4564
            }
4565
 
4566
            overlay.hideEvent.subscribe(overlay.blur);
4567
        },
4568
 
4569
        /**
4570
         * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
4571
         * to be removed for the OverlayManager when destroyed.
4572
         *
4573
         * @method _bindDestroy
4574
         * @param {Overlay} overlay The overlay instance being managed
4575
         * @protected
4576
         */
4577
        _bindDestroy : function(overlay) {
4578
            var mgr = this;
4579
            overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
4580
        },
4581
 
4582
        /**
4583
         * Ensures the zIndex configuration property on the managed overlay based instance
4584
         * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
4585
         *
4586
         * @method _syncZIndex
4587
         * @param {Overlay} overlay The overlay instance being managed
4588
         * @protected
4589
         */
4590
        _syncZIndex : function(overlay) {
4591
            var zIndex = Dom.getStyle(overlay.element, "zIndex");
4592
            if (!isNaN(zIndex)) {
4593
                overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
4594
            } else {
4595
                overlay.cfg.setProperty("zIndex", 0);
4596
            }
4597
        },
4598
 
4599
        /**
4600
        * Registers an Overlay or an array of Overlays with the manager. Upon
4601
        * registration, the Overlay receives functions for focus and blur,
4602
        * along with CustomEvents for each.
4603
        *
4604
        * @method register
4605
        * @param {Overlay} overlay  An Overlay to register with the manager.
4606
        * @param {Overlay[]} overlay  An array of Overlays to register with
4607
        * the manager.
4608
        * @return {boolean} true if any Overlays are registered.
4609
        */
4610
        register: function (overlay) {
4611
 
4612
            var registered = false,
4613
                i,
4614
                n;
4615
 
4616
            if (overlay instanceof Overlay) {
4617
 
4618
                overlay.cfg.addProperty("manager", { value: this } );
4619
 
4620
                this._bindFocus(overlay);
4621
                this._bindBlur(overlay);
4622
                this._bindDestroy(overlay);
4623
                this._syncZIndex(overlay);
4624
 
4625
                this.overlays.push(overlay);
4626
                this.bringToTop(overlay);
4627
 
4628
                registered = true;
4629
 
4630
            } else if (overlay instanceof Array) {
4631
 
4632
                for (i = 0, n = overlay.length; i < n; i++) {
4633
                    registered = this.register(overlay[i]) || registered;
4634
                }
4635
 
4636
            }
4637
 
4638
            return registered;
4639
        },
4640
 
4641
        /**
4642
        * Places the specified Overlay instance on top of all other
4643
        * Overlay instances.
4644
        * @method bringToTop
4645
        * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
4646
        * Overlay instance.
4647
        * @param {String} p_oOverlay String representing the id of an
4648
        * Overlay instance.
4649
        */
4650
        bringToTop: function (p_oOverlay) {
4651
 
4652
            var oOverlay = this.find(p_oOverlay),
4653
                nTopZIndex,
4654
                oTopOverlay,
4655
                aOverlays;
4656
 
4657
            if (oOverlay) {
4658
 
4659
                aOverlays = this.overlays;
4660
                aOverlays.sort(this.compareZIndexDesc);
4661
 
4662
                oTopOverlay = aOverlays[0];
4663
 
4664
                if (oTopOverlay) {
4665
                    nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
4666
 
4667
                    if (!isNaN(nTopZIndex)) {
4668
 
4669
                        var bRequiresBump = false;
4670
 
4671
                        if (oTopOverlay !== oOverlay) {
4672
                            bRequiresBump = true;
4673
                        } else if (aOverlays.length > 1) {
4674
                            var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
4675
                            // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
4676
                            if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
4677
                                bRequiresBump = true;
4678
                            }
4679
                        }
4680
 
4681
                        if (bRequiresBump) {
4682
                            oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
4683
                        }
4684
                    }
4685
                    aOverlays.sort(this.compareZIndexDesc);
4686
                }
4687
            }
4688
        },
4689
 
4690
        /**
4691
        * Attempts to locate an Overlay by instance or ID.
4692
        * @method find
4693
        * @param {Overlay} overlay  An Overlay to locate within the manager
4694
        * @param {String} overlay  An Overlay id to locate within the manager
4695
        * @return {Overlay} The requested Overlay, if found, or null if it
4696
        * cannot be located.
4697
        */
4698
        find: function (overlay) {
4699
 
4700
            var isInstance = overlay instanceof Overlay,
4701
                overlays = this.overlays,
4702
                n = overlays.length,
4703
                found = null,
4704
                o,
4705
                i;
4706
 
4707
            if (isInstance || typeof overlay == "string") {
4708
                for (i = n-1; i >= 0; i--) {
4709
                    o = overlays[i];
4710
                    if ((isInstance && (o === overlay)) || (o.id == overlay)) {
4711
                        found = o;
4712
                        break;
4713
                    }
4714
                }
4715
            }
4716
 
4717
            return found;
4718
        },
4719
 
4720
        /**
4721
        * Used for sorting the manager's Overlays by z-index.
4722
        * @method compareZIndexDesc
4723
        * @private
4724
        * @return {Number} 0, 1, or -1, depending on where the Overlay should
4725
        * fall in the stacking order.
4726
        */
4727
        compareZIndexDesc: function (o1, o2) {
4728
 
4729
            var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
4730
                zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
4731
 
4732
            if (zIndex1 === null && zIndex2 === null) {
4733
                return 0;
4734
            } else if (zIndex1 === null){
4735
                return 1;
4736
            } else if (zIndex2 === null) {
4737
                return -1;
4738
            } else if (zIndex1 > zIndex2) {
4739
                return -1;
4740
            } else if (zIndex1 < zIndex2) {
4741
                return 1;
4742
            } else {
4743
                return 0;
4744
            }
4745
        },
4746
 
4747
        /**
4748
        * Shows all Overlays in the manager.
4749
        * @method showAll
4750
        */
4751
        showAll: function () {
4752
            var overlays = this.overlays,
4753
                n = overlays.length,
4754
                i;
4755
 
4756
            for (i = n - 1; i >= 0; i--) {
4757
                overlays[i].show();
4758
            }
4759
        },
4760
 
4761
        /**
4762
        * Hides all Overlays in the manager.
4763
        * @method hideAll
4764
        */
4765
        hideAll: function () {
4766
            var overlays = this.overlays,
4767
                n = overlays.length,
4768
                i;
4769
 
4770
            for (i = n - 1; i >= 0; i--) {
4771
                overlays[i].hide();
4772
            }
4773
        },
4774
 
4775
        /**
4776
        * Returns a string representation of the object.
4777
        * @method toString
4778
        * @return {String} The string representation of the OverlayManager
4779
        */
4780
        toString: function () {
4781
            return "OverlayManager";
4782
        }
4783
    };
4784
}());
4785
(function () {
4786
 
4787
    /**
4788
    * Tooltip is an implementation of Overlay that behaves like an OS tooltip,
4789
    * displaying when the user mouses over a particular element, and
4790
    * disappearing on mouse out.
4791
    * @namespace YAHOO.widget
4792
    * @class Tooltip
4793
    * @extends YAHOO.widget.Overlay
4794
    * @constructor
4795
    * @param {String} el The element ID representing the Tooltip <em>OR</em>
4796
    * @param {HTMLElement} el The element representing the Tooltip
4797
    * @param {Object} userConfig The configuration object literal containing
4798
    * the configuration that should be set for this Overlay. See configuration
4799
    * documentation for more details.
4800
    */
4801
    YAHOO.widget.Tooltip = function (el, userConfig) {
4802
        YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
4803
    };
4804
 
4805
    var Lang = YAHOO.lang,
4806
        Event = YAHOO.util.Event,
4807
        CustomEvent = YAHOO.util.CustomEvent,
4808
        Dom = YAHOO.util.Dom,
4809
        Tooltip = YAHOO.widget.Tooltip,
4810
        UA = YAHOO.env.ua,
4811
        bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
4812
 
4813
        m_oShadowTemplate,
4814
 
4815
        /**
4816
        * Constant representing the Tooltip's configuration properties
4817
        * @property DEFAULT_CONFIG
4818
        * @private
4819
        * @final
4820
        * @type Object
4821
        */
4822
        DEFAULT_CONFIG = {
4823
 
4824
            "PREVENT_OVERLAP": {
4825
                key: "preventoverlap",
4826
                value: true,
4827
                validator: Lang.isBoolean,
4828
                supercedes: ["x", "y", "xy"]
4829
            },
4830
 
4831
            "SHOW_DELAY": {
4832
                key: "showdelay",
4833
                value: 200,
4834
                validator: Lang.isNumber
4835
            },
4836
 
4837
            "AUTO_DISMISS_DELAY": {
4838
                key: "autodismissdelay",
4839
                value: 5000,
4840
                validator: Lang.isNumber
4841
            },
4842
 
4843
            "HIDE_DELAY": {
4844
                key: "hidedelay",
4845
                value: 250,
4846
                validator: Lang.isNumber
4847
            },
4848
 
4849
            "TEXT": {
4850
                key: "text",
4851
                suppressEvent: true
4852
            },
4853
 
4854
            "CONTAINER": {
4855
                key: "container"
4856
            },
4857
 
4858
            "DISABLED": {
4859
                key: "disabled",
4860
                value: false,
4861
                suppressEvent: true
4862
            },
4863
 
4864
            "XY_OFFSET": {
4865
                key: "xyoffset",
4866
                value: [0, 25],
4867
                suppressEvent: true
4868
            }
4869
        },
4870
 
4871
        /**
4872
        * Constant representing the name of the Tooltip's events
4873
        * @property EVENT_TYPES
4874
        * @private
4875
        * @final
4876
        * @type Object
4877
        */
4878
        EVENT_TYPES = {
4879
            "CONTEXT_MOUSE_OVER": "contextMouseOver",
4880
            "CONTEXT_MOUSE_OUT": "contextMouseOut",
4881
            "CONTEXT_TRIGGER": "contextTrigger"
4882
        };
4883
 
4884
    /**
4885
    * Constant representing the Tooltip CSS class
4886
    * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
4887
    * @static
4888
    * @final
4889
    * @type String
4890
    */
4891
    Tooltip.CSS_TOOLTIP = "yui-tt";
4892
 
4893
    function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
4894
 
4895
        var oConfig = this.cfg,
4896
            sCurrentWidth = oConfig.getProperty("width");
4897
 
4898
        if (sCurrentWidth == sForcedWidth) {
4899
            oConfig.setProperty("width", sOriginalWidth);
4900
        }
4901
    }
4902
 
4903
    /*
4904
        changeContent event handler that sets a Tooltip instance's "width"
4905
        configuration property to the value of its root HTML
4906
        elements's offsetWidth if a specific width has not been set.
4907
    */
4908
 
4909
    function setWidthToOffsetWidth(p_sType, p_aArgs) {
4910
 
4911
        if ("_originalWidth" in this) {
4912
            restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
4913
        }
4914
 
4915
        var oBody = document.body,
4916
            oConfig = this.cfg,
4917
            sOriginalWidth = oConfig.getProperty("width"),
4918
            sNewWidth,
4919
            oClone;
4920
 
4921
        if ((!sOriginalWidth || sOriginalWidth == "auto") &&
4922
            (oConfig.getProperty("container") != oBody ||
4923
            oConfig.getProperty("x") >= Dom.getViewportWidth() ||
4924
            oConfig.getProperty("y") >= Dom.getViewportHeight())) {
4925
 
4926
            oClone = this.element.cloneNode(true);
4927
            oClone.style.visibility = "hidden";
4928
            oClone.style.top = "0px";
4929
            oClone.style.left = "0px";
4930
 
4931
            oBody.appendChild(oClone);
4932
 
4933
            sNewWidth = (oClone.offsetWidth + "px");
4934
 
4935
            oBody.removeChild(oClone);
4936
            oClone = null;
4937
 
4938
            oConfig.setProperty("width", sNewWidth);
4939
            oConfig.refireEvent("xy");
4940
 
4941
            this._originalWidth = sOriginalWidth || "";
4942
            this._forcedWidth = sNewWidth;
4943
        }
4944
    }
4945
 
4946
    // "onDOMReady" that renders the ToolTip
4947
 
4948
    function onDOMReady(p_sType, p_aArgs, p_oObject) {
4949
        this.render(p_oObject);
4950
    }
4951
 
4952
    //  "init" event handler that automatically renders the Tooltip
4953
 
4954
    function onInit() {
4955
        Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
4956
    }
4957
 
4958
    YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
4959
 
4960
        /**
4961
        * The Tooltip initialization method. This method is automatically
4962
        * called by the constructor. A Tooltip is automatically rendered by
4963
        * the init method, and it also is set to be invisible by default,
4964
        * and constrained to viewport by default as well.
4965
        * @method init
4966
        * @param {String} el The element ID representing the Tooltip <em>OR</em>
4967
        * @param {HTMLElement} el The element representing the Tooltip
4968
        * @param {Object} userConfig The configuration object literal
4969
        * containing the configuration that should be set for this Tooltip.
4970
        * See configuration documentation for more details.
4971
        */
4972
        init: function (el, userConfig) {
4973
 
4974
 
4975
            Tooltip.superclass.init.call(this, el);
4976
 
4977
            this.beforeInitEvent.fire(Tooltip);
4978
 
4979
            Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
4980
 
4981
            if (userConfig) {
4982
                this.cfg.applyConfig(userConfig, true);
4983
            }
4984
 
4985
            this.cfg.queueProperty("visible", false);
4986
            this.cfg.queueProperty("constraintoviewport", true);
4987
 
4988
            this.setBody("");
4989
 
4990
            this.subscribe("changeContent", setWidthToOffsetWidth);
4991
            this.subscribe("init", onInit);
4992
            this.subscribe("render", this.onRender);
4993
 
4994
            this.initEvent.fire(Tooltip);
4995
        },
4996
 
4997
        /**
4998
        * Initializes the custom events for Tooltip
4999
        * @method initEvents
5000
        */
5001
        initEvents: function () {
5002
 
5003
            Tooltip.superclass.initEvents.call(this);
5004
            var SIGNATURE = CustomEvent.LIST;
5005
 
5006
            /**
5007
            * CustomEvent fired when user mouses over a context element. Returning false from
5008
            * a subscriber to this event will prevent the tooltip from being displayed for
5009
            * the current context element.
5010
            *
5011
            * @event contextMouseOverEvent
5012
            * @param {HTMLElement} context The context element which the user just moused over
5013
            * @param {DOMEvent} e The DOM event object, associated with the mouse over
5014
            */
5015
            this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
5016
            this.contextMouseOverEvent.signature = SIGNATURE;
5017
 
5018
            /**
5019
            * CustomEvent fired when the user mouses out of a context element.
5020
            *
5021
            * @event contextMouseOutEvent
5022
            * @param {HTMLElement} context The context element which the user just moused out of
5023
            * @param {DOMEvent} e The DOM event object, associated with the mouse out
5024
            */
5025
            this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
5026
            this.contextMouseOutEvent.signature = SIGNATURE;
5027
 
5028
            /**
5029
            * CustomEvent fired just before the tooltip is displayed for the current context.
5030
            * <p>
5031
            *  You can subscribe to this event if you need to set up the text for the
5032
            *  tooltip based on the context element for which it is about to be displayed.
5033
            * </p>
5034
            * <p>This event differs from the beforeShow event in following respects:</p>
5035
            * <ol>
5036
            *   <li>
5037
            *    When moving from one context element to another, if the tooltip is not
5038
            *    hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
5039
            *    be fired when the tooltip is displayed for the new context since it is already visible.
5040
            *    However the contextTrigger event is always fired before displaying the tooltip for
5041
            *    a new context.
5042
            *   </li>
5043
            *   <li>
5044
            *    The trigger event provides access to the context element, allowing you to
5045
            *    set the text of the tooltip based on context element for which the tooltip is
5046
            *    triggered.
5047
            *   </li>
5048
            * </ol>
5049
            * <p>
5050
            *  It is not possible to prevent the tooltip from being displayed
5051
            *  using this event. You can use the contextMouseOverEvent if you need to prevent
5052
            *  the tooltip from being displayed.
5053
            * </p>
5054
            * @event contextTriggerEvent
5055
            * @param {HTMLElement} context The context element for which the tooltip is triggered
5056
            */
5057
            this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
5058
            this.contextTriggerEvent.signature = SIGNATURE;
5059
        },
5060
 
5061
        /**
5062
        * Initializes the class's configurable properties which can be
5063
        * changed using the Overlay's Config object (cfg).
5064
        * @method initDefaultConfig
5065
        */
5066
        initDefaultConfig: function () {
5067
 
5068
            Tooltip.superclass.initDefaultConfig.call(this);
5069
 
5070
            /**
5071
            * Specifies whether the Tooltip should be kept from overlapping
5072
            * its context element.
5073
            * @config preventoverlap
5074
            * @type Boolean
5075
            * @default true
5076
            */
5077
            this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
5078
                value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
5079
                validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
5080
                supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
5081
            });
5082
 
5083
            /**
5084
            * The number of milliseconds to wait before showing a Tooltip
5085
            * on mouseover.
5086
            * @config showdelay
5087
            * @type Number
5088
            * @default 200
5089
            */
5090
            this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
5091
                handler: this.configShowDelay,
5092
                value: 200,
5093
                validator: DEFAULT_CONFIG.SHOW_DELAY.validator
5094
            });
5095
 
5096
            /**
5097
            * The number of milliseconds to wait before automatically
5098
            * dismissing a Tooltip after the mouse has been resting on the
5099
            * context element.
5100
            * @config autodismissdelay
5101
            * @type Number
5102
            * @default 5000
5103
            */
5104
            this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
5105
                handler: this.configAutoDismissDelay,
5106
                value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
5107
                validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
5108
            });
5109
 
5110
            /**
5111
            * The number of milliseconds to wait before hiding a Tooltip
5112
            * after mouseout.
5113
            * @config hidedelay
5114
            * @type Number
5115
            * @default 250
5116
            */
5117
            this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
5118
                handler: this.configHideDelay,
5119
                value: DEFAULT_CONFIG.HIDE_DELAY.value,
5120
                validator: DEFAULT_CONFIG.HIDE_DELAY.validator
5121
            });
5122
 
5123
            /**
5124
            * Specifies the Tooltip's text. The text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
5125
            * @config text
5126
            * @type HTML
5127
            * @default null
5128
            */
5129
            this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
5130
                handler: this.configText,
5131
                suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
5132
            });
5133
 
5134
            /**
5135
            * Specifies the container element that the Tooltip's markup
5136
            * should be rendered into.
5137
            * @config container
5138
            * @type HTMLElement/String
5139
            * @default document.body
5140
            */
5141
            this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
5142
                handler: this.configContainer,
5143
                value: document.body
5144
            });
5145
 
5146
            /**
5147
            * Specifies whether or not the tooltip is disabled. Disabled tooltips
5148
            * will not be displayed. If the tooltip is driven by the title attribute
5149
            * of the context element, the title attribute will still be removed for
5150
            * disabled tooltips, to prevent default tooltip behavior.
5151
            *
5152
            * @config disabled
5153
            * @type Boolean
5154
            * @default false
5155
            */
5156
            this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
5157
                handler: this.configContainer,
5158
                value: DEFAULT_CONFIG.DISABLED.value,
5159
                supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
5160
            });
5161
 
5162
            /**
5163
            * Specifies the XY offset from the mouse position, where the tooltip should be displayed, specified
5164
            * as a 2 element array (e.g. [10, 20]);
5165
            *
5166
            * @config xyoffset
5167
            * @type Array
5168
            * @default [0, 25]
5169
            */
5170
            this.cfg.addProperty(DEFAULT_CONFIG.XY_OFFSET.key, {
5171
                value: DEFAULT_CONFIG.XY_OFFSET.value.concat(),
5172
                supressEvent: DEFAULT_CONFIG.XY_OFFSET.suppressEvent
5173
            });
5174
 
5175
            /**
5176
            * Specifies the element or elements that the Tooltip should be
5177
            * anchored to on mouseover.
5178
            * @config context
5179
            * @type HTMLElement[]/String[]
5180
            * @default null
5181
            */
5182
 
5183
            /**
5184
            * String representing the width of the Tooltip.  <em>Please note:
5185
            * </em> As of version 2.3 if either no value or a value of "auto"
5186
            * is specified, and the Toolip's "container" configuration property
5187
            * is set to something other than <code>document.body</code> or
5188
            * its "context" element resides outside the immediately visible
5189
            * portion of the document, the width of the Tooltip will be
5190
            * calculated based on the offsetWidth of its root HTML and set just
5191
            * before it is made visible.  The original value will be
5192
            * restored when the Tooltip is hidden. This ensures the Tooltip is
5193
            * rendered at a usable width.  For more information see
5194
            * YUILibrary bug #1685496 and YUILibrary
5195
            * bug #1735423.
5196
            * @config width
5197
            * @type String
5198
            * @default null
5199
            */
5200
 
5201
        },
5202
 
5203
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
5204
 
5205
        /**
5206
        * The default event handler fired when the "text" property is changed.
5207
        * @method configText
5208
        * @param {String} type The CustomEvent type (usually the property name)
5209
        * @param {Object[]} args The CustomEvent arguments. For configuration
5210
        * handlers, args[0] will equal the newly applied value for the property.
5211
        * @param {Object} obj The scope object. For configuration handlers,
5212
        * this will usually equal the owner.
5213
        */
5214
        configText: function (type, args, obj) {
5215
            var text = args[0];
5216
            if (text) {
5217
                this.setBody(text);
5218
            }
5219
        },
5220
 
5221
        /**
5222
        * The default event handler fired when the "container" property
5223
        * is changed.
5224
        * @method configContainer
5225
        * @param {String} type The CustomEvent type (usually the property name)
5226
        * @param {Object[]} args The CustomEvent arguments. For
5227
        * configuration handlers, args[0] will equal the newly applied value
5228
        * for the property.
5229
        * @param {Object} obj The scope object. For configuration handlers,
5230
        * this will usually equal the owner.
5231
        */
5232
        configContainer: function (type, args, obj) {
5233
            var container = args[0];
5234
 
5235
            if (typeof container == 'string') {
5236
                this.cfg.setProperty("container", document.getElementById(container), true);
5237
            }
5238
        },
5239
 
5240
        /**
5241
        * @method _removeEventListeners
5242
        * @description Removes all of the DOM event handlers from the HTML
5243
        *  element(s) that trigger the display of the tooltip.
5244
        * @protected
5245
        */
5246
        _removeEventListeners: function () {
5247
 
5248
            var aElements = this._context,
5249
                nElements,
5250
                oElement,
5251
                i;
5252
 
5253
            if (aElements) {
5254
                nElements = aElements.length;
5255
                if (nElements > 0) {
5256
                    i = nElements - 1;
5257
                    do {
5258
                        oElement = aElements[i];
5259
                        Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
5260
                        Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
5261
                        Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
5262
                    }
5263
                    while (i--);
5264
                }
5265
            }
5266
        },
5267
 
5268
        /**
5269
        * The default event handler fired when the "context" property
5270
        * is changed.
5271
        * @method configContext
5272
        * @param {String} type The CustomEvent type (usually the property name)
5273
        * @param {Object[]} args The CustomEvent arguments. For configuration
5274
        * handlers, args[0] will equal the newly applied value for the property.
5275
        * @param {Object} obj The scope object. For configuration handlers,
5276
        * this will usually equal the owner.
5277
        */
5278
        configContext: function (type, args, obj) {
5279
 
5280
            var context = args[0],
5281
                aElements,
5282
                nElements,
5283
                oElement,
5284
                i;
5285
 
5286
            if (context) {
5287
 
5288
                // Normalize parameter into an array
5289
                if (! (context instanceof Array)) {
5290
                    if (typeof context == "string") {
5291
                        this.cfg.setProperty("context", [document.getElementById(context)], true);
5292
                    } else { // Assuming this is an element
5293
                        this.cfg.setProperty("context", [context], true);
5294
                    }
5295
                    context = this.cfg.getProperty("context");
5296
                }
5297
 
5298
                // Remove any existing mouseover/mouseout listeners
5299
                this._removeEventListeners();
5300
 
5301
                // Add mouseover/mouseout listeners to context elements
5302
                this._context = context;
5303
 
5304
                aElements = this._context;
5305
 
5306
                if (aElements) {
5307
                    nElements = aElements.length;
5308
                    if (nElements > 0) {
5309
                        i = nElements - 1;
5310
                        do {
5311
                            oElement = aElements[i];
5312
                            Event.on(oElement, "mouseover", this.onContextMouseOver, this);
5313
                            Event.on(oElement, "mousemove", this.onContextMouseMove, this);
5314
                            Event.on(oElement, "mouseout", this.onContextMouseOut, this);
5315
                        }
5316
                        while (i--);
5317
                    }
5318
                }
5319
            }
5320
        },
5321
 
5322
        // END BUILT-IN PROPERTY EVENT HANDLERS //
5323
 
5324
        // BEGIN BUILT-IN DOM EVENT HANDLERS //
5325
 
5326
        /**
5327
        * The default event handler fired when the user moves the mouse while
5328
        * over the context element.
5329
        * @method onContextMouseMove
5330
        * @param {DOMEvent} e The current DOM event
5331
        * @param {Object} obj The object argument
5332
        */
5333
        onContextMouseMove: function (e, obj) {
5334
            obj.pageX = Event.getPageX(e);
5335
            obj.pageY = Event.getPageY(e);
5336
        },
5337
 
5338
        /**
5339
        * The default event handler fired when the user mouses over the
5340
        * context element.
5341
        * @method onContextMouseOver
5342
        * @param {DOMEvent} e The current DOM event
5343
        * @param {Object} obj The object argument
5344
        */
5345
        onContextMouseOver: function (e, obj) {
5346
            var context = this;
5347
 
5348
            if (context.title) {
5349
                obj._tempTitle = context.title;
5350
                context.title = "";
5351
            }
5352
 
5353
            // Fire first, to honor disabled set in the listner
5354
            if (obj.fireEvent("contextMouseOver", context, e) !== false && !obj.cfg.getProperty("disabled")) {
5355
 
5356
                // Stop the tooltip from being hidden (set on last mouseout)
5357
                if (obj.hideProcId) {
5358
                    clearTimeout(obj.hideProcId);
5359
                    obj.hideProcId = null;
5360
                }
5361
 
5362
                Event.on(context, "mousemove", obj.onContextMouseMove, obj);
5363
 
5364
                /**
5365
                * The unique process ID associated with the thread responsible
5366
                * for showing the Tooltip.
5367
                * @type int
5368
                */
5369
                obj.showProcId = obj.doShow(e, context);
5370
            }
5371
        },
5372
 
5373
        /**
5374
        * The default event handler fired when the user mouses out of
5375
        * the context element.
5376
        * @method onContextMouseOut
5377
        * @param {DOMEvent} e The current DOM event
5378
        * @param {Object} obj The object argument
5379
        */
5380
        onContextMouseOut: function (e, obj) {
5381
            var el = this;
5382
 
5383
            if (obj._tempTitle) {
5384
                el.title = obj._tempTitle;
5385
                obj._tempTitle = null;
5386
            }
5387
 
5388
            if (obj.showProcId) {
5389
                clearTimeout(obj.showProcId);
5390
                obj.showProcId = null;
5391
            }
5392
 
5393
            if (obj.hideProcId) {
5394
                clearTimeout(obj.hideProcId);
5395
                obj.hideProcId = null;
5396
            }
5397
 
5398
            obj.fireEvent("contextMouseOut", el, e);
5399
 
5400
            obj.hideProcId = setTimeout(function () {
5401
                obj.hide();
5402
            }, obj.cfg.getProperty("hidedelay"));
5403
        },
5404
 
5405
        // END BUILT-IN DOM EVENT HANDLERS //
5406
 
5407
        /**
5408
        * Processes the showing of the Tooltip by setting the timeout delay
5409
        * and offset of the Tooltip.
5410
        * @method doShow
5411
        * @param {DOMEvent} e The current DOM event
5412
        * @param {HTMLElement} context The current context element
5413
        * @return {Number} The process ID of the timeout function associated
5414
        * with doShow
5415
        */
5416
        doShow: function (e, context) {
5417
 
5418
            var offset = this.cfg.getProperty("xyoffset"),
5419
                xOffset = offset[0],
5420
                yOffset = offset[1],
5421
                me = this;
5422
 
5423
            if (UA.opera && context.tagName &&
5424
                context.tagName.toUpperCase() == "A") {
5425
                yOffset += 12;
5426
            }
5427
 
5428
            return setTimeout(function () {
5429
 
5430
                var txt = me.cfg.getProperty("text");
5431
 
5432
                // title does not over-ride text
5433
                if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
5434
                    me.setBody(me._tempTitle);
5435
                } else {
5436
                    me.cfg.refireEvent("text");
5437
                }
5438
 
5439
                me.moveTo(me.pageX + xOffset, me.pageY + yOffset);
5440
 
5441
                if (me.cfg.getProperty("preventoverlap")) {
5442
                    me.preventOverlap(me.pageX, me.pageY);
5443
                }
5444
 
5445
                Event.removeListener(context, "mousemove", me.onContextMouseMove);
5446
 
5447
                me.contextTriggerEvent.fire(context);
5448
 
5449
                me.show();
5450
 
5451
                me.hideProcId = me.doHide();
5452
 
5453
            }, this.cfg.getProperty("showdelay"));
5454
        },
5455
 
5456
        /**
5457
        * Sets the timeout for the auto-dismiss delay, which by default is 5
5458
        * seconds, meaning that a tooltip will automatically dismiss itself
5459
        * after 5 seconds of being displayed.
5460
        * @method doHide
5461
        */
5462
        doHide: function () {
5463
 
5464
            var me = this;
5465
 
5466
 
5467
            return setTimeout(function () {
5468
 
5469
                me.hide();
5470
 
5471
            }, this.cfg.getProperty("autodismissdelay"));
5472
 
5473
        },
5474
 
5475
        /**
5476
        * Fired when the Tooltip is moved, this event handler is used to
5477
        * prevent the Tooltip from overlapping with its context element.
5478
        * @method preventOverlay
5479
        * @param {Number} pageX The x coordinate position of the mouse pointer
5480
        * @param {Number} pageY The y coordinate position of the mouse pointer
5481
        */
5482
        preventOverlap: function (pageX, pageY) {
5483
 
5484
            var height = this.element.offsetHeight,
5485
                mousePoint = new YAHOO.util.Point(pageX, pageY),
5486
                elementRegion = Dom.getRegion(this.element);
5487
 
5488
            elementRegion.top -= 5;
5489
            elementRegion.left -= 5;
5490
            elementRegion.right += 5;
5491
            elementRegion.bottom += 5;
5492
 
5493
 
5494
            if (elementRegion.contains(mousePoint)) {
5495
                this.cfg.setProperty("y", (pageY - height - 5));
5496
            }
5497
        },
5498
 
5499
 
5500
        /**
5501
        * @method onRender
5502
        * @description "render" event handler for the Tooltip.
5503
        * @param {String} p_sType String representing the name of the event
5504
        * that was fired.
5505
        * @param {Array} p_aArgs Array of arguments sent when the event
5506
        * was fired.
5507
        */
5508
        onRender: function (p_sType, p_aArgs) {
5509
 
5510
            function sizeShadow() {
5511
 
5512
                var oElement = this.element,
5513
                    oShadow = this.underlay;
5514
 
5515
                if (oShadow) {
5516
                    oShadow.style.width = (oElement.offsetWidth + 6) + "px";
5517
                    oShadow.style.height = (oElement.offsetHeight + 1) + "px";
5518
                }
5519
 
5520
            }
5521
 
5522
            function addShadowVisibleClass() {
5523
                Dom.addClass(this.underlay, "yui-tt-shadow-visible");
5524
 
5525
                if (UA.ie) {
5526
                    this.forceUnderlayRedraw();
5527
                }
5528
            }
5529
 
5530
            function removeShadowVisibleClass() {
5531
                Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
5532
            }
5533
 
5534
            function createShadow() {
5535
 
5536
                var oShadow = this.underlay,
5537
                    oElement,
5538
                    Module,
5539
                    nIE,
5540
                    me;
5541
 
5542
                if (!oShadow) {
5543
 
5544
                    oElement = this.element;
5545
                    Module = YAHOO.widget.Module;
5546
                    nIE = UA.ie;
5547
                    me = this;
5548
 
5549
                    if (!m_oShadowTemplate) {
5550
                        m_oShadowTemplate = document.createElement("div");
5551
                        m_oShadowTemplate.className = "yui-tt-shadow";
5552
                    }
5553
 
5554
                    oShadow = m_oShadowTemplate.cloneNode(false);
5555
 
5556
                    oElement.appendChild(oShadow);
5557
 
5558
                    this.underlay = oShadow;
5559
 
5560
                    // Backward compatibility, even though it's probably
5561
                    // intended to be "private", it isn't marked as such in the api docs
5562
                    this._shadow = this.underlay;
5563
 
5564
                    addShadowVisibleClass.call(this);
5565
 
5566
                    this.subscribe("beforeShow", addShadowVisibleClass);
5567
                    this.subscribe("hide", removeShadowVisibleClass);
5568
 
5569
                    if (bIEQuirks) {
5570
                        window.setTimeout(function () {
5571
                            sizeShadow.call(me);
5572
                        }, 0);
5573
 
5574
                        this.cfg.subscribeToConfigEvent("width", sizeShadow);
5575
                        this.cfg.subscribeToConfigEvent("height", sizeShadow);
5576
                        this.subscribe("changeContent", sizeShadow);
5577
 
5578
                        Module.textResizeEvent.subscribe(sizeShadow, this, true);
5579
                        this.subscribe("destroy", function () {
5580
                            Module.textResizeEvent.unsubscribe(sizeShadow, this);
5581
                        });
5582
                    }
5583
                }
5584
            }
5585
 
5586
            function onBeforeShow() {
5587
                createShadow.call(this);
5588
                this.unsubscribe("beforeShow", onBeforeShow);
5589
            }
5590
 
5591
            if (this.cfg.getProperty("visible")) {
5592
                createShadow.call(this);
5593
            } else {
5594
                this.subscribe("beforeShow", onBeforeShow);
5595
            }
5596
 
5597
        },
5598
 
5599
        /**
5600
         * Forces the underlay element to be repainted, through the application/removal
5601
         * of a yui-force-redraw class to the underlay element.
5602
         *
5603
         * @method forceUnderlayRedraw
5604
         */
5605
        forceUnderlayRedraw : function() {
5606
            var tt = this;
5607
            Dom.addClass(tt.underlay, "yui-force-redraw");
5608
            setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
5609
        },
5610
 
5611
        /**
5612
        * Removes the Tooltip element from the DOM and sets all child
5613
        * elements to null.
5614
        * @method destroy
5615
        */
5616
        destroy: function () {
5617
 
5618
            // Remove any existing mouseover/mouseout listeners
5619
            this._removeEventListeners();
5620
 
5621
            Tooltip.superclass.destroy.call(this);
5622
 
5623
        },
5624
 
5625
        /**
5626
        * Returns a string representation of the object.
5627
        * @method toString
5628
        * @return {String} The string representation of the Tooltip
5629
        */
5630
        toString: function () {
5631
            return "Tooltip " + this.id;
5632
        }
5633
 
5634
    });
5635
 
5636
}());
5637
(function () {
5638
 
5639
    /**
5640
    * Panel is an implementation of Overlay that behaves like an OS window,
5641
    * with a draggable header and an optional close icon at the top right.
5642
    * @namespace YAHOO.widget
5643
    * @class Panel
5644
    * @extends YAHOO.widget.Overlay
5645
    * @constructor
5646
    * @param {String} el The element ID representing the Panel <em>OR</em>
5647
    * @param {HTMLElement} el The element representing the Panel
5648
    * @param {Object} userConfig The configuration object literal containing
5649
    * the configuration that should be set for this Panel. See configuration
5650
    * documentation for more details.
5651
    */
5652
    YAHOO.widget.Panel = function (el, userConfig) {
5653
        YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
5654
    };
5655
 
5656
    var _currentModal = null;
5657
 
5658
    var Lang = YAHOO.lang,
5659
        Util = YAHOO.util,
5660
        Dom = Util.Dom,
5661
        Event = Util.Event,
5662
        CustomEvent = Util.CustomEvent,
5663
        KeyListener = YAHOO.util.KeyListener,
5664
        Config = Util.Config,
5665
        Overlay = YAHOO.widget.Overlay,
5666
        Panel = YAHOO.widget.Panel,
5667
        UA = YAHOO.env.ua,
5668
 
5669
        bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
5670
 
5671
        m_oMaskTemplate,
5672
        m_oUnderlayTemplate,
5673
        m_oCloseIconTemplate,
5674
 
5675
        /**
5676
        * Constant representing the name of the Panel's events
5677
        * @property EVENT_TYPES
5678
        * @private
5679
        * @final
5680
        * @type Object
5681
        */
5682
        EVENT_TYPES = {
5683
            "BEFORE_SHOW_MASK" : "beforeShowMask",
5684
            "BEFORE_HIDE_MASK" : "beforeHideMask",
5685
            "SHOW_MASK": "showMask",
5686
            "HIDE_MASK": "hideMask",
5687
            "DRAG": "drag"
5688
        },
5689
 
5690
        /**
5691
        * Constant representing the Panel's configuration properties
5692
        * @property DEFAULT_CONFIG
5693
        * @private
5694
        * @final
5695
        * @type Object
5696
        */
5697
        DEFAULT_CONFIG = {
5698
 
5699
            "CLOSE": {
5700
                key: "close",
5701
                value: true,
5702
                validator: Lang.isBoolean,
5703
                supercedes: ["visible"]
5704
            },
5705
 
5706
            "DRAGGABLE": {
5707
                key: "draggable",
5708
                value: (Util.DD ? true : false),
5709
                validator: Lang.isBoolean,
5710
                supercedes: ["visible"]
5711
            },
5712
 
5713
            "DRAG_ONLY" : {
5714
                key: "dragonly",
5715
                value: false,
5716
                validator: Lang.isBoolean,
5717
                supercedes: ["draggable"]
5718
            },
5719
 
5720
            "UNDERLAY": {
5721
                key: "underlay",
5722
                value: "shadow",
5723
                supercedes: ["visible"]
5724
            },
5725
 
5726
            "MODAL": {
5727
                key: "modal",
5728
                value: false,
5729
                validator: Lang.isBoolean,
5730
                supercedes: ["visible", "zindex"]
5731
            },
5732
 
5733
            "KEY_LISTENERS": {
5734
                key: "keylisteners",
5735
                suppressEvent: true,
5736
                supercedes: ["visible"]
5737
            },
5738
 
5739
            "STRINGS" : {
5740
                key: "strings",
5741
                supercedes: ["close"],
5742
                validator: Lang.isObject,
5743
                value: {
5744
                    close: "Close"
5745
                }
5746
            }
5747
        };
5748
 
5749
    /**
5750
    * Constant representing the default CSS class used for a Panel
5751
    * @property YAHOO.widget.Panel.CSS_PANEL
5752
    * @static
5753
    * @final
5754
    * @type String
5755
    */
5756
    Panel.CSS_PANEL = "yui-panel";
5757
 
5758
    /**
5759
    * Constant representing the default CSS class used for a Panel's
5760
    * wrapping container
5761
    * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
5762
    * @static
5763
    * @final
5764
    * @type String
5765
    */
5766
    Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
5767
 
5768
    /**
5769
     * Constant representing the default set of focusable elements
5770
     * on the pagewhich Modal Panels will prevent access to, when
5771
     * the modal mask is displayed
5772
     *
5773
     * @property YAHOO.widget.Panel.FOCUSABLE
5774
     * @static
5775
     * @type Array
5776
     */
5777
    Panel.FOCUSABLE = [
5778
        "a",
5779
        "button",
5780
        "select",
5781
        "textarea",
5782
        "input",
5783
        "iframe"
5784
    ];
5785
 
5786
    // Private CustomEvent listeners
5787
 
5788
    /*
5789
        "beforeRender" event handler that creates an empty header for a Panel
5790
        instance if its "draggable" configuration property is set to "true"
5791
        and no header has been created.
5792
    */
5793
 
5794
    function createHeader(p_sType, p_aArgs) {
5795
        if (!this.header && this.cfg.getProperty("draggable")) {
5796
            this.setHeader("&#160;");
5797
        }
5798
    }
5799
 
5800
    /*
5801
        "hide" event handler that sets a Panel instance's "width"
5802
        configuration property back to its original value before
5803
        "setWidthToOffsetWidth" was called.
5804
    */
5805
 
5806
    function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
5807
 
5808
        var sOriginalWidth = p_oObject[0],
5809
            sNewWidth = p_oObject[1],
5810
            oConfig = this.cfg,
5811
            sCurrentWidth = oConfig.getProperty("width");
5812
 
5813
        if (sCurrentWidth == sNewWidth) {
5814
            oConfig.setProperty("width", sOriginalWidth);
5815
        }
5816
 
5817
        this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
5818
    }
5819
 
5820
    /*
5821
        "beforeShow" event handler that sets a Panel instance's "width"
5822
        configuration property to the value of its root HTML
5823
        elements's offsetWidth
5824
    */
5825
 
5826
    function setWidthToOffsetWidth(p_sType, p_aArgs) {
5827
 
5828
        var oConfig,
5829
            sOriginalWidth,
5830
            sNewWidth;
5831
 
5832
        if (bIEQuirks) {
5833
 
5834
            oConfig = this.cfg;
5835
            sOriginalWidth = oConfig.getProperty("width");
5836
 
5837
            if (!sOriginalWidth || sOriginalWidth == "auto") {
5838
 
5839
                sNewWidth = (this.element.offsetWidth + "px");
5840
 
5841
                oConfig.setProperty("width", sNewWidth);
5842
 
5843
                this.subscribe("hide", restoreOriginalWidth,
5844
                    [(sOriginalWidth || ""), sNewWidth]);
5845
 
5846
            }
5847
        }
5848
    }
5849
 
5850
    YAHOO.extend(Panel, Overlay, {
5851
 
5852
        /**
5853
        * The Overlay initialization method, which is executed for Overlay and
5854
        * all of its subclasses. This method is automatically called by the
5855
        * constructor, and  sets up all DOM references for pre-existing markup,
5856
        * and creates required markup if it is not already present.
5857
        * @method init
5858
        * @param {String} el The element ID representing the Overlay <em>OR</em>
5859
        * @param {HTMLElement} el The element representing the Overlay
5860
        * @param {Object} userConfig The configuration object literal
5861
        * containing the configuration that should be set for this Overlay.
5862
        * See configuration documentation for more details.
5863
        */
5864
        init: function (el, userConfig) {
5865
            /*
5866
                 Note that we don't pass the user config in here yet because
5867
                 we only want it executed once, at the lowest subclass level
5868
            */
5869
 
5870
            Panel.superclass.init.call(this, el/*, userConfig*/);
5871
 
5872
            this.beforeInitEvent.fire(Panel);
5873
 
5874
            Dom.addClass(this.element, Panel.CSS_PANEL);
5875
 
5876
            this.buildWrapper();
5877
 
5878
            if (userConfig) {
5879
                this.cfg.applyConfig(userConfig, true);
5880
            }
5881
 
5882
            this.subscribe("showMask", this._addFocusHandlers);
5883
            this.subscribe("hideMask", this._removeFocusHandlers);
5884
            this.subscribe("beforeRender", createHeader);
5885
 
5886
            this.subscribe("render", function() {
5887
                this.setFirstLastFocusable();
5888
                this.subscribe("changeContent", this.setFirstLastFocusable);
5889
            });
5890
 
5891
            this.subscribe("show", this._focusOnShow);
5892
 
5893
            this.initEvent.fire(Panel);
5894
        },
5895
 
5896
        /**
5897
         * @method _onElementFocus
5898
         * @private
5899
         *
5900
         * "focus" event handler for a focuable element. Used to automatically
5901
         * blur the element when it receives focus to ensure that a Panel
5902
         * instance's modality is not compromised.
5903
         *
5904
         * @param {Event} e The DOM event object
5905
         */
5906
        _onElementFocus : function(e){
5907
 
5908
            if(_currentModal === this) {
5909
 
5910
                var target = Event.getTarget(e),
5911
                    doc = document.documentElement,
5912
                    insideDoc = (target !== doc && target !== window);
5913
 
5914
                // mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on
5915
                // the documentElement, when the document scrollbars are clicked on
5916
                if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
5917
                    try {
5918
                        this._focusFirstModal();
5919
                    } catch(err){
5920
                        // Just in case we fail to focus
5921
                        try {
5922
                            if (insideDoc && target !== document.body) {
5923
                                target.blur();
5924
                            }
5925
                        } catch(err2) { }
5926
                    }
5927
                }
5928
            }
5929
        },
5930
 
5931
        /**
5932
         * Focuses on the first element if present, otherwise falls back to the focus mechanisms used for
5933
         * modality. This method does not try/catch focus failures. The caller is responsible for catching exceptions,
5934
         * and taking remedial measures.
5935
         *
5936
         * @method _focusFirstModal
5937
         */
5938
        _focusFirstModal : function() {
5939
            var el = this.firstElement;
5940
            if (el) {
5941
                el.focus();
5942
            } else {
5943
                if (this._modalFocus) {
5944
                    this._modalFocus.focus();
5945
                } else {
5946
                    this.innerElement.focus();
5947
                }
5948
            }
5949
        },
5950
 
5951
        /**
5952
         *  @method _addFocusHandlers
5953
         *  @protected
5954
         *
5955
         *  "showMask" event handler that adds a "focus" event handler to all
5956
         *  focusable elements in the document to enforce a Panel instance's
5957
         *  modality from being compromised.
5958
         *
5959
         *  @param p_sType {String} Custom event type
5960
         *  @param p_aArgs {Array} Custom event arguments
5961
         */
5962
        _addFocusHandlers: function(p_sType, p_aArgs) {
5963
            if (!this.firstElement) {
5964
                if (UA.webkit || UA.opera) {
5965
                    if (!this._modalFocus) {
5966
                        this._createHiddenFocusElement();
5967
                    }
5968
                } else {
5969
                    this.innerElement.tabIndex = 0;
5970
                }
5971
            }
5972
            this._setTabLoop(this.firstElement, this.lastElement);
5973
            Event.onFocus(document.documentElement, this._onElementFocus, this, true);
5974
            _currentModal = this;
5975
        },
5976
 
5977
        /**
5978
         * Creates a hidden focusable element, used to focus on,
5979
         * to enforce modality for browsers in which focus cannot
5980
         * be applied to the container box.
5981
         *
5982
         * @method _createHiddenFocusElement
5983
         * @private
5984
         */
5985
        _createHiddenFocusElement : function() {
5986
            var e = document.createElement("button");
5987
            e.style.height = "1px";
5988
            e.style.width = "1px";
5989
            e.style.position = "absolute";
5990
            e.style.left = "-10000em";
5991
            e.style.opacity = 0;
5992
            e.tabIndex = -1;
5993
            this.innerElement.appendChild(e);
5994
            this._modalFocus = e;
5995
        },
5996
 
5997
        /**
5998
         *  @method _removeFocusHandlers
5999
         *  @protected
6000
         *
6001
         *  "hideMask" event handler that removes all "focus" event handlers added
6002
         *  by the "addFocusEventHandlers" method.
6003
         *
6004
         *  @param p_sType {String} Event type
6005
         *  @param p_aArgs {Array} Event Arguments
6006
         */
6007
        _removeFocusHandlers: function(p_sType, p_aArgs) {
6008
            Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
6009
 
6010
            if (_currentModal == this) {
6011
                _currentModal = null;
6012
            }
6013
        },
6014
 
6015
        /**
6016
         * Focus handler for the show event
6017
         *
6018
         * @method _focusOnShow
6019
         * @param {String} type Event Type
6020
         * @param {Array} args Event arguments
6021
         * @param {Object} obj Additional data
6022
         */
6023
        _focusOnShow : function(type, args, obj) {
6024
 
6025
            if (args && args[1]) {
6026
                Event.stopEvent(args[1]);
6027
            }
6028
 
6029
            if (!this.focusFirst(type, args, obj)) {
6030
                if (this.cfg.getProperty("modal")) {
6031
                    this._focusFirstModal();
6032
                }
6033
            }
6034
        },
6035
 
6036
        /**
6037
         * Sets focus to the first element in the Panel.
6038
         *
6039
         * @method focusFirst
6040
         * @return {Boolean} true, if successfully focused, false otherwise
6041
         */
6042
        focusFirst: function (type, args, obj) {
6043
            var el = this.firstElement, focused = false;
6044
 
6045
            if (args && args[1]) {
6046
                Event.stopEvent(args[1]);
6047
            }
6048
 
6049
            if (el) {
6050
                try {
6051
                    el.focus();
6052
                    focused = true;
6053
                } catch(err) {
6054
                    // Ignore
6055
                }
6056
            }
6057
 
6058
            return focused;
6059
        },
6060
 
6061
        /**
6062
         * Sets focus to the last element in the Panel.
6063
         *
6064
         * @method focusLast
6065
         * @return {Boolean} true, if successfully focused, false otherwise
6066
         */
6067
        focusLast: function (type, args, obj) {
6068
            var el = this.lastElement, focused = false;
6069
 
6070
            if (args && args[1]) {
6071
                Event.stopEvent(args[1]);
6072
            }
6073
 
6074
            if (el) {
6075
                try {
6076
                    el.focus();
6077
                    focused = true;
6078
                } catch(err) {
6079
                    // Ignore
6080
                }
6081
            }
6082
 
6083
            return focused;
6084
        },
6085
 
6086
        /**
6087
         * Protected internal method for setTabLoop, which can be used by
6088
         * subclasses to jump in and modify the arguments passed in if required.
6089
         *
6090
         * @method _setTabLoop
6091
         * @param {HTMLElement} firstElement
6092
         * @param {HTMLElement} lastElement
6093
         * @protected
6094
         *
6095
         */
6096
        _setTabLoop : function(firstElement, lastElement) {
6097
            this.setTabLoop(firstElement, lastElement);
6098
        },
6099
 
6100
        /**
6101
         * Sets up a tab, shift-tab loop between the first and last elements
6102
         * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
6103
         * instance properties, which are reset everytime this method is invoked.
6104
         *
6105
         * @method setTabLoop
6106
         * @param {HTMLElement} firstElement
6107
         * @param {HTMLElement} lastElement
6108
         *
6109
         */
6110
        setTabLoop : function(firstElement, lastElement) {
6111
 
6112
            var backTab = this.preventBackTab, tab = this.preventTabOut,
6113
                showEvent = this.showEvent, hideEvent = this.hideEvent;
6114
 
6115
            if (backTab) {
6116
                backTab.disable();
6117
                showEvent.unsubscribe(backTab.enable, backTab);
6118
                hideEvent.unsubscribe(backTab.disable, backTab);
6119
                backTab = this.preventBackTab = null;
6120
            }
6121
 
6122
            if (tab) {
6123
                tab.disable();
6124
                showEvent.unsubscribe(tab.enable, tab);
6125
                hideEvent.unsubscribe(tab.disable,tab);
6126
                tab = this.preventTabOut = null;
6127
            }
6128
 
6129
            if (firstElement) {
6130
                this.preventBackTab = new KeyListener(firstElement,
6131
                    {shift:true, keys:9},
6132
                    {fn:this.focusLast, scope:this, correctScope:true}
6133
                );
6134
                backTab = this.preventBackTab;
6135
 
6136
                showEvent.subscribe(backTab.enable, backTab, true);
6137
                hideEvent.subscribe(backTab.disable,backTab, true);
6138
            }
6139
 
6140
            if (lastElement) {
6141
                this.preventTabOut = new KeyListener(lastElement,
6142
                    {shift:false, keys:9},
6143
                    {fn:this.focusFirst, scope:this, correctScope:true}
6144
                );
6145
                tab = this.preventTabOut;
6146
 
6147
                showEvent.subscribe(tab.enable, tab, true);
6148
                hideEvent.subscribe(tab.disable,tab, true);
6149
            }
6150
        },
6151
 
6152
        /**
6153
         * Returns an array of the currently focusable items which reside within
6154
         * Panel. The set of focusable elements the method looks for are defined
6155
         * in the Panel.FOCUSABLE static property
6156
         *
6157
         * @method getFocusableElements
6158
         * @param {HTMLElement} root element to start from.
6159
         */
6160
        getFocusableElements : function(root) {
6161
 
6162
            root = root || this.innerElement;
6163
 
6164
            var focusable = {}, panel = this;
6165
            for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
6166
                focusable[Panel.FOCUSABLE[i]] = true;
6167
            }
6168
 
6169
            // Not looking by Tag, since we want elements in DOM order
6170
 
6171
            return Dom.getElementsBy(function(el) { return panel._testIfFocusable(el, focusable); }, null, root);
6172
        },
6173
 
6174
        /**
6175
         * This is the test method used by getFocusableElements, to determine which elements to
6176
         * include in the focusable elements list. Users may override this to customize behavior.
6177
         *
6178
         * @method _testIfFocusable
6179
         * @param {Object} el The element being tested
6180
         * @param {Object} focusable The hash of known focusable elements, created by an array-to-map operation on Panel.FOCUSABLE
6181
         * @protected
6182
         */
6183
        _testIfFocusable: function(el, focusable) {
6184
            if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
6185
                return true;
6186
            }
6187
            return false;
6188
        },
6189
 
6190
        /**
6191
         * Sets the firstElement and lastElement instance properties
6192
         * to the first and last focusable elements in the Panel.
6193
         *
6194
         * @method setFirstLastFocusable
6195
         */
6196
        setFirstLastFocusable : function() {
6197
 
6198
            this.firstElement = null;
6199
            this.lastElement = null;
6200
 
6201
            var elements = this.getFocusableElements();
6202
            this.focusableElements = elements;
6203
 
6204
            if (elements.length > 0) {
6205
                this.firstElement = elements[0];
6206
                this.lastElement = elements[elements.length - 1];
6207
            }
6208
 
6209
            if (this.cfg.getProperty("modal")) {
6210
                this._setTabLoop(this.firstElement, this.lastElement);
6211
            }
6212
        },
6213
 
6214
        /**
6215
         * Initializes the custom events for Module which are fired
6216
         * automatically at appropriate times by the Module class.
6217
         */
6218
        initEvents: function () {
6219
            Panel.superclass.initEvents.call(this);
6220
 
6221
            var SIGNATURE = CustomEvent.LIST;
6222
 
6223
            /**
6224
            * CustomEvent fired after the modality mask is shown
6225
            * @event showMaskEvent
6226
            */
6227
            this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
6228
            this.showMaskEvent.signature = SIGNATURE;
6229
 
6230
            /**
6231
            * CustomEvent fired before the modality mask is shown. Subscribers can return false to prevent the
6232
            * mask from being shown
6233
            * @event beforeShowMaskEvent
6234
            */
6235
            this.beforeShowMaskEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW_MASK);
6236
            this.beforeShowMaskEvent.signature = SIGNATURE;
6237
 
6238
            /**
6239
            * CustomEvent fired after the modality mask is hidden
6240
            * @event hideMaskEvent
6241
            */
6242
            this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
6243
            this.hideMaskEvent.signature = SIGNATURE;
6244
 
6245
            /**
6246
            * CustomEvent fired before the modality mask is hidden. Subscribers can return false to prevent the
6247
            * mask from being hidden
6248
            * @event beforeHideMaskEvent
6249
            */
6250
            this.beforeHideMaskEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE_MASK);
6251
            this.beforeHideMaskEvent.signature = SIGNATURE;
6252
 
6253
            /**
6254
            * CustomEvent when the Panel is dragged
6255
            * @event dragEvent
6256
            */
6257
            this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
6258
            this.dragEvent.signature = SIGNATURE;
6259
        },
6260
 
6261
        /**
6262
         * Initializes the class's configurable properties which can be changed
6263
         * using the Panel's Config object (cfg).
6264
         * @method initDefaultConfig
6265
         */
6266
        initDefaultConfig: function () {
6267
            Panel.superclass.initDefaultConfig.call(this);
6268
 
6269
            // Add panel config properties //
6270
 
6271
            /**
6272
            * True if the Panel should display a "close" button
6273
            * @config close
6274
            * @type Boolean
6275
            * @default true
6276
            */
6277
            this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
6278
                handler: this.configClose,
6279
                value: DEFAULT_CONFIG.CLOSE.value,
6280
                validator: DEFAULT_CONFIG.CLOSE.validator,
6281
                supercedes: DEFAULT_CONFIG.CLOSE.supercedes
6282
            });
6283
 
6284
            /**
6285
            * Boolean specifying if the Panel should be draggable.  The default
6286
            * value is "true" if the Drag and Drop utility is included,
6287
            * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
6288
            * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
6289
            * (Quirks Mode) where Panels that either don't have a value set for
6290
            * their "width" configuration property, or their "width"
6291
            * configuration property is set to "auto" will only be draggable by
6292
            * placing the mouse on the text of the Panel's header element.
6293
            * To fix this bug, draggable Panels missing a value for their
6294
            * "width" configuration property, or whose "width" configuration
6295
            * property is set to "auto" will have it set to the value of
6296
            * their root HTML element's offsetWidth before they are made
6297
            * visible.  The calculated width is then removed when the Panel is
6298
            * hidden. <em>This fix is only applied to draggable Panels in IE 6
6299
            * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
6300
            * more information on this issue see:
6301
            * YUILibrary bugs #1726972 and #1589210.
6302
            * @config draggable
6303
            * @type Boolean
6304
            * @default true
6305
            */
6306
            this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
6307
                handler: this.configDraggable,
6308
                value: (Util.DD) ? true : false,
6309
                validator: DEFAULT_CONFIG.DRAGGABLE.validator,
6310
                supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
6311
            });
6312
 
6313
            /**
6314
            * Boolean specifying if the draggable Panel should be drag only, not interacting with drop
6315
            * targets on the page.
6316
            * <p>
6317
            * When set to true, draggable Panels will not check to see if they are over drop targets,
6318
            * or fire the DragDrop events required to support drop target interaction (onDragEnter,
6319
            * onDragOver, onDragOut, onDragDrop etc.).
6320
            * If the Panel is not designed to be dropped on any target elements on the page, then this
6321
            * flag can be set to true to improve performance.
6322
            * </p>
6323
            * <p>
6324
            * When set to false, all drop target related events will be fired.
6325
            * </p>
6326
            * <p>
6327
            * The property is set to false by default to maintain backwards compatibility but should be
6328
            * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
6329
            *
6330
            * @config dragOnly
6331
            * @type Boolean
6332
            * @default false
6333
            */
6334
            this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, {
6335
                value: DEFAULT_CONFIG.DRAG_ONLY.value,
6336
                validator: DEFAULT_CONFIG.DRAG_ONLY.validator,
6337
                supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes
6338
            });
6339
 
6340
            /**
6341
            * Sets the type of underlay to display for the Panel. Valid values
6342
            * are "shadow," "matte," and "none".  <strong>PLEASE NOTE:</strong>
6343
            * The creation of the underlay element is deferred until the Panel
6344
            * is initially made visible.  For Gecko-based browsers on Mac
6345
            * OS X the underlay elment is always created as it is used as a
6346
            * shim to prevent Aqua scrollbars below a Panel instance from poking
6347
            * through it (See YUILibrary bug #1723530).
6348
            * @config underlay
6349
            * @type String
6350
            * @default shadow
6351
            */
6352
            this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
6353
                handler: this.configUnderlay,
6354
                value: DEFAULT_CONFIG.UNDERLAY.value,
6355
                supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
6356
            });
6357
 
6358
            /**
6359
            * True if the Panel should be displayed in a modal fashion,
6360
            * automatically creating a transparent mask over the document that
6361
            * will not be removed until the Panel is dismissed.
6362
            * @config modal
6363
            * @type Boolean
6364
            * @default false
6365
            */
6366
            this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
6367
                handler: this.configModal,
6368
                value: DEFAULT_CONFIG.MODAL.value,
6369
                validator: DEFAULT_CONFIG.MODAL.validator,
6370
                supercedes: DEFAULT_CONFIG.MODAL.supercedes
6371
            });
6372
 
6373
            /**
6374
            * A KeyListener (or array of KeyListeners) that will be enabled
6375
            * when the Panel is shown, and disabled when the Panel is hidden.
6376
            * @config keylisteners
6377
            * @type YAHOO.util.KeyListener[]
6378
            * @default null
6379
            */
6380
            this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
6381
                handler: this.configKeyListeners,
6382
                suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
6383
                supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
6384
            });
6385
 
6386
            /**
6387
            * UI Strings used by the Panel. The strings are inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
6388
            *
6389
            * @config strings
6390
            * @type Object
6391
            * @default An object literal with the properties shown below:
6392
            *     <dl>
6393
            *         <dt>close</dt><dd><em>HTML</em> : The markup to use as the label for the close icon. Defaults to "Close".</dd>
6394
            *     </dl>
6395
            */
6396
            this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, {
6397
                value:DEFAULT_CONFIG.STRINGS.value,
6398
                handler:this.configStrings,
6399
                validator:DEFAULT_CONFIG.STRINGS.validator,
6400
                supercedes:DEFAULT_CONFIG.STRINGS.supercedes
6401
            });
6402
        },
6403
 
6404
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
6405
 
6406
        /**
6407
        * The default event handler fired when the "close" property is changed.
6408
        * The method controls the appending or hiding of the close icon at the
6409
        * top right of the Panel.
6410
        * @method configClose
6411
        * @param {String} type The CustomEvent type (usually the property name)
6412
        * @param {Object[]} args The CustomEvent arguments. For configuration
6413
        * handlers, args[0] will equal the newly applied value for the property.
6414
        * @param {Object} obj The scope object. For configuration handlers,
6415
        * this will usually equal the owner.
6416
        */
6417
        configClose: function (type, args, obj) {
6418
 
6419
            var val = args[0],
6420
                oClose = this.close,
6421
                strings = this.cfg.getProperty("strings"),
6422
                fc;
6423
 
6424
            if (val) {
6425
                if (!oClose) {
6426
 
6427
                    if (!m_oCloseIconTemplate) {
6428
                        m_oCloseIconTemplate = document.createElement("a");
6429
                        m_oCloseIconTemplate.className = "container-close";
6430
                        m_oCloseIconTemplate.href = "#";
6431
                    }
6432
 
6433
                    oClose = m_oCloseIconTemplate.cloneNode(true);
6434
 
6435
                    fc = this.innerElement.firstChild;
6436
 
6437
                    if (fc) {
6438
                        this.innerElement.insertBefore(oClose, fc);
6439
                    } else {
6440
                        this.innerElement.appendChild(oClose);
6441
                    }
6442
 
6443
                    oClose.innerHTML = (strings && strings.close) ? strings.close : "&#160;";
6444
 
6445
                    Event.on(oClose, "click", this._doClose, this, true);
6446
 
6447
                    this.close = oClose;
6448
 
6449
                } else {
6450
                    oClose.style.display = "block";
6451
                }
6452
 
6453
            } else {
6454
                if (oClose) {
6455
                    oClose.style.display = "none";
6456
                }
6457
            }
6458
 
6459
        },
6460
 
6461
        /**
6462
         * Event handler for the close icon
6463
         *
6464
         * @method _doClose
6465
         * @protected
6466
         *
6467
         * @param {DOMEvent} e
6468
         */
6469
        _doClose : function (e) {
6470
            Event.preventDefault(e);
6471
            this.hide();
6472
        },
6473
 
6474
        /**
6475
        * The default event handler fired when the "draggable" property
6476
        * is changed.
6477
        * @method configDraggable
6478
        * @param {String} type The CustomEvent type (usually the property name)
6479
        * @param {Object[]} args The CustomEvent arguments. For configuration
6480
        * handlers, args[0] will equal the newly applied value for the property.
6481
        * @param {Object} obj The scope object. For configuration handlers,
6482
        * this will usually equal the owner.
6483
        */
6484
        configDraggable: function (type, args, obj) {
6485
            var val = args[0];
6486
 
6487
            if (val) {
6488
                if (!Util.DD) {
6489
                    this.cfg.setProperty("draggable", false);
6490
                    return;
6491
                }
6492
 
6493
                if (this.header) {
6494
                    Dom.setStyle(this.header, "cursor", "move");
6495
                    this.registerDragDrop();
6496
                }
6497
 
6498
                this.subscribe("beforeShow", setWidthToOffsetWidth);
6499
 
6500
            } else {
6501
 
6502
                if (this.dd) {
6503
                    this.dd.unreg();
6504
                }
6505
 
6506
                if (this.header) {
6507
                    Dom.setStyle(this.header,"cursor","auto");
6508
                }
6509
 
6510
                this.unsubscribe("beforeShow", setWidthToOffsetWidth);
6511
            }
6512
        },
6513
 
6514
        /**
6515
        * The default event handler fired when the "underlay" property
6516
        * is changed.
6517
        * @method configUnderlay
6518
        * @param {String} type The CustomEvent type (usually the property name)
6519
        * @param {Object[]} args The CustomEvent arguments. For configuration
6520
        * handlers, args[0] will equal the newly applied value for the property.
6521
        * @param {Object} obj The scope object. For configuration handlers,
6522
        * this will usually equal the owner.
6523
        */
6524
        configUnderlay: function (type, args, obj) {
6525
 
6526
            var bMacGecko = (this.platform == "mac" && UA.gecko),
6527
                sUnderlay = args[0].toLowerCase(),
6528
                oUnderlay = this.underlay,
6529
                oElement = this.element;
6530
 
6531
            function createUnderlay() {
6532
                var bNew = false;
6533
                if (!oUnderlay) { // create if not already in DOM
6534
 
6535
                    if (!m_oUnderlayTemplate) {
6536
                        m_oUnderlayTemplate = document.createElement("div");
6537
                        m_oUnderlayTemplate.className = "underlay";
6538
                    }
6539
 
6540
                    oUnderlay = m_oUnderlayTemplate.cloneNode(false);
6541
                    this.element.appendChild(oUnderlay);
6542
 
6543
                    this.underlay = oUnderlay;
6544
 
6545
                    if (bIEQuirks) {
6546
                        this.sizeUnderlay();
6547
                        this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
6548
                        this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
6549
 
6550
                        this.changeContentEvent.subscribe(this.sizeUnderlay);
6551
                        YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
6552
                    }
6553
 
6554
                    if (UA.webkit && UA.webkit < 420) {
6555
                        this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
6556
                    }
6557
 
6558
                    bNew = true;
6559
                }
6560
            }
6561
 
6562
            function onBeforeShow() {
6563
                var bNew = createUnderlay.call(this);
6564
                if (!bNew && bIEQuirks) {
6565
                    this.sizeUnderlay();
6566
                }
6567
                this._underlayDeferred = false;
6568
                this.beforeShowEvent.unsubscribe(onBeforeShow);
6569
            }
6570
 
6571
            function destroyUnderlay() {
6572
                if (this._underlayDeferred) {
6573
                    this.beforeShowEvent.unsubscribe(onBeforeShow);
6574
                    this._underlayDeferred = false;
6575
                }
6576
 
6577
                if (oUnderlay) {
6578
                    this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
6579
                    this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
6580
                    this.changeContentEvent.unsubscribe(this.sizeUnderlay);
6581
                    this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
6582
                    YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
6583
 
6584
                    this.element.removeChild(oUnderlay);
6585
 
6586
                    this.underlay = null;
6587
                }
6588
            }
6589
 
6590
            switch (sUnderlay) {
6591
                case "shadow":
6592
                    Dom.removeClass(oElement, "matte");
6593
                    Dom.addClass(oElement, "shadow");
6594
                    break;
6595
                case "matte":
6596
                    if (!bMacGecko) {
6597
                        destroyUnderlay.call(this);
6598
                    }
6599
                    Dom.removeClass(oElement, "shadow");
6600
                    Dom.addClass(oElement, "matte");
6601
                    break;
6602
                default:
6603
                    if (!bMacGecko) {
6604
                        destroyUnderlay.call(this);
6605
                    }
6606
                    Dom.removeClass(oElement, "shadow");
6607
                    Dom.removeClass(oElement, "matte");
6608
                    break;
6609
            }
6610
 
6611
            if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
6612
                if (this.cfg.getProperty("visible")) {
6613
                    var bNew = createUnderlay.call(this);
6614
                    if (!bNew && bIEQuirks) {
6615
                        this.sizeUnderlay();
6616
                    }
6617
                } else {
6618
                    if (!this._underlayDeferred) {
6619
                        this.beforeShowEvent.subscribe(onBeforeShow);
6620
                        this._underlayDeferred = true;
6621
                    }
6622
                }
6623
            }
6624
        },
6625
 
6626
        /**
6627
        * The default event handler fired when the "modal" property is
6628
        * changed. This handler subscribes or unsubscribes to the show and hide
6629
        * events to handle the display or hide of the modality mask.
6630
        * @method configModal
6631
        * @param {String} type The CustomEvent type (usually the property name)
6632
        * @param {Object[]} args The CustomEvent arguments. For configuration
6633
        * handlers, args[0] will equal the newly applied value for the property.
6634
        * @param {Object} obj The scope object. For configuration handlers,
6635
        * this will usually equal the owner.
6636
        */
6637
        configModal: function (type, args, obj) {
6638
 
6639
            var modal = args[0];
6640
            if (modal) {
6641
                if (!this._hasModalityEventListeners) {
6642
 
6643
                    this.subscribe("beforeShow", this.buildMask);
6644
                    this.subscribe("beforeShow", this.bringToTop);
6645
                    this.subscribe("beforeShow", this.showMask);
6646
                    this.subscribe("hide", this.hideMask);
6647
 
6648
                    Overlay.windowResizeEvent.subscribe(this.sizeMask,
6649
                        this, true);
6650
 
6651
                    this._hasModalityEventListeners = true;
6652
                }
6653
            } else {
6654
                if (this._hasModalityEventListeners) {
6655
 
6656
                    if (this.cfg.getProperty("visible")) {
6657
                        this.hideMask();
6658
                        this.removeMask();
6659
                    }
6660
 
6661
                    this.unsubscribe("beforeShow", this.buildMask);
6662
                    this.unsubscribe("beforeShow", this.bringToTop);
6663
                    this.unsubscribe("beforeShow", this.showMask);
6664
                    this.unsubscribe("hide", this.hideMask);
6665
 
6666
                    Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
6667
 
6668
                    this._hasModalityEventListeners = false;
6669
                }
6670
            }
6671
        },
6672
 
6673
        /**
6674
        * Removes the modality mask.
6675
        * @method removeMask
6676
        */
6677
        removeMask: function () {
6678
 
6679
            var oMask = this.mask,
6680
                oParentNode;
6681
 
6682
            if (oMask) {
6683
                /*
6684
                    Hide the mask before destroying it to ensure that DOM
6685
                    event handlers on focusable elements get removed.
6686
                */
6687
                this.hideMask();
6688
 
6689
                oParentNode = oMask.parentNode;
6690
                if (oParentNode) {
6691
                    oParentNode.removeChild(oMask);
6692
                }
6693
 
6694
                this.mask = null;
6695
            }
6696
        },
6697
 
6698
        /**
6699
        * The default event handler fired when the "keylisteners" property
6700
        * is changed.
6701
        * @method configKeyListeners
6702
        * @param {String} type The CustomEvent type (usually the property name)
6703
        * @param {Object[]} args The CustomEvent arguments. For configuration
6704
        * handlers, args[0] will equal the newly applied value for the property.
6705
        * @param {Object} obj The scope object. For configuration handlers,
6706
        * this will usually equal the owner.
6707
        */
6708
        configKeyListeners: function (type, args, obj) {
6709
 
6710
            var listeners = args[0],
6711
                listener,
6712
                nListeners,
6713
                i;
6714
 
6715
            if (listeners) {
6716
 
6717
                if (listeners instanceof Array) {
6718
 
6719
                    nListeners = listeners.length;
6720
 
6721
                    for (i = 0; i < nListeners; i++) {
6722
 
6723
                        listener = listeners[i];
6724
 
6725
                        if (!Config.alreadySubscribed(this.showEvent,
6726
                            listener.enable, listener)) {
6727
 
6728
                            this.showEvent.subscribe(listener.enable,
6729
                                listener, true);
6730
 
6731
                        }
6732
 
6733
                        if (!Config.alreadySubscribed(this.hideEvent,
6734
                            listener.disable, listener)) {
6735
 
6736
                            this.hideEvent.subscribe(listener.disable,
6737
                                listener, true);
6738
 
6739
                            this.destroyEvent.subscribe(listener.disable,
6740
                                listener, true);
6741
                        }
6742
                    }
6743
 
6744
                } else {
6745
 
6746
                    if (!Config.alreadySubscribed(this.showEvent,
6747
                        listeners.enable, listeners)) {
6748
 
6749
                        this.showEvent.subscribe(listeners.enable,
6750
                            listeners, true);
6751
                    }
6752
 
6753
                    if (!Config.alreadySubscribed(this.hideEvent,
6754
                        listeners.disable, listeners)) {
6755
 
6756
                        this.hideEvent.subscribe(listeners.disable,
6757
                            listeners, true);
6758
 
6759
                        this.destroyEvent.subscribe(listeners.disable,
6760
                            listeners, true);
6761
 
6762
                    }
6763
 
6764
                }
6765
 
6766
            }
6767
 
6768
        },
6769
 
6770
        /**
6771
        * The default handler for the "strings" property
6772
        * @method configStrings
6773
        */
6774
        configStrings : function(type, args, obj) {
6775
            var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
6776
            this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
6777
        },
6778
 
6779
        /**
6780
        * The default event handler fired when the "height" property is changed.
6781
        * @method configHeight
6782
        * @param {String} type The CustomEvent type (usually the property name)
6783
        * @param {Object[]} args The CustomEvent arguments. For configuration
6784
        * handlers, args[0] will equal the newly applied value for the property.
6785
        * @param {Object} obj The scope object. For configuration handlers,
6786
        * this will usually equal the owner.
6787
        */
6788
        configHeight: function (type, args, obj) {
6789
            var height = args[0],
6790
                el = this.innerElement;
6791
 
6792
            Dom.setStyle(el, "height", height);
6793
            this.cfg.refireEvent("iframe");
6794
        },
6795
 
6796
        /**
6797
         * The default custom event handler executed when the Panel's height is changed,
6798
         * if the autofillheight property has been set.
6799
         *
6800
         * @method _autoFillOnHeightChange
6801
         * @protected
6802
         * @param {String} type The event type
6803
         * @param {Array} args The array of arguments passed to event subscribers
6804
         * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
6805
         * out the containers height
6806
         */
6807
        _autoFillOnHeightChange : function(type, args, el) {
6808
            Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
6809
            if (bIEQuirks) {
6810
                var panel = this;
6811
                setTimeout(function() {
6812
                    panel.sizeUnderlay();
6813
                },0);
6814
            }
6815
        },
6816
 
6817
        /**
6818
        * The default event handler fired when the "width" property is changed.
6819
        * @method configWidth
6820
        * @param {String} type The CustomEvent type (usually the property name)
6821
        * @param {Object[]} args The CustomEvent arguments. For configuration
6822
        * handlers, args[0] will equal the newly applied value for the property.
6823
        * @param {Object} obj The scope object. For configuration handlers,
6824
        * this will usually equal the owner.
6825
        */
6826
        configWidth: function (type, args, obj) {
6827
 
6828
            var width = args[0],
6829
                el = this.innerElement;
6830
 
6831
            Dom.setStyle(el, "width", width);
6832
            this.cfg.refireEvent("iframe");
6833
 
6834
        },
6835
 
6836
        /**
6837
        * The default event handler fired when the "zIndex" property is changed.
6838
        * @method configzIndex
6839
        * @param {String} type The CustomEvent type (usually the property name)
6840
        * @param {Object[]} args The CustomEvent arguments. For configuration
6841
        * handlers, args[0] will equal the newly applied value for the property.
6842
        * @param {Object} obj The scope object. For configuration handlers,
6843
        * this will usually equal the owner.
6844
        */
6845
        configzIndex: function (type, args, obj) {
6846
            Panel.superclass.configzIndex.call(this, type, args, obj);
6847
 
6848
            if (this.mask || this.cfg.getProperty("modal") === true) {
6849
                var panelZ = Dom.getStyle(this.element, "zIndex");
6850
                if (!panelZ || isNaN(panelZ)) {
6851
                    panelZ = 0;
6852
                }
6853
 
6854
                if (panelZ === 0) {
6855
                    // Recursive call to configzindex (which should be stopped
6856
                    // from going further because panelZ should no longer === 0)
6857
                    this.cfg.setProperty("zIndex", 1);
6858
                } else {
6859
                    this.stackMask();
6860
                }
6861
            }
6862
        },
6863
 
6864
        // END BUILT-IN PROPERTY EVENT HANDLERS //
6865
        /**
6866
        * Builds the wrapping container around the Panel that is used for
6867
        * positioning the shadow and matte underlays. The container element is
6868
        * assigned to a  local instance variable called container, and the
6869
        * element is reinserted inside of it.
6870
        * @method buildWrapper
6871
        */
6872
        buildWrapper: function () {
6873
 
6874
            var elementParent = this.element.parentNode,
6875
                originalElement = this.element,
6876
                wrapper = document.createElement("div");
6877
 
6878
            wrapper.className = Panel.CSS_PANEL_CONTAINER;
6879
            wrapper.id = originalElement.id + "_c";
6880
 
6881
            if (elementParent) {
6882
                elementParent.insertBefore(wrapper, originalElement);
6883
            }
6884
 
6885
            wrapper.appendChild(originalElement);
6886
 
6887
            this.element = wrapper;
6888
            this.innerElement = originalElement;
6889
 
6890
            Dom.setStyle(this.innerElement, "visibility", "inherit");
6891
        },
6892
 
6893
        /**
6894
        * Adjusts the size of the shadow based on the size of the element.
6895
        * @method sizeUnderlay
6896
        */
6897
        sizeUnderlay: function () {
6898
            var oUnderlay = this.underlay,
6899
                oElement;
6900
 
6901
            if (oUnderlay) {
6902
                oElement = this.element;
6903
                oUnderlay.style.width = oElement.offsetWidth + "px";
6904
                oUnderlay.style.height = oElement.offsetHeight + "px";
6905
            }
6906
        },
6907
 
6908
        /**
6909
        * Registers the Panel's header for drag & drop capability.
6910
        * @method registerDragDrop
6911
        */
6912
        registerDragDrop: function () {
6913
 
6914
            var me = this;
6915
 
6916
            if (this.header) {
6917
 
6918
                if (!Util.DD) {
6919
                    return;
6920
                }
6921
 
6922
                var bDragOnly = (this.cfg.getProperty("dragonly") === true);
6923
 
6924
                /**
6925
                 * The YAHOO.util.DD instance, used to implement the draggable header for the panel if draggable is enabled
6926
                 *
6927
                 * @property dd
6928
                 * @type YAHOO.util.DD
6929
                 */
6930
                this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
6931
 
6932
                if (!this.header.id) {
6933
                    this.header.id = this.id + "_h";
6934
                }
6935
 
6936
                this.dd.startDrag = function () {
6937
 
6938
                    var offsetHeight,
6939
                        offsetWidth,
6940
                        viewPortWidth,
6941
                        viewPortHeight,
6942
                        scrollX,
6943
                        scrollY;
6944
 
6945
                    if (YAHOO.env.ua.ie == 6) {
6946
                        Dom.addClass(me.element,"drag");
6947
                    }
6948
 
6949
                    if (me.cfg.getProperty("constraintoviewport")) {
6950
 
6951
                        var nViewportOffset = Overlay.VIEWPORT_OFFSET;
6952
 
6953
                        offsetHeight = me.element.offsetHeight;
6954
                        offsetWidth = me.element.offsetWidth;
6955
 
6956
                        viewPortWidth = Dom.getViewportWidth();
6957
                        viewPortHeight = Dom.getViewportHeight();
6958
 
6959
                        scrollX = Dom.getDocumentScrollLeft();
6960
                        scrollY = Dom.getDocumentScrollTop();
6961
 
6962
                        if (offsetHeight + nViewportOffset < viewPortHeight) {
6963
                            this.minY = scrollY + nViewportOffset;
6964
                            this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
6965
                        } else {
6966
                            this.minY = scrollY + nViewportOffset;
6967
                            this.maxY = scrollY + nViewportOffset;
6968
                        }
6969
 
6970
                        if (offsetWidth + nViewportOffset < viewPortWidth) {
6971
                            this.minX = scrollX + nViewportOffset;
6972
                            this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
6973
                        } else {
6974
                            this.minX = scrollX + nViewportOffset;
6975
                            this.maxX = scrollX + nViewportOffset;
6976
                        }
6977
 
6978
                        this.constrainX = true;
6979
                        this.constrainY = true;
6980
                    } else {
6981
                        this.constrainX = false;
6982
                        this.constrainY = false;
6983
                    }
6984
 
6985
                    me.dragEvent.fire("startDrag", arguments);
6986
                };
6987
 
6988
                this.dd.onDrag = function () {
6989
                    me.syncPosition();
6990
                    me.cfg.refireEvent("iframe");
6991
                    if (this.platform == "mac" && YAHOO.env.ua.gecko) {
6992
                        this.showMacGeckoScrollbars();
6993
                    }
6994
 
6995
                    me.dragEvent.fire("onDrag", arguments);
6996
                };
6997
 
6998
                this.dd.endDrag = function () {
6999
 
7000
                    if (YAHOO.env.ua.ie == 6) {
7001
                        Dom.removeClass(me.element,"drag");
7002
                    }
7003
 
7004
                    me.dragEvent.fire("endDrag", arguments);
7005
                    me.moveEvent.fire(me.cfg.getProperty("xy"));
7006
 
7007
                };
7008
 
7009
                this.dd.setHandleElId(this.header.id);
7010
                this.dd.addInvalidHandleType("INPUT");
7011
                this.dd.addInvalidHandleType("SELECT");
7012
                this.dd.addInvalidHandleType("TEXTAREA");
7013
            }
7014
        },
7015
 
7016
        /**
7017
        * Builds the mask that is laid over the document when the Panel is
7018
        * configured to be modal.
7019
        * @method buildMask
7020
        */
7021
        buildMask: function () {
7022
            var oMask = this.mask;
7023
            if (!oMask) {
7024
                if (!m_oMaskTemplate) {
7025
                    m_oMaskTemplate = document.createElement("div");
7026
                    m_oMaskTemplate.className = "mask";
7027
                    m_oMaskTemplate.innerHTML = "&#160;";
7028
                }
7029
                oMask = m_oMaskTemplate.cloneNode(true);
7030
                oMask.id = this.id + "_mask";
7031
 
7032
                document.body.insertBefore(oMask, document.body.firstChild);
7033
 
7034
                this.mask = oMask;
7035
 
7036
                if (YAHOO.env.ua.gecko && this.platform == "mac") {
7037
                    Dom.addClass(this.mask, "block-scrollbars");
7038
                }
7039
 
7040
                // Stack mask based on the element zindex
7041
                this.stackMask();
7042
            }
7043
        },
7044
 
7045
        /**
7046
        * Hides the modality mask.
7047
        * @method hideMask
7048
        */
7049
        hideMask: function () {
7050
            if (this.cfg.getProperty("modal") && this.mask && this.beforeHideMaskEvent.fire()) {
7051
                this.mask.style.display = "none";
7052
                Dom.removeClass(document.body, "masked");
7053
                this.hideMaskEvent.fire();
7054
            }
7055
        },
7056
 
7057
        /**
7058
        * Shows the modality mask.
7059
        * @method showMask
7060
        */
7061
        showMask: function () {
7062
            if (this.cfg.getProperty("modal") && this.mask && this.beforeShowMaskEvent.fire()) {
7063
                Dom.addClass(document.body, "masked");
7064
                this.sizeMask();
7065
                this.mask.style.display = "block";
7066
                this.showMaskEvent.fire();
7067
            }
7068
        },
7069
 
7070
        /**
7071
        * Sets the size of the modality mask to cover the entire scrollable
7072
        * area of the document
7073
        * @method sizeMask
7074
        */
7075
        sizeMask: function () {
7076
            if (this.mask) {
7077
 
7078
                // Shrink mask first, so it doesn't affect the document size.
7079
                var mask = this.mask,
7080
                    viewWidth = Dom.getViewportWidth(),
7081
                    viewHeight = Dom.getViewportHeight();
7082
 
7083
                if (mask.offsetHeight > viewHeight) {
7084
                    mask.style.height = viewHeight + "px";
7085
                }
7086
 
7087
                if (mask.offsetWidth > viewWidth) {
7088
                    mask.style.width = viewWidth + "px";
7089
                }
7090
 
7091
                // Then size it to the document
7092
                mask.style.height = Dom.getDocumentHeight() + "px";
7093
                mask.style.width = Dom.getDocumentWidth() + "px";
7094
            }
7095
        },
7096
 
7097
        /**
7098
         * Sets the zindex of the mask, if it exists, based on the zindex of
7099
         * the Panel element. The zindex of the mask is set to be one less
7100
         * than the Panel element's zindex.
7101
         *
7102
         * <p>NOTE: This method will not bump up the zindex of the Panel
7103
         * to ensure that the mask has a non-negative zindex. If you require the
7104
         * mask zindex to be 0 or higher, the zindex of the Panel
7105
         * should be set to a value higher than 0, before this method is called.
7106
         * </p>
7107
         * @method stackMask
7108
         */
7109
        stackMask: function() {
7110
            if (this.mask) {
7111
                var panelZ = Dom.getStyle(this.element, "zIndex");
7112
                if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
7113
                    Dom.setStyle(this.mask, "zIndex", panelZ - 1);
7114
                }
7115
            }
7116
        },
7117
 
7118
        /**
7119
        * Renders the Panel by inserting the elements that are not already in
7120
        * the main Panel into their correct places. Optionally appends the
7121
        * Panel to the specified node prior to the render's execution. NOTE:
7122
        * For Panels without existing markup, the appendToNode argument is
7123
        * REQUIRED. If this argument is ommitted and the current element is
7124
        * not present in the document, the function will return false,
7125
        * indicating that the render was a failure.
7126
        * @method render
7127
        * @param {String} appendToNode The element id to which the Module
7128
        * should be appended to prior to rendering <em>OR</em>
7129
        * @param {HTMLElement} appendToNode The element to which the Module
7130
        * should be appended to prior to rendering
7131
        * @return {boolean} Success or failure of the render
7132
        */
7133
        render: function (appendToNode) {
7134
            return Panel.superclass.render.call(this, appendToNode, this.innerElement);
7135
        },
7136
 
7137
        /**
7138
         * Renders the currently set header into it's proper position under the
7139
         * module element. If the module element is not provided, "this.innerElement"
7140
         * is used.
7141
         *
7142
         * @method _renderHeader
7143
         * @protected
7144
         * @param {HTMLElement} moduleElement Optional. A reference to the module element
7145
         */
7146
        _renderHeader: function(moduleElement){
7147
            moduleElement = moduleElement || this.innerElement;
7148
			Panel.superclass._renderHeader.call(this, moduleElement);
7149
        },
7150
 
7151
        /**
7152
         * Renders the currently set body into it's proper position under the
7153
         * module element. If the module element is not provided, "this.innerElement"
7154
         * is used.
7155
         *
7156
         * @method _renderBody
7157
         * @protected
7158
         * @param {HTMLElement} moduleElement Optional. A reference to the module element.
7159
         */
7160
        _renderBody: function(moduleElement){
7161
            moduleElement = moduleElement || this.innerElement;
7162
            Panel.superclass._renderBody.call(this, moduleElement);
7163
        },
7164
 
7165
        /**
7166
         * Renders the currently set footer into it's proper position under the
7167
         * module element. If the module element is not provided, "this.innerElement"
7168
         * is used.
7169
         *
7170
         * @method _renderFooter
7171
         * @protected
7172
         * @param {HTMLElement} moduleElement Optional. A reference to the module element
7173
         */
7174
        _renderFooter: function(moduleElement){
7175
            moduleElement = moduleElement || this.innerElement;
7176
            Panel.superclass._renderFooter.call(this, moduleElement);
7177
        },
7178
 
7179
        /**
7180
        * Removes the Panel element from the DOM and sets all child elements
7181
        * to null.
7182
        * @method destroy
7183
        * @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.
7184
        * 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.
7185
        */
7186
        destroy: function (shallowPurge) {
7187
            Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
7188
            this.removeMask();
7189
            if (this.close) {
7190
                Event.purgeElement(this.close);
7191
            }
7192
            Panel.superclass.destroy.call(this, shallowPurge);
7193
        },
7194
 
7195
        /**
7196
         * Forces the underlay element to be repainted through the application/removal
7197
         * of a yui-force-redraw class to the underlay element.
7198
         *
7199
         * @method forceUnderlayRedraw
7200
         */
7201
        forceUnderlayRedraw : function () {
7202
            var u = this.underlay;
7203
            Dom.addClass(u, "yui-force-redraw");
7204
            setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
7205
        },
7206
 
7207
        /**
7208
        * Returns a String representation of the object.
7209
        * @method toString
7210
        * @return {String} The string representation of the Panel.
7211
        */
7212
        toString: function () {
7213
            return "Panel " + this.id;
7214
        }
7215
 
7216
    });
7217
 
7218
}());
7219
(function () {
7220
 
7221
    /**
7222
    * <p>
7223
    * Dialog is an implementation of Panel that can be used to submit form
7224
    * data.
7225
    * </p>
7226
    * <p>
7227
    * Built-in functionality for buttons with event handlers is included.
7228
    * If the optional YUI Button dependancy is included on the page, the buttons
7229
    * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
7230
    * will be created.
7231
    * </p>
7232
    * <p>
7233
    * Forms can be processed in 3 ways -- via an asynchronous Connection utility call,
7234
    * a simple form POST or GET, or manually. The YUI Connection utility should be
7235
    * included if you're using the default "async" postmethod, but is not required if
7236
    * you're using any of the other postmethod values.
7237
    * </p>
7238
    * @namespace YAHOO.widget
7239
    * @class Dialog
7240
    * @extends YAHOO.widget.Panel
7241
    * @constructor
7242
    * @param {String} el The element ID representing the Dialog <em>OR</em>
7243
    * @param {HTMLElement} el The element representing the Dialog
7244
    * @param {Object} userConfig The configuration object literal containing
7245
    * the configuration that should be set for this Dialog. See configuration
7246
    * documentation for more details.
7247
    */
7248
    YAHOO.widget.Dialog = function (el, userConfig) {
7249
        YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
7250
    };
7251
 
7252
    var Event = YAHOO.util.Event,
7253
        CustomEvent = YAHOO.util.CustomEvent,
7254
        Dom = YAHOO.util.Dom,
7255
        Dialog = YAHOO.widget.Dialog,
7256
        Lang = YAHOO.lang,
7257
 
7258
        /**
7259
         * Constant representing the name of the Dialog's events
7260
         * @property EVENT_TYPES
7261
         * @private
7262
         * @final
7263
         * @type Object
7264
         */
7265
        EVENT_TYPES = {
7266
            "BEFORE_SUBMIT": "beforeSubmit",
7267
            "SUBMIT": "submit",
7268
            "MANUAL_SUBMIT": "manualSubmit",
7269
            "ASYNC_SUBMIT": "asyncSubmit",
7270
            "FORM_SUBMIT": "formSubmit",
7271
            "CANCEL": "cancel"
7272
        },
7273
 
7274
        /**
7275
        * Constant representing the Dialog's configuration properties
7276
        * @property DEFAULT_CONFIG
7277
        * @private
7278
        * @final
7279
        * @type Object
7280
        */
7281
        DEFAULT_CONFIG = {
7282
 
7283
            "POST_METHOD": {
7284
                key: "postmethod",
7285
                value: "async"
7286
            },
7287
 
7288
            "POST_DATA" : {
7289
                key: "postdata",
7290
                value: null
7291
            },
7292
 
7293
            "BUTTONS": {
7294
                key: "buttons",
7295
                value: "none",
7296
                supercedes: ["visible"]
7297
            },
7298
 
7299
            "HIDEAFTERSUBMIT" : {
7300
                key: "hideaftersubmit",
7301
                value: true
7302
            }
7303
 
7304
        };
7305
 
7306
    /**
7307
    * Constant representing the default CSS class used for a Dialog
7308
    * @property YAHOO.widget.Dialog.CSS_DIALOG
7309
    * @static
7310
    * @final
7311
    * @type String
7312
    */
7313
    Dialog.CSS_DIALOG = "yui-dialog";
7314
 
7315
    function removeButtonEventHandlers() {
7316
 
7317
        var aButtons = this._aButtons,
7318
            nButtons,
7319
            oButton,
7320
            i;
7321
 
7322
        if (Lang.isArray(aButtons)) {
7323
            nButtons = aButtons.length;
7324
 
7325
            if (nButtons > 0) {
7326
                i = nButtons - 1;
7327
                do {
7328
                    oButton = aButtons[i];
7329
 
7330
                    if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
7331
                        oButton.destroy();
7332
                    }
7333
                    else if (oButton.tagName.toUpperCase() == "BUTTON") {
7334
                        Event.purgeElement(oButton);
7335
                        Event.purgeElement(oButton, false);
7336
                    }
7337
                }
7338
                while (i--);
7339
            }
7340
        }
7341
    }
7342
 
7343
    YAHOO.extend(Dialog, YAHOO.widget.Panel, {
7344
 
7345
        /**
7346
        * @property form
7347
        * @description Object reference to the Dialog's
7348
        * <code>&#60;form&#62;</code> element.
7349
        * @default null
7350
        * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
7351
        * level-one-html.html#ID-40002357">HTMLFormElement</a>
7352
        */
7353
        form: null,
7354
 
7355
        /**
7356
        * Initializes the class's configurable properties which can be changed
7357
        * using the Dialog's Config object (cfg).
7358
        * @method initDefaultConfig
7359
        */
7360
        initDefaultConfig: function () {
7361
            Dialog.superclass.initDefaultConfig.call(this);
7362
 
7363
            /**
7364
            * The internally maintained callback object for use with the
7365
            * Connection utility. The format of the callback object is
7366
            * similar to Connection Manager's callback object and is
7367
            * simply passed through to Connection Manager when the async
7368
            * request is made.
7369
            * @property callback
7370
            * @type Object
7371
            */
7372
            this.callback = {
7373
 
7374
                /**
7375
                * The function to execute upon success of the
7376
                * Connection submission (when the form does not
7377
                * contain a file input element).
7378
                *
7379
                * @property callback.success
7380
                * @type Function
7381
                */
7382
                success: null,
7383
 
7384
                /**
7385
                * The function to execute upon failure of the
7386
                * Connection submission
7387
                * @property callback.failure
7388
                * @type Function
7389
                */
7390
                failure: null,
7391
 
7392
                /**
7393
                *<p>
7394
                * The function to execute upon success of the
7395
                * Connection submission, when the form contains
7396
                * a file input element.
7397
                * </p>
7398
                * <p>
7399
                * <em>NOTE:</em> Connection manager will not
7400
                * invoke the success or failure handlers for the file
7401
                * upload use case. This will be the only callback
7402
                * handler invoked.
7403
                * </p>
7404
                * <p>
7405
                * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
7406
                * Connection Manager documenation on file uploads</a>.
7407
                * </p>
7408
                * @property callback.upload
7409
                * @type Function
7410
                */
7411
 
7412
                /**
7413
                * The arbitrary argument or arguments to pass to the Connection
7414
                * callback functions
7415
                * @property callback.argument
7416
                * @type Object
7417
                */
7418
                argument: null
7419
 
7420
            };
7421
 
7422
            // Add form dialog config properties //
7423
            /**
7424
            * The method to use for posting the Dialog's form. Possible values
7425
            * are "async", "form", and "manual".
7426
            * @config postmethod
7427
            * @type String
7428
            * @default async
7429
            */
7430
            this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
7431
                handler: this.configPostMethod,
7432
                value: DEFAULT_CONFIG.POST_METHOD.value,
7433
                validator: function (val) {
7434
                    if (val != "form" && val != "async" && val != "none" &&
7435
                        val != "manual") {
7436
                        return false;
7437
                    } else {
7438
                        return true;
7439
                    }
7440
                }
7441
            });
7442
 
7443
            /**
7444
            * Any additional post data which needs to be sent when using the
7445
            * <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
7446
            * The format for the post data string is defined by Connection Manager's
7447
            * <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a>
7448
            * method.
7449
            * @config postdata
7450
            * @type String
7451
            * @default null
7452
            */
7453
            this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
7454
                value: DEFAULT_CONFIG.POST_DATA.value
7455
            });
7456
 
7457
            /**
7458
            * This property is used to configure whether or not the
7459
            * dialog should be automatically hidden after submit.
7460
            *
7461
            * @config hideaftersubmit
7462
            * @type Boolean
7463
            * @default true
7464
            */
7465
            this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
7466
                value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
7467
            });
7468
 
7469
            /**
7470
            * Array of object literals, each containing a set of properties
7471
            * defining a button to be appended into the Dialog's footer.
7472
            *
7473
            * <p>Each button object in the buttons array can have three properties:</p>
7474
            * <dl>
7475
            *    <dt>text:</dt>
7476
            *    <dd>
7477
            *       The text that will display on the face of the button. The text can
7478
            *       include HTML, as long as it is compliant with HTML Button specifications. The text is added to the DOM as HTML,
7479
            *       and should be escaped by the implementor if coming from an external source.
7480
            *    </dd>
7481
            *    <dt>handler:</dt>
7482
            *    <dd>Can be either:
7483
            *    <ol>
7484
            *       <li>A reference to a function that should fire when the
7485
            *       button is clicked.  (In this case scope of this function is
7486
            *       always its Dialog instance.)</li>
7487
            *
7488
            *       <li>An object literal representing the code to be
7489
            *       executed when the button is clicked.
7490
            *
7491
            *       <p>Format:</p>
7492
            *
7493
            *       <p>
7494
            *       <code>{
7495
            *       <br>
7496
            *       <strong>fn:</strong> Function, &#47;&#47;
7497
            *       The handler to call when  the event fires.
7498
            *       <br>
7499
            *       <strong>obj:</strong> Object, &#47;&#47;
7500
            *       An  object to pass back to the handler.
7501
            *       <br>
7502
            *       <strong>scope:</strong> Object &#47;&#47;
7503
            *       The object to use for the scope of the handler.
7504
            *       <br>
7505
            *       }</code>
7506
            *       </p>
7507
            *       </li>
7508
            *     </ol>
7509
            *     </dd>
7510
            *     <dt>isDefault:</dt>
7511
            *     <dd>
7512
            *        An optional boolean value that specifies that a button
7513
            *        should be highlighted and focused by default.
7514
            *     </dd>
7515
            * </dl>
7516
            *
7517
            * <em>NOTE:</em>If the YUI Button Widget is included on the page,
7518
            * the buttons created will be instances of YAHOO.widget.Button.
7519
            * Otherwise, HTML Buttons (<code>&#60;BUTTON&#62;</code>) will be
7520
            * created.
7521
            *
7522
            * @config buttons
7523
            * @type {Array|String}
7524
            * @default "none"
7525
            */
7526
            this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
7527
                handler: this.configButtons,
7528
                value: DEFAULT_CONFIG.BUTTONS.value,
7529
                supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
7530
            });
7531
 
7532
        },
7533
 
7534
        /**
7535
        * Initializes the custom events for Dialog which are fired
7536
        * automatically at appropriate times by the Dialog class.
7537
        * @method initEvents
7538
        */
7539
        initEvents: function () {
7540
            Dialog.superclass.initEvents.call(this);
7541
 
7542
            var SIGNATURE = CustomEvent.LIST;
7543
 
7544
            /**
7545
            * CustomEvent fired prior to submission
7546
            * @event beforeSubmitEvent
7547
            */
7548
            this.beforeSubmitEvent =
7549
                this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
7550
            this.beforeSubmitEvent.signature = SIGNATURE;
7551
 
7552
            /**
7553
            * CustomEvent fired after submission
7554
            * @event submitEvent
7555
            */
7556
            this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
7557
            this.submitEvent.signature = SIGNATURE;
7558
 
7559
            /**
7560
            * CustomEvent fired for manual submission, before the generic submit event is fired
7561
            * @event manualSubmitEvent
7562
            */
7563
            this.manualSubmitEvent =
7564
                this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
7565
            this.manualSubmitEvent.signature = SIGNATURE;
7566
 
7567
            /**
7568
            * CustomEvent fired after asynchronous submission, before the generic submit event is fired
7569
            *
7570
            * @event asyncSubmitEvent
7571
            * @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
7572
            */
7573
            this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
7574
            this.asyncSubmitEvent.signature = SIGNATURE;
7575
 
7576
            /**
7577
            * CustomEvent fired after form-based submission, before the generic submit event is fired
7578
            * @event formSubmitEvent
7579
            */
7580
            this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
7581
            this.formSubmitEvent.signature = SIGNATURE;
7582
 
7583
            /**
7584
            * CustomEvent fired after cancel
7585
            * @event cancelEvent
7586
            */
7587
            this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
7588
            this.cancelEvent.signature = SIGNATURE;
7589
 
7590
        },
7591
 
7592
        /**
7593
        * The Dialog initialization method, which is executed for Dialog and
7594
        * all of its subclasses. This method is automatically called by the
7595
        * constructor, and  sets up all DOM references for pre-existing markup,
7596
        * and creates required markup if it is not already present.
7597
        *
7598
        * @method init
7599
        * @param {String} el The element ID representing the Dialog <em>OR</em>
7600
        * @param {HTMLElement} el The element representing the Dialog
7601
        * @param {Object} userConfig The configuration object literal
7602
        * containing the configuration that should be set for this Dialog.
7603
        * See configuration documentation for more details.
7604
        */
7605
        init: function (el, userConfig) {
7606
 
7607
            /*
7608
                 Note that we don't pass the user config in here yet because
7609
                 we only want it executed once, at the lowest subclass level
7610
            */
7611
 
7612
            Dialog.superclass.init.call(this, el/*, userConfig*/);
7613
 
7614
            this.beforeInitEvent.fire(Dialog);
7615
 
7616
            Dom.addClass(this.element, Dialog.CSS_DIALOG);
7617
 
7618
            this.cfg.setProperty("visible", false);
7619
 
7620
            if (userConfig) {
7621
                this.cfg.applyConfig(userConfig, true);
7622
            }
7623
 
7624
            //this.showEvent.subscribe(this.focusFirst, this, true);
7625
            this.beforeHideEvent.subscribe(this.blurButtons, this, true);
7626
 
7627
            this.subscribe("changeBody", this.registerForm);
7628
 
7629
            this.initEvent.fire(Dialog);
7630
        },
7631
 
7632
        /**
7633
        * Submits the Dialog's form depending on the value of the
7634
        * "postmethod" configuration property.  <strong>Please note:
7635
        * </strong> As of version 2.3 this method will automatically handle
7636
        * asyncronous file uploads should the Dialog instance's form contain
7637
        * <code>&#60;input type="file"&#62;</code> elements.  If a Dialog
7638
        * instance will be handling asyncronous file uploads, its
7639
        * <code>callback</code> property will need to be setup with a
7640
        * <code>upload</code> handler rather than the standard
7641
        * <code>success</code> and, or <code>failure</code> handlers.  For more
7642
        * information, see the <a href="http://developer.yahoo.com/yui/
7643
        * connection/#file">Connection Manager documenation on file uploads</a>.
7644
        * @method doSubmit
7645
        */
7646
        doSubmit: function () {
7647
 
7648
            var Connect = YAHOO.util.Connect,
7649
                oForm = this.form,
7650
                bUseFileUpload = false,
7651
                bUseSecureFileUpload = false,
7652
                aElements,
7653
                nElements,
7654
                i,
7655
                formAttrs;
7656
 
7657
            switch (this.cfg.getProperty("postmethod")) {
7658
 
7659
                case "async":
7660
                    aElements = oForm.elements;
7661
                    nElements = aElements.length;
7662
 
7663
                    if (nElements > 0) {
7664
                        i = nElements - 1;
7665
                        do {
7666
                            if (aElements[i].type == "file") {
7667
                                bUseFileUpload = true;
7668
                                break;
7669
                            }
7670
                        }
7671
                        while(i--);
7672
                    }
7673
 
7674
                    if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
7675
                        bUseSecureFileUpload = true;
7676
                    }
7677
 
7678
                    formAttrs = this._getFormAttributes(oForm);
7679
 
7680
                    Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
7681
 
7682
                    var postData = this.cfg.getProperty("postdata");
7683
                    var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
7684
 
7685
                    this.asyncSubmitEvent.fire(c);
7686
 
7687
                    break;
7688
 
7689
                case "form":
7690
                    oForm.submit();
7691
                    this.formSubmitEvent.fire();
7692
                    break;
7693
 
7694
                case "none":
7695
                case "manual":
7696
                    this.manualSubmitEvent.fire();
7697
                    break;
7698
            }
7699
        },
7700
 
7701
        /**
7702
         * Retrieves important attributes (currently method and action) from
7703
         * the form element, accounting for any elements which may have the same name
7704
         * as the attributes. Defaults to "POST" and "" for method and action respectively
7705
         * if the attribute cannot be retrieved.
7706
         *
7707
         * @method _getFormAttributes
7708
         * @protected
7709
         * @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
7710
         * @return {Object} Object literal, with method and action String properties.
7711
         */
7712
        _getFormAttributes : function(oForm){
7713
            var attrs = {
7714
                method : null,
7715
                action : null
7716
            };
7717
 
7718
            if (oForm) {
7719
                if (oForm.getAttributeNode) {
7720
                    var action = oForm.getAttributeNode("action");
7721
                    var method = oForm.getAttributeNode("method");
7722
 
7723
                    if (action) {
7724
                        attrs.action = action.value;
7725
                    }
7726
 
7727
                    if (method) {
7728
                        attrs.method = method.value;
7729
                    }
7730
 
7731
                } else {
7732
                    attrs.action = oForm.getAttribute("action");
7733
                    attrs.method = oForm.getAttribute("method");
7734
                }
7735
            }
7736
 
7737
            attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
7738
            attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
7739
 
7740
            return attrs;
7741
        },
7742
 
7743
        /**
7744
        * Prepares the Dialog's internal FORM object, creating one if one is
7745
        * not currently present.
7746
        * @method registerForm
7747
        */
7748
        registerForm: function() {
7749
 
7750
            var form = this.element.getElementsByTagName("form")[0];
7751
 
7752
            if (this.form) {
7753
                if (this.form == form && Dom.isAncestor(this.element, this.form)) {
7754
                    return;
7755
                } else {
7756
                    Event.purgeElement(this.form);
7757
                    this.form = null;
7758
                }
7759
            }
7760
 
7761
            if (!form) {
7762
                form = document.createElement("form");
7763
                form.name = "frm_" + this.id;
7764
                this.body.appendChild(form);
7765
            }
7766
 
7767
            if (form) {
7768
                this.form = form;
7769
                Event.on(form, "submit", this._submitHandler, this, true);
7770
            }
7771
        },
7772
 
7773
        /**
7774
         * Internal handler for the form submit event
7775
         *
7776
         * @method _submitHandler
7777
         * @protected
7778
         * @param {DOMEvent} e The DOM Event object
7779
         */
7780
        _submitHandler : function(e) {
7781
            Event.stopEvent(e);
7782
            this.submit();
7783
            this.form.blur();
7784
        },
7785
 
7786
        /**
7787
         * Sets up a tab, shift-tab loop between the first and last elements
7788
         * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
7789
         * instance properties, which are reset everytime this method is invoked.
7790
         *
7791
         * @method setTabLoop
7792
         * @param {HTMLElement} firstElement
7793
         * @param {HTMLElement} lastElement
7794
         *
7795
         */
7796
        setTabLoop : function(firstElement, lastElement) {
7797
 
7798
            firstElement = firstElement || this.firstButton;
7799
            lastElement = lastElement || this.lastButton;
7800
 
7801
            Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
7802
        },
7803
 
7804
        /**
7805
         * Protected internal method for setTabLoop, which can be used by
7806
         * subclasses to jump in and modify the arguments passed in if required.
7807
         *
7808
         * @method _setTabLoop
7809
         * @param {HTMLElement} firstElement
7810
         * @param {HTMLElement} lastElement
7811
         * @protected
7812
         */
7813
        _setTabLoop : function(firstElement, lastElement) {
7814
            firstElement = firstElement || this.firstButton;
7815
            lastElement = this.lastButton || lastElement;
7816
 
7817
            this.setTabLoop(firstElement, lastElement);
7818
        },
7819
 
7820
        /**
7821
         * Configures instance properties, pointing to the
7822
         * first and last focusable elements in the Dialog's form.
7823
         *
7824
         * @method setFirstLastFocusable
7825
         */
7826
        setFirstLastFocusable : function() {
7827
 
7828
            Dialog.superclass.setFirstLastFocusable.call(this);
7829
 
7830
            var i, l, el, elements = this.focusableElements;
7831
 
7832
            this.firstFormElement = null;
7833
            this.lastFormElement = null;
7834
 
7835
            if (this.form && elements && elements.length > 0) {
7836
                l = elements.length;
7837
 
7838
                for (i = 0; i < l; ++i) {
7839
                    el = elements[i];
7840
                    if (this.form === el.form) {
7841
                        this.firstFormElement = el;
7842
                        break;
7843
                    }
7844
                }
7845
 
7846
                for (i = l-1; i >= 0; --i) {
7847
                    el = elements[i];
7848
                    if (this.form === el.form) {
7849
                        this.lastFormElement = el;
7850
                        break;
7851
                    }
7852
                }
7853
            }
7854
        },
7855
 
7856
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
7857
        /**
7858
        * The default event handler fired when the "close" property is
7859
        * changed. The method controls the appending or hiding of the close
7860
        * icon at the top right of the Dialog.
7861
        * @method configClose
7862
        * @param {String} type The CustomEvent type (usually the property name)
7863
        * @param {Object[]} args The CustomEvent arguments. For
7864
        * configuration handlers, args[0] will equal the newly applied value
7865
        * for the property.
7866
        * @param {Object} obj The scope object. For configuration handlers,
7867
        * this will usually equal the owner.
7868
        */
7869
        configClose: function (type, args, obj) {
7870
            Dialog.superclass.configClose.apply(this, arguments);
7871
        },
7872
 
7873
        /**
7874
         * Event handler for the close icon
7875
         *
7876
         * @method _doClose
7877
         * @protected
7878
         *
7879
         * @param {DOMEvent} e
7880
         */
7881
         _doClose : function(e) {
7882
            Event.preventDefault(e);
7883
            this.cancel();
7884
        },
7885
 
7886
        /**
7887
        * The default event handler for the "buttons" configuration property
7888
        * @method configButtons
7889
        * @param {String} type The CustomEvent type (usually the property name)
7890
        * @param {Object[]} args The CustomEvent arguments. For configuration
7891
        * handlers, args[0] will equal the newly applied value for the property.
7892
        * @param {Object} obj The scope object. For configuration handlers,
7893
        * this will usually equal the owner.
7894
        */
7895
        configButtons: function (type, args, obj) {
7896
 
7897
            var Button = YAHOO.widget.Button,
7898
                aButtons = args[0],
7899
                oInnerElement = this.innerElement,
7900
                oButton,
7901
                oButtonEl,
7902
                oYUIButton,
7903
                nButtons,
7904
                oSpan,
7905
                oFooter,
7906
                i;
7907
 
7908
            removeButtonEventHandlers.call(this);
7909
 
7910
            this._aButtons = null;
7911
 
7912
            if (Lang.isArray(aButtons)) {
7913
 
7914
                oSpan = document.createElement("span");
7915
                oSpan.className = "button-group";
7916
                nButtons = aButtons.length;
7917
 
7918
                this._aButtons = [];
7919
                this.defaultHtmlButton = null;
7920
 
7921
                for (i = 0; i < nButtons; i++) {
7922
                    oButton = aButtons[i];
7923
 
7924
                    if (Button) {
7925
                        oYUIButton = new Button({ label: oButton.text, type:oButton.type });
7926
                        oYUIButton.appendTo(oSpan);
7927
 
7928
                        oButtonEl = oYUIButton.get("element");
7929
 
7930
                        if (oButton.isDefault) {
7931
                            oYUIButton.addClass("default");
7932
                            this.defaultHtmlButton = oButtonEl;
7933
                        }
7934
 
7935
                        if (Lang.isFunction(oButton.handler)) {
7936
 
7937
                            oYUIButton.set("onclick", {
7938
                                fn: oButton.handler,
7939
                                obj: this,
7940
                                scope: this
7941
                            });
7942
 
7943
                        } else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
7944
 
7945
                            oYUIButton.set("onclick", {
7946
                                fn: oButton.handler.fn,
7947
                                obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7948
                                scope: (oButton.handler.scope || this)
7949
                            });
7950
 
7951
                        }
7952
 
7953
                        this._aButtons[this._aButtons.length] = oYUIButton;
7954
 
7955
                    } else {
7956
 
7957
                        oButtonEl = document.createElement("button");
7958
                        oButtonEl.setAttribute("type", "button");
7959
 
7960
                        if (oButton.isDefault) {
7961
                            oButtonEl.className = "default";
7962
                            this.defaultHtmlButton = oButtonEl;
7963
                        }
7964
 
7965
                        oButtonEl.innerHTML = oButton.text;
7966
 
7967
                        if (Lang.isFunction(oButton.handler)) {
7968
                            Event.on(oButtonEl, "click", oButton.handler, this, true);
7969
                        } else if (Lang.isObject(oButton.handler) &&
7970
                            Lang.isFunction(oButton.handler.fn)) {
7971
 
7972
                            Event.on(oButtonEl, "click",
7973
                                oButton.handler.fn,
7974
                                ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
7975
                                (oButton.handler.scope || this));
7976
                        }
7977
 
7978
                        oSpan.appendChild(oButtonEl);
7979
                        this._aButtons[this._aButtons.length] = oButtonEl;
7980
                    }
7981
 
7982
                    oButton.htmlButton = oButtonEl;
7983
 
7984
                    if (i === 0) {
7985
                        this.firstButton = oButtonEl;
7986
                    }
7987
 
7988
                    if (i == (nButtons - 1)) {
7989
                        this.lastButton = oButtonEl;
7990
                    }
7991
                }
7992
 
7993
                this.setFooter(oSpan);
7994
 
7995
                oFooter = this.footer;
7996
 
7997
                if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
7998
                    oInnerElement.appendChild(oFooter);
7999
                }
8000
 
8001
                this.buttonSpan = oSpan;
8002
 
8003
            } else { // Do cleanup
8004
                oSpan = this.buttonSpan;
8005
                oFooter = this.footer;
8006
                if (oSpan && oFooter) {
8007
                    oFooter.removeChild(oSpan);
8008
                    this.buttonSpan = null;
8009
                    this.firstButton = null;
8010
                    this.lastButton = null;
8011
                    this.defaultHtmlButton = null;
8012
                }
8013
            }
8014
 
8015
            this.changeContentEvent.fire();
8016
        },
8017
 
8018
        /**
8019
        * @method getButtons
8020
        * @description Returns an array containing each of the Dialog's
8021
        * buttons, by default an array of HTML <code>&#60;BUTTON&#62;</code>
8022
        * elements.  If the Dialog's buttons were created using the
8023
        * YAHOO.widget.Button class (via the inclusion of the optional Button
8024
        * dependency on the page), an array of YAHOO.widget.Button instances
8025
        * is returned.
8026
        * @return {Array}
8027
        */
8028
        getButtons: function () {
8029
            return this._aButtons || null;
8030
        },
8031
 
8032
        /**
8033
         * <p>
8034
         * Sets focus to the first focusable element in the Dialog's form if found,
8035
         * else, the default button if found, else the first button defined via the
8036
         * "buttons" configuration property.
8037
         * </p>
8038
         * <p>
8039
         * This method is invoked when the Dialog is made visible.
8040
         * </p>
8041
         * @method focusFirst
8042
         * @return {Boolean} true, if focused. false if not
8043
         */
8044
        focusFirst: function (type, args, obj) {
8045
 
8046
            var el = this.firstFormElement,
8047
                focused = false;
8048
 
8049
            if (args && args[1]) {
8050
                Event.stopEvent(args[1]);
8051
 
8052
                // When tabbing here, use firstElement instead of firstFormElement
8053
                if (args[0] === 9 && this.firstElement) {
8054
                    el = this.firstElement;
8055
                }
8056
            }
8057
 
8058
            if (el) {
8059
                try {
8060
                    el.focus();
8061
                    focused = true;
8062
                } catch(oException) {
8063
                    // Ignore
8064
                }
8065
            } else {
8066
                if (this.defaultHtmlButton) {
8067
                    focused = this.focusDefaultButton();
8068
                } else {
8069
                    focused = this.focusFirstButton();
8070
                }
8071
            }
8072
            return focused;
8073
        },
8074
 
8075
        /**
8076
        * Sets focus to the last element in the Dialog's form or the last
8077
        * button defined via the "buttons" configuration property.
8078
        * @method focusLast
8079
        * @return {Boolean} true, if focused. false if not
8080
        */
8081
        focusLast: function (type, args, obj) {
8082
 
8083
            var aButtons = this.cfg.getProperty("buttons"),
8084
                el = this.lastFormElement,
8085
                focused = false;
8086
 
8087
            if (args && args[1]) {
8088
                Event.stopEvent(args[1]);
8089
 
8090
                // When tabbing here, use lastElement instead of lastFormElement
8091
                if (args[0] === 9 && this.lastElement) {
8092
                    el = this.lastElement;
8093
                }
8094
            }
8095
 
8096
            if (aButtons && Lang.isArray(aButtons)) {
8097
                focused = this.focusLastButton();
8098
            } else {
8099
                if (el) {
8100
                    try {
8101
                        el.focus();
8102
                        focused = true;
8103
                    } catch(oException) {
8104
                        // Ignore
8105
                    }
8106
                }
8107
            }
8108
 
8109
            return focused;
8110
        },
8111
 
8112
        /**
8113
         * Helper method to normalize button references. It either returns the
8114
         * YUI Button instance for the given element if found,
8115
         * or the passes back the HTMLElement reference if a corresponding YUI Button
8116
         * reference is not found or YAHOO.widget.Button does not exist on the page.
8117
         *
8118
         * @method _getButton
8119
         * @private
8120
         * @param {HTMLElement} button
8121
         * @return {YAHOO.widget.Button|HTMLElement}
8122
         */
8123
        _getButton : function(button) {
8124
            var Button = YAHOO.widget.Button;
8125
 
8126
            // If we have an HTML button and YUI Button is on the page,
8127
            // get the YUI Button reference if available.
8128
            if (Button && button && button.nodeName && button.id) {
8129
                button = Button.getButton(button.id) || button;
8130
            }
8131
 
8132
            return button;
8133
        },
8134
 
8135
        /**
8136
        * Sets the focus to the button that is designated as the default via
8137
        * the "buttons" configuration property. By default, this method is
8138
        * called when the Dialog is made visible.
8139
        * @method focusDefaultButton
8140
        * @return {Boolean} true if focused, false if not
8141
        */
8142
        focusDefaultButton: function () {
8143
            var button = this._getButton(this.defaultHtmlButton),
8144
                         focused = false;
8145
 
8146
            if (button) {
8147
                /*
8148
                    Place the call to the "focus" method inside a try/catch
8149
                    block to prevent IE from throwing JavaScript errors if
8150
                    the element is disabled or hidden.
8151
                */
8152
                try {
8153
                    button.focus();
8154
                    focused = true;
8155
                } catch(oException) {
8156
                }
8157
            }
8158
            return focused;
8159
        },
8160
 
8161
        /**
8162
        * Blurs all the buttons defined via the "buttons"
8163
        * configuration property.
8164
        * @method blurButtons
8165
        */
8166
        blurButtons: function () {
8167
 
8168
            var aButtons = this.cfg.getProperty("buttons"),
8169
                nButtons,
8170
                oButton,
8171
                oElement,
8172
                i;
8173
 
8174
            if (aButtons && Lang.isArray(aButtons)) {
8175
                nButtons = aButtons.length;
8176
                if (nButtons > 0) {
8177
                    i = (nButtons - 1);
8178
                    do {
8179
                        oButton = aButtons[i];
8180
                        if (oButton) {
8181
                            oElement = this._getButton(oButton.htmlButton);
8182
                            if (oElement) {
8183
                                /*
8184
                                    Place the call to the "blur" method inside
8185
                                    a try/catch block to prevent IE from
8186
                                    throwing JavaScript errors if the element
8187
                                    is disabled or hidden.
8188
                                */
8189
                                try {
8190
                                    oElement.blur();
8191
                                } catch(oException) {
8192
                                    // ignore
8193
                                }
8194
                            }
8195
                        }
8196
                    } while(i--);
8197
                }
8198
            }
8199
        },
8200
 
8201
        /**
8202
        * Sets the focus to the first button created via the "buttons"
8203
        * configuration property.
8204
        * @method focusFirstButton
8205
        * @return {Boolean} true, if focused. false if not
8206
        */
8207
        focusFirstButton: function () {
8208
 
8209
            var aButtons = this.cfg.getProperty("buttons"),
8210
                oButton,
8211
                oElement,
8212
                focused = false;
8213
 
8214
            if (aButtons && Lang.isArray(aButtons)) {
8215
                oButton = aButtons[0];
8216
                if (oButton) {
8217
                    oElement = this._getButton(oButton.htmlButton);
8218
                    if (oElement) {
8219
                        /*
8220
                            Place the call to the "focus" method inside a
8221
                            try/catch block to prevent IE from throwing
8222
                            JavaScript errors if the element is disabled
8223
                            or hidden.
8224
                        */
8225
                        try {
8226
                            oElement.focus();
8227
                            focused = true;
8228
                        } catch(oException) {
8229
                            // ignore
8230
                        }
8231
                    }
8232
                }
8233
            }
8234
 
8235
            return focused;
8236
        },
8237
 
8238
        /**
8239
        * Sets the focus to the last button created via the "buttons"
8240
        * configuration property.
8241
        * @method focusLastButton
8242
        * @return {Boolean} true, if focused. false if not
8243
        */
8244
        focusLastButton: function () {
8245
 
8246
            var aButtons = this.cfg.getProperty("buttons"),
8247
                nButtons,
8248
                oButton,
8249
                oElement,
8250
                focused = false;
8251
 
8252
            if (aButtons && Lang.isArray(aButtons)) {
8253
                nButtons = aButtons.length;
8254
                if (nButtons > 0) {
8255
                    oButton = aButtons[(nButtons - 1)];
8256
 
8257
                    if (oButton) {
8258
                        oElement = this._getButton(oButton.htmlButton);
8259
                        if (oElement) {
8260
                            /*
8261
                                Place the call to the "focus" method inside a
8262
                                try/catch block to prevent IE from throwing
8263
                                JavaScript errors if the element is disabled
8264
                                or hidden.
8265
                            */
8266
 
8267
                            try {
8268
                                oElement.focus();
8269
                                focused = true;
8270
                            } catch(oException) {
8271
                                // Ignore
8272
                            }
8273
                        }
8274
                    }
8275
                }
8276
            }
8277
 
8278
            return focused;
8279
        },
8280
 
8281
        /**
8282
        * The default event handler for the "postmethod" configuration property
8283
        * @method configPostMethod
8284
        * @param {String} type The CustomEvent type (usually the property name)
8285
        * @param {Object[]} args The CustomEvent arguments. For
8286
        * configuration handlers, args[0] will equal the newly applied value
8287
        * for the property.
8288
        * @param {Object} obj The scope object. For configuration handlers,
8289
        * this will usually equal the owner.
8290
        */
8291
        configPostMethod: function (type, args, obj) {
8292
            this.registerForm();
8293
        },
8294
 
8295
        // END BUILT-IN PROPERTY EVENT HANDLERS //
8296
 
8297
        /**
8298
        * Built-in function hook for writing a validation function that will
8299
        * be checked for a "true" value prior to a submit. This function, as
8300
        * implemented by default, always returns true, so it should be
8301
        * overridden if validation is necessary.
8302
        * @method validate
8303
        */
8304
        validate: function () {
8305
            return true;
8306
        },
8307
 
8308
        /**
8309
        * Executes a submit of the Dialog if validation
8310
        * is successful. By default the Dialog is hidden
8311
        * after submission, but you can set the "hideaftersubmit"
8312
        * configuration property to false, to prevent the Dialog
8313
        * from being hidden.
8314
        *
8315
        * @method submit
8316
        */
8317
        submit: function () {
8318
            if (this.validate()) {
8319
                if (this.beforeSubmitEvent.fire()) {
8320
                    this.doSubmit();
8321
                    this.submitEvent.fire();
8322
 
8323
                    if (this.cfg.getProperty("hideaftersubmit")) {
8324
                        this.hide();
8325
                    }
8326
 
8327
                    return true;
8328
                } else {
8329
                    return false;
8330
                }
8331
            } else {
8332
                return false;
8333
            }
8334
        },
8335
 
8336
        /**
8337
        * Executes the cancel of the Dialog followed by a hide.
8338
        * @method cancel
8339
        */
8340
        cancel: function () {
8341
            this.cancelEvent.fire();
8342
            this.hide();
8343
        },
8344
 
8345
        /**
8346
        * Returns a JSON-compatible data structure representing the data
8347
        * currently contained in the form.
8348
        * @method getData
8349
        * @return {Object} A JSON object reprsenting the data of the
8350
        * current form.
8351
        */
8352
        getData: function () {
8353
 
8354
            var oForm = this.form,
8355
                aElements,
8356
                nTotalElements,
8357
                oData,
8358
                sName,
8359
                oElement,
8360
                nElements,
8361
                sType,
8362
                sTagName,
8363
                aOptions,
8364
                nOptions,
8365
                aValues,
8366
                oOption,
8367
                oRadio,
8368
                oCheckbox,
8369
                valueAttr,
8370
                i,
8371
                n;
8372
 
8373
            function isFormElement(p_oElement) {
8374
                var sTag = p_oElement.tagName.toUpperCase();
8375
                return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
8376
                        sTag == "SELECT") && p_oElement.name == sName);
8377
            }
8378
 
8379
            if (oForm) {
8380
 
8381
                aElements = oForm.elements;
8382
                nTotalElements = aElements.length;
8383
                oData = {};
8384
 
8385
                for (i = 0; i < nTotalElements; i++) {
8386
                    sName = aElements[i].name;
8387
 
8388
                    /*
8389
                        Using "Dom.getElementsBy" to safeguard user from JS
8390
                        errors that result from giving a form field (or set of
8391
                        fields) the same name as a native method of a form
8392
                        (like "submit") or a DOM collection (such as the "item"
8393
                        method). Originally tried accessing fields via the
8394
                        "namedItem" method of the "element" collection, but
8395
                        discovered that it won't return a collection of fields
8396
                        in Gecko.
8397
                    */
8398
 
8399
                    oElement = Dom.getElementsBy(isFormElement, "*", oForm);
8400
                    nElements = oElement.length;
8401
 
8402
                    if (nElements > 0) {
8403
                        if (nElements == 1) {
8404
                            oElement = oElement[0];
8405
 
8406
                            sType = oElement.type;
8407
                            sTagName = oElement.tagName.toUpperCase();
8408
 
8409
                            switch (sTagName) {
8410
                                case "INPUT":
8411
                                    if (sType == "checkbox") {
8412
                                        oData[sName] = oElement.checked;
8413
                                    } else if (sType != "radio") {
8414
                                        oData[sName] = oElement.value;
8415
                                    }
8416
                                    break;
8417
 
8418
                                case "TEXTAREA":
8419
                                    oData[sName] = oElement.value;
8420
                                    break;
8421
 
8422
                                case "SELECT":
8423
                                    aOptions = oElement.options;
8424
                                    nOptions = aOptions.length;
8425
                                    aValues = [];
8426
 
8427
                                    for (n = 0; n < nOptions; n++) {
8428
                                        oOption = aOptions[n];
8429
                                        if (oOption.selected) {
8430
                                            valueAttr = oOption.attributes.value;
8431
                                            aValues[aValues.length] = (valueAttr && valueAttr.specified) ? oOption.value : oOption.text;
8432
                                        }
8433
                                    }
8434
                                    oData[sName] = aValues;
8435
                                    break;
8436
                            }
8437
 
8438
                        } else {
8439
                            sType = oElement[0].type;
8440
                            switch (sType) {
8441
                                case "radio":
8442
                                    for (n = 0; n < nElements; n++) {
8443
                                        oRadio = oElement[n];
8444
                                        if (oRadio.checked) {
8445
                                            oData[sName] = oRadio.value;
8446
                                            break;
8447
                                        }
8448
                                    }
8449
                                    break;
8450
 
8451
                                case "checkbox":
8452
                                    aValues = [];
8453
                                    for (n = 0; n < nElements; n++) {
8454
                                        oCheckbox = oElement[n];
8455
                                        if (oCheckbox.checked) {
8456
                                            aValues[aValues.length] =  oCheckbox.value;
8457
                                        }
8458
                                    }
8459
                                    oData[sName] = aValues;
8460
                                    break;
8461
                            }
8462
                        }
8463
                    }
8464
                }
8465
            }
8466
 
8467
            return oData;
8468
        },
8469
 
8470
        /**
8471
        * Removes the Panel element from the DOM and sets all child elements
8472
        * to null.
8473
        * @method destroy
8474
        * @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.
8475
        * 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.
8476
        */
8477
        destroy: function (shallowPurge) {
8478
            removeButtonEventHandlers.call(this);
8479
 
8480
            this._aButtons = null;
8481
 
8482
            var aForms = this.element.getElementsByTagName("form"),
8483
                oForm;
8484
 
8485
            if (aForms.length > 0) {
8486
                oForm = aForms[0];
8487
 
8488
                if (oForm) {
8489
                    Event.purgeElement(oForm);
8490
                    if (oForm.parentNode) {
8491
                        oForm.parentNode.removeChild(oForm);
8492
                    }
8493
                    this.form = null;
8494
                }
8495
            }
8496
            Dialog.superclass.destroy.call(this, shallowPurge);
8497
        },
8498
 
8499
        /**
8500
        * Returns a string representation of the object.
8501
        * @method toString
8502
        * @return {String} The string representation of the Dialog
8503
        */
8504
        toString: function () {
8505
            return "Dialog " + this.id;
8506
        }
8507
 
8508
    });
8509
 
8510
}());
8511
(function () {
8512
 
8513
    /**
8514
    * SimpleDialog is a simple implementation of Dialog that can be used to
8515
    * submit a single value. Forms can be processed in 3 ways -- via an
8516
    * asynchronous Connection utility call, a simple form POST or GET,
8517
    * or manually.
8518
    * @namespace YAHOO.widget
8519
    * @class SimpleDialog
8520
    * @extends YAHOO.widget.Dialog
8521
    * @constructor
8522
    * @param {String} el The element ID representing the SimpleDialog
8523
    * <em>OR</em>
8524
    * @param {HTMLElement} el The element representing the SimpleDialog
8525
    * @param {Object} userConfig The configuration object literal containing
8526
    * the configuration that should be set for this SimpleDialog. See
8527
    * configuration documentation for more details.
8528
    */
8529
    YAHOO.widget.SimpleDialog = function (el, userConfig) {
8530
 
8531
        YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
8532
            el, userConfig);
8533
 
8534
    };
8535
 
8536
    var Dom = YAHOO.util.Dom,
8537
        SimpleDialog = YAHOO.widget.SimpleDialog,
8538
 
8539
        /**
8540
        * Constant representing the SimpleDialog's configuration properties
8541
        * @property DEFAULT_CONFIG
8542
        * @private
8543
        * @final
8544
        * @type Object
8545
        */
8546
        DEFAULT_CONFIG = {
8547
 
8548
            "ICON": {
8549
                key: "icon",
8550
                value: "none",
8551
                suppressEvent: true
8552
            },
8553
 
8554
            "TEXT": {
8555
                key: "text",
8556
                value: "",
8557
                suppressEvent: true,
8558
                supercedes: ["icon"]
8559
            }
8560
 
8561
        };
8562
 
8563
    /**
8564
    * Constant for the standard network icon for a blocking action
8565
    * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
8566
    * @static
8567
    * @final
8568
    * @type String
8569
    */
8570
    SimpleDialog.ICON_BLOCK = "blckicon";
8571
 
8572
    /**
8573
    * Constant for the standard network icon for alarm
8574
    * @property YAHOO.widget.SimpleDialog.ICON_ALARM
8575
    * @static
8576
    * @final
8577
    * @type String
8578
    */
8579
    SimpleDialog.ICON_ALARM = "alrticon";
8580
 
8581
    /**
8582
    * Constant for the standard network icon for help
8583
    * @property YAHOO.widget.SimpleDialog.ICON_HELP
8584
    * @static
8585
    * @final
8586
    * @type String
8587
    */
8588
    SimpleDialog.ICON_HELP  = "hlpicon";
8589
 
8590
    /**
8591
    * Constant for the standard network icon for info
8592
    * @property YAHOO.widget.SimpleDialog.ICON_INFO
8593
    * @static
8594
    * @final
8595
    * @type String
8596
    */
8597
    SimpleDialog.ICON_INFO  = "infoicon";
8598
 
8599
    /**
8600
    * Constant for the standard network icon for warn
8601
    * @property YAHOO.widget.SimpleDialog.ICON_WARN
8602
    * @static
8603
    * @final
8604
    * @type String
8605
    */
8606
    SimpleDialog.ICON_WARN  = "warnicon";
8607
 
8608
    /**
8609
    * Constant for the standard network icon for a tip
8610
    * @property YAHOO.widget.SimpleDialog.ICON_TIP
8611
    * @static
8612
    * @final
8613
    * @type String
8614
    */
8615
    SimpleDialog.ICON_TIP   = "tipicon";
8616
 
8617
    /**
8618
    * Constant representing the name of the CSS class applied to the element
8619
    * created by the "icon" configuration property.
8620
    * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
8621
    * @static
8622
    * @final
8623
    * @type String
8624
    */
8625
    SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
8626
 
8627
    /**
8628
    * Constant representing the default CSS class used for a SimpleDialog
8629
    * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
8630
    * @static
8631
    * @final
8632
    * @type String
8633
    */
8634
    SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
8635
 
8636
 
8637
    YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
8638
 
8639
        /**
8640
        * Initializes the class's configurable properties which can be changed
8641
        * using the SimpleDialog's Config object (cfg).
8642
        * @method initDefaultConfig
8643
        */
8644
        initDefaultConfig: function () {
8645
 
8646
            SimpleDialog.superclass.initDefaultConfig.call(this);
8647
 
8648
            // Add dialog config properties //
8649
 
8650
            /**
8651
            * Sets the informational icon for the SimpleDialog
8652
            * @config icon
8653
            * @type String
8654
            * @default "none"
8655
            */
8656
            this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
8657
                handler: this.configIcon,
8658
                value: DEFAULT_CONFIG.ICON.value,
8659
                suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
8660
            });
8661
 
8662
            /**
8663
            * Sets the text for the SimpleDialog. The text is inserted into the DOM as HTML, and should be escaped by the implementor if coming from an external source.
8664
            * @config text
8665
            * @type HTML
8666
            * @default ""
8667
            */
8668
            this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
8669
                handler: this.configText,
8670
                value: DEFAULT_CONFIG.TEXT.value,
8671
                suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
8672
                supercedes: DEFAULT_CONFIG.TEXT.supercedes
8673
            });
8674
 
8675
        },
8676
 
8677
 
8678
        /**
8679
        * The SimpleDialog initialization method, which is executed for
8680
        * SimpleDialog and all of its subclasses. This method is automatically
8681
        * called by the constructor, and  sets up all DOM references for
8682
        * pre-existing markup, and creates required markup if it is not
8683
        * already present.
8684
        * @method init
8685
        * @param {String} el The element ID representing the SimpleDialog
8686
        * <em>OR</em>
8687
        * @param {HTMLElement} el The element representing the SimpleDialog
8688
        * @param {Object} userConfig The configuration object literal
8689
        * containing the configuration that should be set for this
8690
        * SimpleDialog. See configuration documentation for more details.
8691
        */
8692
        init: function (el, userConfig) {
8693
 
8694
            /*
8695
                Note that we don't pass the user config in here yet because we
8696
                only want it executed once, at the lowest subclass level
8697
            */
8698
 
8699
            SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
8700
 
8701
            this.beforeInitEvent.fire(SimpleDialog);
8702
 
8703
            Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
8704
 
8705
            this.cfg.queueProperty("postmethod", "manual");
8706
 
8707
            if (userConfig) {
8708
                this.cfg.applyConfig(userConfig, true);
8709
            }
8710
 
8711
            this.beforeRenderEvent.subscribe(function () {
8712
                if (! this.body) {
8713
                    this.setBody("");
8714
                }
8715
            }, this, true);
8716
 
8717
            this.initEvent.fire(SimpleDialog);
8718
 
8719
        },
8720
 
8721
        /**
8722
        * Prepares the SimpleDialog's internal FORM object, creating one if one
8723
        * is not currently present, and adding the value hidden field.
8724
        * @method registerForm
8725
        */
8726
        registerForm: function () {
8727
            SimpleDialog.superclass.registerForm.call(this);
8728
 
8729
            var doc = this.form.ownerDocument,
8730
                input = doc.createElement("input");
8731
 
8732
            input.type = "hidden";
8733
            input.name = this.id;
8734
            input.value = "";
8735
 
8736
            this.form.appendChild(input);
8737
        },
8738
 
8739
        // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
8740
 
8741
        /**
8742
        * Fired when the "icon" property is set.
8743
        * @method configIcon
8744
        * @param {String} type The CustomEvent type (usually the property name)
8745
        * @param {Object[]} args The CustomEvent arguments. For configuration
8746
        * handlers, args[0] will equal the newly applied value for the property.
8747
        * @param {Object} obj The scope object. For configuration handlers,
8748
        * this will usually equal the owner.
8749
        */
8750
        configIcon: function (type,args,obj) {
8751
 
8752
            var sIcon = args[0],
8753
                oBody = this.body,
8754
                sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
8755
				aElements,
8756
                oIcon,
8757
                oIconParent;
8758
 
8759
            if (sIcon && sIcon != "none") {
8760
 
8761
                aElements = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
8762
 
8763
				if (aElements.length === 1) {
8764
 
8765
					oIcon = aElements[0];
8766
                    oIconParent = oIcon.parentNode;
8767
 
8768
                    if (oIconParent) {
8769
 
8770
                        oIconParent.removeChild(oIcon);
8771
 
8772
                        oIcon = null;
8773
 
8774
                    }
8775
 
8776
				}
8777
 
8778
 
8779
                if (sIcon.indexOf(".") == -1) {
8780
 
8781
                    oIcon = document.createElement("span");
8782
                    oIcon.className = (sCSSClass + " " + sIcon);
8783
                    oIcon.innerHTML = "&#160;";
8784
 
8785
                } else {
8786
 
8787
                    oIcon = document.createElement("img");
8788
                    oIcon.src = (this.imageRoot + sIcon);
8789
                    oIcon.className = sCSSClass;
8790
 
8791
                }
8792
 
8793
 
8794
                if (oIcon) {
8795
 
8796
                    oBody.insertBefore(oIcon, oBody.firstChild);
8797
 
8798
                }
8799
 
8800
            }
8801
 
8802
        },
8803
 
8804
        /**
8805
        * Fired when the "text" property is set.
8806
        * @method configText
8807
        * @param {String} type The CustomEvent type (usually the property name)
8808
        * @param {Object[]} args The CustomEvent arguments. For configuration
8809
        * handlers, args[0] will equal the newly applied value for the property.
8810
        * @param {Object} obj The scope object. For configuration handlers,
8811
        * this will usually equal the owner.
8812
        */
8813
        configText: function (type,args,obj) {
8814
            var text = args[0];
8815
            if (text) {
8816
                this.setBody(text);
8817
                this.cfg.refireEvent("icon");
8818
            }
8819
        },
8820
 
8821
        // END BUILT-IN PROPERTY EVENT HANDLERS //
8822
 
8823
        /**
8824
        * Returns a string representation of the object.
8825
        * @method toString
8826
        * @return {String} The string representation of the SimpleDialog
8827
        */
8828
        toString: function () {
8829
            return "SimpleDialog " + this.id;
8830
        }
8831
 
8832
        /**
8833
        * <p>
8834
        * Sets the SimpleDialog's body content to the HTML specified.
8835
        * If no body is present, one will be automatically created.
8836
        * An empty string can be passed to the method to clear the contents of the body.
8837
        * </p>
8838
        * <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
8839
        * and <a href="#config_icon">icon</a> configuration properties to set the contents
8840
        * of it's body element in accordance with the UI design for a SimpleDialog (an
8841
        * icon and message text). Calling setBody on the SimpleDialog will not enforce this
8842
        * UI design constraint and will replace the entire contents of the SimpleDialog body.
8843
        * It should only be used if you wish the replace the default icon/text body structure
8844
        * of a SimpleDialog with your own custom markup.</p>
8845
        *
8846
        * @method setBody
8847
        * @param {HTML} bodyContent The HTML used to set the body.
8848
        * As a convenience, non HTMLElement objects can also be passed into
8849
        * the method, and will be treated as strings, with the body innerHTML
8850
        * set to their default toString implementations.
8851
        *
8852
        * <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>
8853
        *
8854
        * <em>OR</em>
8855
        * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
8856
        * <em>OR</em>
8857
        * @param {DocumentFragment} bodyContent The document fragment
8858
        * containing elements which are to be added to the body
8859
        */
8860
    });
8861
 
8862
}());
8863
(function () {
8864
 
8865
    /**
8866
    * ContainerEffect encapsulates animation transitions that are executed when
8867
    * an Overlay is shown or hidden.
8868
    * @namespace YAHOO.widget
8869
    * @class ContainerEffect
8870
    * @constructor
8871
    * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
8872
    * should be associated with
8873
    * @param {Object} attrIn The object literal representing the animation
8874
    * arguments to be used for the animate-in transition. The arguments for
8875
    * this literal are: attributes(object, see YAHOO.util.Anim for description),
8876
    * duration(Number), and method(i.e. Easing.easeIn).
8877
    * @param {Object} attrOut The object literal representing the animation
8878
    * arguments to be used for the animate-out transition. The arguments for
8879
    * this literal are: attributes(object, see YAHOO.util.Anim for description),
8880
    * duration(Number), and method(i.e. Easing.easeIn).
8881
    * @param {HTMLElement} targetElement Optional. The target element that
8882
    * should be animated during the transition. Defaults to overlay.element.
8883
    * @param {class} Optional. The animation class to instantiate. Defaults to
8884
    * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
8885
    */
8886
    YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
8887
 
8888
        if (!animClass) {
8889
            animClass = YAHOO.util.Anim;
8890
        }
8891
 
8892
        /**
8893
        * The overlay to animate
8894
        * @property overlay
8895
        * @type YAHOO.widget.Overlay
8896
        */
8897
        this.overlay = overlay;
8898
 
8899
        /**
8900
        * The animation attributes to use when transitioning into view
8901
        * @property attrIn
8902
        * @type Object
8903
        */
8904
        this.attrIn = attrIn;
8905
 
8906
        /**
8907
        * The animation attributes to use when transitioning out of view
8908
        * @property attrOut
8909
        * @type Object
8910
        */
8911
        this.attrOut = attrOut;
8912
 
8913
        /**
8914
        * The target element to be animated
8915
        * @property targetElement
8916
        * @type HTMLElement
8917
        */
8918
        this.targetElement = targetElement || overlay.element;
8919
 
8920
        /**
8921
        * The animation class to use for animating the overlay
8922
        * @property animClass
8923
        * @type class
8924
        */
8925
        this.animClass = animClass;
8926
    };
8927
 
8928
    var Dom = YAHOO.util.Dom,
8929
        CustomEvent = YAHOO.util.CustomEvent,
8930
        ContainerEffect = YAHOO.widget.ContainerEffect;
8931
 
8932
    /**
8933
    * A pre-configured ContainerEffect instance that can be used for fading
8934
    * an overlay in and out.
8935
    * @method FADE
8936
    * @static
8937
    * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
8938
    * @param {Number} dur The duration of the animation
8939
    * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
8940
    */
8941
    ContainerEffect.FADE = function (overlay, dur) {
8942
 
8943
        var Easing = YAHOO.util.Easing,
8944
            fin = {
8945
                attributes: {opacity:{from:0, to:1}},
8946
                duration: dur,
8947
                method: Easing.easeIn
8948
            },
8949
            fout = {
8950
                attributes: {opacity:{to:0}},
8951
                duration: dur,
8952
                method: Easing.easeOut
8953
            },
8954
            fade = new ContainerEffect(overlay, fin, fout, overlay.element);
8955
 
8956
        fade.handleUnderlayStart = function() {
8957
            var underlay = this.overlay.underlay;
8958
            if (underlay && YAHOO.env.ua.ie) {
8959
                var hasFilters = (underlay.filters && underlay.filters.length > 0);
8960
                if(hasFilters) {
8961
                    Dom.addClass(overlay.element, "yui-effect-fade");
8962
                }
8963
            }
8964
        };
8965
 
8966
        fade.handleUnderlayComplete = function() {
8967
            var underlay = this.overlay.underlay;
8968
            if (underlay && YAHOO.env.ua.ie) {
8969
                Dom.removeClass(overlay.element, "yui-effect-fade");
8970
            }
8971
        };
8972
 
8973
        fade.handleStartAnimateIn = function (type, args, obj) {
8974
            obj.overlay._fadingIn = true;
8975
 
8976
            Dom.addClass(obj.overlay.element, "hide-select");
8977
 
8978
            if (!obj.overlay.underlay) {
8979
                obj.overlay.cfg.refireEvent("underlay");
8980
            }
8981
 
8982
            obj.handleUnderlayStart();
8983
 
8984
            obj.overlay._setDomVisibility(true);
8985
            Dom.setStyle(obj.overlay.element, "opacity", 0);
8986
        };
8987
 
8988
        fade.handleCompleteAnimateIn = function (type,args,obj) {
8989
            obj.overlay._fadingIn = false;
8990
 
8991
            Dom.removeClass(obj.overlay.element, "hide-select");
8992
 
8993
            if (obj.overlay.element.style.filter) {
8994
                obj.overlay.element.style.filter = null;
8995
            }
8996
 
8997
            obj.handleUnderlayComplete();
8998
 
8999
            obj.overlay.cfg.refireEvent("iframe");
9000
            obj.animateInCompleteEvent.fire();
9001
        };
9002
 
9003
        fade.handleStartAnimateOut = function (type, args, obj) {
9004
            obj.overlay._fadingOut = true;
9005
            Dom.addClass(obj.overlay.element, "hide-select");
9006
            obj.handleUnderlayStart();
9007
        };
9008
 
9009
        fade.handleCompleteAnimateOut =  function (type, args, obj) {
9010
            obj.overlay._fadingOut = false;
9011
            Dom.removeClass(obj.overlay.element, "hide-select");
9012
 
9013
            if (obj.overlay.element.style.filter) {
9014
                obj.overlay.element.style.filter = null;
9015
            }
9016
            obj.overlay._setDomVisibility(false);
9017
            Dom.setStyle(obj.overlay.element, "opacity", 1);
9018
 
9019
            obj.handleUnderlayComplete();
9020
 
9021
            obj.overlay.cfg.refireEvent("iframe");
9022
            obj.animateOutCompleteEvent.fire();
9023
        };
9024
 
9025
        fade.init();
9026
        return fade;
9027
    };
9028
 
9029
 
9030
    /**
9031
    * A pre-configured ContainerEffect instance that can be used for sliding an
9032
    * overlay in and out.
9033
    * @method SLIDE
9034
    * @static
9035
    * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
9036
    * @param {Number} dur The duration of the animation
9037
    * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
9038
    */
9039
    ContainerEffect.SLIDE = function (overlay, dur) {
9040
        var Easing = YAHOO.util.Easing,
9041
 
9042
            x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
9043
            y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
9044
            clientWidth = Dom.getClientWidth(),
9045
            offsetWidth = overlay.element.offsetWidth,
9046
 
9047
            sin =  {
9048
                attributes: { points: { to: [x, y] } },
9049
                duration: dur,
9050
                method: Easing.easeIn
9051
            },
9052
 
9053
            sout = {
9054
                attributes: { points: { to: [(clientWidth + 25), y] } },
9055
                duration: dur,
9056
                method: Easing.easeOut
9057
            },
9058
 
9059
            slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
9060
 
9061
        slide.handleStartAnimateIn = function (type,args,obj) {
9062
            obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
9063
            obj.overlay.element.style.top  = y + "px";
9064
        };
9065
 
9066
        slide.handleTweenAnimateIn = function (type, args, obj) {
9067
 
9068
            var pos = Dom.getXY(obj.overlay.element),
9069
                currentX = pos[0],
9070
                currentY = pos[1];
9071
 
9072
            if (Dom.getStyle(obj.overlay.element, "visibility") ==
9073
                "hidden" && currentX < x) {
9074
 
9075
                obj.overlay._setDomVisibility(true);
9076
 
9077
            }
9078
 
9079
            obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
9080
            obj.overlay.cfg.refireEvent("iframe");
9081
        };
9082
 
9083
        slide.handleCompleteAnimateIn = function (type, args, obj) {
9084
            obj.overlay.cfg.setProperty("xy", [x, y], true);
9085
            obj.startX = x;
9086
            obj.startY = y;
9087
            obj.overlay.cfg.refireEvent("iframe");
9088
            obj.animateInCompleteEvent.fire();
9089
        };
9090
 
9091
        slide.handleStartAnimateOut = function (type, args, obj) {
9092
 
9093
            var vw = Dom.getViewportWidth(),
9094
                pos = Dom.getXY(obj.overlay.element),
9095
                yso = pos[1];
9096
 
9097
            obj.animOut.attributes.points.to = [(vw + 25), yso];
9098
        };
9099
 
9100
        slide.handleTweenAnimateOut = function (type, args, obj) {
9101
 
9102
            var pos = Dom.getXY(obj.overlay.element),
9103
                xto = pos[0],
9104
                yto = pos[1];
9105
 
9106
            obj.overlay.cfg.setProperty("xy", [xto, yto], true);
9107
            obj.overlay.cfg.refireEvent("iframe");
9108
        };
9109
 
9110
        slide.handleCompleteAnimateOut = function (type, args, obj) {
9111
            obj.overlay._setDomVisibility(false);
9112
 
9113
            obj.overlay.cfg.setProperty("xy", [x, y]);
9114
            obj.animateOutCompleteEvent.fire();
9115
        };
9116
 
9117
        slide.init();
9118
        return slide;
9119
    };
9120
 
9121
    ContainerEffect.prototype = {
9122
 
9123
        /**
9124
        * Initializes the animation classes and events.
9125
        * @method init
9126
        */
9127
        init: function () {
9128
 
9129
            this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
9130
            this.beforeAnimateInEvent.signature = CustomEvent.LIST;
9131
 
9132
            this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
9133
            this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
9134
 
9135
            this.animateInCompleteEvent = this.createEvent("animateInComplete");
9136
            this.animateInCompleteEvent.signature = CustomEvent.LIST;
9137
 
9138
            this.animateOutCompleteEvent = this.createEvent("animateOutComplete");
9139
            this.animateOutCompleteEvent.signature = CustomEvent.LIST;
9140
 
9141
            this.animIn = new this.animClass(
9142
                this.targetElement,
9143
                this.attrIn.attributes,
9144
                this.attrIn.duration,
9145
                this.attrIn.method);
9146
 
9147
            this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
9148
            this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
9149
            this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);
9150
 
9151
            this.animOut = new this.animClass(
9152
                this.targetElement,
9153
                this.attrOut.attributes,
9154
                this.attrOut.duration,
9155
                this.attrOut.method);
9156
 
9157
            this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
9158
            this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
9159
            this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut, this);
9160
 
9161
        },
9162
 
9163
        /**
9164
        * Triggers the in-animation.
9165
        * @method animateIn
9166
        */
9167
        animateIn: function () {
9168
            this._stopAnims(this.lastFrameOnStop);
9169
            this.beforeAnimateInEvent.fire();
9170
            this.animIn.animate();
9171
        },
9172
 
9173
        /**
9174
        * Triggers the out-animation.
9175
        * @method animateOut
9176
        */
9177
        animateOut: function () {
9178
            this._stopAnims(this.lastFrameOnStop);
9179
            this.beforeAnimateOutEvent.fire();
9180
            this.animOut.animate();
9181
        },
9182
 
9183
        /**
9184
         * Flag to define whether Anim should jump to the last frame,
9185
         * when animateIn or animateOut is stopped.
9186
         *
9187
         * @property lastFrameOnStop
9188
         * @default true
9189
         * @type boolean
9190
         */
9191
        lastFrameOnStop : true,
9192
 
9193
        /**
9194
         * Stops both animIn and animOut instances, if in progress.
9195
         *
9196
         * @method _stopAnims
9197
         * @param {boolean} finish If true, animation will jump to final frame.
9198
         * @protected
9199
         */
9200
        _stopAnims : function(finish) {
9201
            if (this.animOut && this.animOut.isAnimated()) {
9202
                this.animOut.stop(finish);
9203
            }
9204
 
9205
            if (this.animIn && this.animIn.isAnimated()) {
9206
                this.animIn.stop(finish);
9207
            }
9208
        },
9209
 
9210
        /**
9211
        * The default onStart handler for the in-animation.
9212
        * @method handleStartAnimateIn
9213
        * @param {String} type The CustomEvent type
9214
        * @param {Object[]} args The CustomEvent arguments
9215
        * @param {Object} obj The scope object
9216
        */
9217
        handleStartAnimateIn: function (type, args, obj) { },
9218
 
9219
        /**
9220
        * The default onTween handler for the in-animation.
9221
        * @method handleTweenAnimateIn
9222
        * @param {String} type The CustomEvent type
9223
        * @param {Object[]} args The CustomEvent arguments
9224
        * @param {Object} obj The scope object
9225
        */
9226
        handleTweenAnimateIn: function (type, args, obj) { },
9227
 
9228
        /**
9229
        * The default onComplete handler for the in-animation.
9230
        * @method handleCompleteAnimateIn
9231
        * @param {String} type The CustomEvent type
9232
        * @param {Object[]} args The CustomEvent arguments
9233
        * @param {Object} obj The scope object
9234
        */
9235
        handleCompleteAnimateIn: function (type, args, obj) { },
9236
 
9237
        /**
9238
        * The default onStart handler for the out-animation.
9239
        * @method handleStartAnimateOut
9240
        * @param {String} type The CustomEvent type
9241
        * @param {Object[]} args The CustomEvent arguments
9242
        * @param {Object} obj The scope object
9243
        */
9244
        handleStartAnimateOut: function (type, args, obj) { },
9245
 
9246
        /**
9247
        * The default onTween handler for the out-animation.
9248
        * @method handleTweenAnimateOut
9249
        * @param {String} type The CustomEvent type
9250
        * @param {Object[]} args The CustomEvent arguments
9251
        * @param {Object} obj The scope object
9252
        */
9253
        handleTweenAnimateOut: function (type, args, obj) { },
9254
 
9255
        /**
9256
        * The default onComplete handler for the out-animation.
9257
        * @method handleCompleteAnimateOut
9258
        * @param {String} type The CustomEvent type
9259
        * @param {Object[]} args The CustomEvent arguments
9260
        * @param {Object} obj The scope object
9261
        */
9262
        handleCompleteAnimateOut: function (type, args, obj) { },
9263
 
9264
        /**
9265
        * Returns a string representation of the object.
9266
        * @method toString
9267
        * @return {String} The string representation of the ContainerEffect
9268
        */
9269
        toString: function () {
9270
            var output = "ContainerEffect";
9271
            if (this.overlay) {
9272
                output += " [" + this.overlay.toString() + "]";
9273
            }
9274
            return output;
9275
        }
9276
    };
9277
 
9278
    YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
9279
 
9280
})();
9281
YAHOO.register("container", YAHOO.widget.Module, {version: "2.9.0", build: "2800"});
9282
 
9283
}, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom", "yui2-event", "yui2-skin-sam-container"], "supersedes": ["yui2-containercore"], "optional": ["yui2-animation", "yui2-dragdrop", "yui2-connection"]});