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