~ubuntu-branches/ubuntu/natty/otrs2/natty-updates

« back to all changes in this revision

Viewing changes to var/httpd/htdocs/yui/2.7.0/build/calendar/calendar.js

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2010-08-09 19:43:44 UTC
  • mfrom: (1.1.12)
  • Revision ID: package-import@ubuntu.com-20100809194344-absef1ut5mfj3qhv
Tags: 2.4.7+dfsg1-1
* Strip out yui from the source in the dfsg version.
  Closes: #591196
* Depend on libjs-yui and link to this package, instead of using the embedded
  yui version. This changes make the flash ticket statistics unuseable!
  Closes: #592146

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3
 
Code licensed under the BSD License:
4
 
http://developer.yahoo.net/yui/license.txt
5
 
version: 2.7.0
6
 
*/
7
 
(function () {
8
 
 
9
 
    /**
10
 
    * Config is a utility used within an Object to allow the implementer to
11
 
    * maintain a list of local configuration properties and listen for changes 
12
 
    * to those properties dynamically using CustomEvent. The initial values are 
13
 
    * also maintained so that the configuration can be reset at any given point 
14
 
    * to its initial state.
15
 
    * @namespace YAHOO.util
16
 
    * @class Config
17
 
    * @constructor
18
 
    * @param {Object} owner The owner Object to which this Config Object belongs
19
 
    */
20
 
    YAHOO.util.Config = function (owner) {
21
 
 
22
 
        if (owner) {
23
 
            this.init(owner);
24
 
        }
25
 
 
26
 
 
27
 
    };
28
 
 
29
 
 
30
 
    var Lang = YAHOO.lang,
31
 
        CustomEvent = YAHOO.util.CustomEvent,
32
 
        Config = YAHOO.util.Config;
33
 
 
34
 
 
35
 
    /**
36
 
     * Constant representing the CustomEvent type for the config changed event.
37
 
     * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
38
 
     * @private
39
 
     * @static
40
 
     * @final
41
 
     */
42
 
    Config.CONFIG_CHANGED_EVENT = "configChanged";
43
 
    
44
 
    /**
45
 
     * Constant representing the boolean type string
46
 
     * @property YAHOO.util.Config.BOOLEAN_TYPE
47
 
     * @private
48
 
     * @static
49
 
     * @final
50
 
     */
51
 
    Config.BOOLEAN_TYPE = "boolean";
52
 
    
53
 
    Config.prototype = {
54
 
     
55
 
        /**
56
 
        * Object reference to the owner of this Config Object
57
 
        * @property owner
58
 
        * @type Object
59
 
        */
60
 
        owner: null,
61
 
        
62
 
        /**
63
 
        * Boolean flag that specifies whether a queue is currently 
64
 
        * being executed
65
 
        * @property queueInProgress
66
 
        * @type Boolean
67
 
        */
68
 
        queueInProgress: false,
69
 
        
70
 
        /**
71
 
        * Maintains the local collection of configuration property objects and 
72
 
        * their specified values
73
 
        * @property config
74
 
        * @private
75
 
        * @type Object
76
 
        */ 
77
 
        config: null,
78
 
        
79
 
        /**
80
 
        * Maintains the local collection of configuration property objects as 
81
 
        * they were initially applied.
82
 
        * This object is used when resetting a property.
83
 
        * @property initialConfig
84
 
        * @private
85
 
        * @type Object
86
 
        */ 
87
 
        initialConfig: null,
88
 
        
89
 
        /**
90
 
        * Maintains the local, normalized CustomEvent queue
91
 
        * @property eventQueue
92
 
        * @private
93
 
        * @type Object
94
 
        */ 
95
 
        eventQueue: null,
96
 
        
97
 
        /**
98
 
        * Custom Event, notifying subscribers when Config properties are set 
99
 
        * (setProperty is called without the silent flag
100
 
        * @event configChangedEvent
101
 
        */
102
 
        configChangedEvent: null,
103
 
    
104
 
        /**
105
 
        * Initializes the configuration Object and all of its local members.
106
 
        * @method init
107
 
        * @param {Object} owner The owner Object to which this Config 
108
 
        * Object belongs
109
 
        */
110
 
        init: function (owner) {
111
 
    
112
 
            this.owner = owner;
113
 
    
114
 
            this.configChangedEvent = 
115
 
                this.createEvent(Config.CONFIG_CHANGED_EVENT);
116
 
    
117
 
            this.configChangedEvent.signature = CustomEvent.LIST;
118
 
            this.queueInProgress = false;
119
 
            this.config = {};
120
 
            this.initialConfig = {};
121
 
            this.eventQueue = [];
122
 
        
123
 
        },
124
 
        
125
 
        /**
126
 
        * Validates that the value passed in is a Boolean.
127
 
        * @method checkBoolean
128
 
        * @param {Object} val The value to validate
129
 
        * @return {Boolean} true, if the value is valid
130
 
        */ 
131
 
        checkBoolean: function (val) {
132
 
            return (typeof val == Config.BOOLEAN_TYPE);
133
 
        },
134
 
        
135
 
        /**
136
 
        * Validates that the value passed in is a number.
137
 
        * @method checkNumber
138
 
        * @param {Object} val The value to validate
139
 
        * @return {Boolean} true, if the value is valid
140
 
        */
141
 
        checkNumber: function (val) {
142
 
            return (!isNaN(val));
143
 
        },
144
 
        
145
 
        /**
146
 
        * Fires a configuration property event using the specified value. 
147
 
        * @method fireEvent
148
 
        * @private
149
 
        * @param {String} key The configuration property's name
150
 
        * @param {value} Object The value of the correct type for the property
151
 
        */ 
152
 
        fireEvent: function ( key, value ) {
153
 
            var property = this.config[key];
154
 
        
155
 
            if (property && property.event) {
156
 
                property.event.fire(value);
157
 
            } 
158
 
        },
159
 
        
160
 
        /**
161
 
        * Adds a property to the Config Object's private config hash.
162
 
        * @method addProperty
163
 
        * @param {String} key The configuration property's name
164
 
        * @param {Object} propertyObject The Object containing all of this 
165
 
        * property's arguments
166
 
        */
167
 
        addProperty: function ( key, propertyObject ) {
168
 
            key = key.toLowerCase();
169
 
        
170
 
            this.config[key] = propertyObject;
171
 
        
172
 
            propertyObject.event = this.createEvent(key, { scope: this.owner });
173
 
            propertyObject.event.signature = CustomEvent.LIST;
174
 
            
175
 
            
176
 
            propertyObject.key = key;
177
 
        
178
 
            if (propertyObject.handler) {
179
 
                propertyObject.event.subscribe(propertyObject.handler, 
180
 
                    this.owner);
181
 
            }
182
 
        
183
 
            this.setProperty(key, propertyObject.value, true);
184
 
            
185
 
            if (! propertyObject.suppressEvent) {
186
 
                this.queueProperty(key, propertyObject.value);
187
 
            }
188
 
            
189
 
        },
190
 
        
191
 
        /**
192
 
        * Returns a key-value configuration map of the values currently set in  
193
 
        * the Config Object.
194
 
        * @method getConfig
195
 
        * @return {Object} The current config, represented in a key-value map
196
 
        */
197
 
        getConfig: function () {
198
 
        
199
 
            var cfg = {},
200
 
                currCfg = this.config,
201
 
                prop,
202
 
                property;
203
 
                
204
 
            for (prop in currCfg) {
205
 
                if (Lang.hasOwnProperty(currCfg, prop)) {
206
 
                    property = currCfg[prop];
207
 
                    if (property && property.event) {
208
 
                        cfg[prop] = property.value;
209
 
                    }
210
 
                }
211
 
            }
212
 
 
213
 
            return cfg;
214
 
        },
215
 
        
216
 
        /**
217
 
        * Returns the value of specified property.
218
 
        * @method getProperty
219
 
        * @param {String} key The name of the property
220
 
        * @return {Object}  The value of the specified property
221
 
        */
222
 
        getProperty: function (key) {
223
 
            var property = this.config[key.toLowerCase()];
224
 
            if (property && property.event) {
225
 
                return property.value;
226
 
            } else {
227
 
                return undefined;
228
 
            }
229
 
        },
230
 
        
231
 
        /**
232
 
        * Resets the specified property's value to its initial value.
233
 
        * @method resetProperty
234
 
        * @param {String} key The name of the property
235
 
        * @return {Boolean} True is the property was reset, false if not
236
 
        */
237
 
        resetProperty: function (key) {
238
 
    
239
 
            key = key.toLowerCase();
240
 
        
241
 
            var property = this.config[key];
242
 
    
243
 
            if (property && property.event) {
244
 
    
245
 
                if (this.initialConfig[key] && 
246
 
                    !Lang.isUndefined(this.initialConfig[key])) {
247
 
    
248
 
                    this.setProperty(key, this.initialConfig[key]);
249
 
 
250
 
                    return true;
251
 
    
252
 
                }
253
 
    
254
 
            } else {
255
 
    
256
 
                return false;
257
 
            }
258
 
    
259
 
        },
260
 
        
261
 
        /**
262
 
        * Sets the value of a property. If the silent property is passed as 
263
 
        * true, the property's event will not be fired.
264
 
        * @method setProperty
265
 
        * @param {String} key The name of the property
266
 
        * @param {String} value The value to set the property to
267
 
        * @param {Boolean} silent Whether the value should be set silently, 
268
 
        * without firing the property event.
269
 
        * @return {Boolean} True, if the set was successful, false if it failed.
270
 
        */
271
 
        setProperty: function (key, value, silent) {
272
 
        
273
 
            var property;
274
 
        
275
 
            key = key.toLowerCase();
276
 
        
277
 
            if (this.queueInProgress && ! silent) {
278
 
                // Currently running through a queue... 
279
 
                this.queueProperty(key,value);
280
 
                return true;
281
 
    
282
 
            } else {
283
 
                property = this.config[key];
284
 
                if (property && property.event) {
285
 
                    if (property.validator && !property.validator(value)) {
286
 
                        return false;
287
 
                    } else {
288
 
                        property.value = value;
289
 
                        if (! silent) {
290
 
                            this.fireEvent(key, value);
291
 
                            this.configChangedEvent.fire([key, value]);
292
 
                        }
293
 
                        return true;
294
 
                    }
295
 
                } else {
296
 
                    return false;
297
 
                }
298
 
            }
299
 
        },
300
 
        
301
 
        /**
302
 
        * Sets the value of a property and queues its event to execute. If the 
303
 
        * event is already scheduled to execute, it is
304
 
        * moved from its current position to the end of the queue.
305
 
        * @method queueProperty
306
 
        * @param {String} key The name of the property
307
 
        * @param {String} value The value to set the property to
308
 
        * @return {Boolean}  true, if the set was successful, false if 
309
 
        * it failed.
310
 
        */ 
311
 
        queueProperty: function (key, value) {
312
 
        
313
 
            key = key.toLowerCase();
314
 
        
315
 
            var property = this.config[key],
316
 
                foundDuplicate = false,
317
 
                iLen,
318
 
                queueItem,
319
 
                queueItemKey,
320
 
                queueItemValue,
321
 
                sLen,
322
 
                supercedesCheck,
323
 
                qLen,
324
 
                queueItemCheck,
325
 
                queueItemCheckKey,
326
 
                queueItemCheckValue,
327
 
                i,
328
 
                s,
329
 
                q;
330
 
                                
331
 
            if (property && property.event) {
332
 
    
333
 
                if (!Lang.isUndefined(value) && property.validator && 
334
 
                    !property.validator(value)) { // validator
335
 
                    return false;
336
 
                } else {
337
 
        
338
 
                    if (!Lang.isUndefined(value)) {
339
 
                        property.value = value;
340
 
                    } else {
341
 
                        value = property.value;
342
 
                    }
343
 
        
344
 
                    foundDuplicate = false;
345
 
                    iLen = this.eventQueue.length;
346
 
        
347
 
                    for (i = 0; i < iLen; i++) {
348
 
                        queueItem = this.eventQueue[i];
349
 
        
350
 
                        if (queueItem) {
351
 
                            queueItemKey = queueItem[0];
352
 
                            queueItemValue = queueItem[1];
353
 
 
354
 
                            if (queueItemKey == key) {
355
 
    
356
 
                                /*
357
 
                                    found a dupe... push to end of queue, null 
358
 
                                    current item, and break
359
 
                                */
360
 
    
361
 
                                this.eventQueue[i] = null;
362
 
    
363
 
                                this.eventQueue.push(
364
 
                                    [key, (!Lang.isUndefined(value) ? 
365
 
                                    value : queueItemValue)]);
366
 
    
367
 
                                foundDuplicate = true;
368
 
                                break;
369
 
                            }
370
 
                        }
371
 
                    }
372
 
                    
373
 
                    // this is a refire, or a new property in the queue
374
 
    
375
 
                    if (! foundDuplicate && !Lang.isUndefined(value)) { 
376
 
                        this.eventQueue.push([key, value]);
377
 
                    }
378
 
                }
379
 
        
380
 
                if (property.supercedes) {
381
 
 
382
 
                    sLen = property.supercedes.length;
383
 
 
384
 
                    for (s = 0; s < sLen; s++) {
385
 
 
386
 
                        supercedesCheck = property.supercedes[s];
387
 
                        qLen = this.eventQueue.length;
388
 
 
389
 
                        for (q = 0; q < qLen; q++) {
390
 
                            queueItemCheck = this.eventQueue[q];
391
 
 
392
 
                            if (queueItemCheck) {
393
 
                                queueItemCheckKey = queueItemCheck[0];
394
 
                                queueItemCheckValue = queueItemCheck[1];
395
 
 
396
 
                                if (queueItemCheckKey == 
397
 
                                    supercedesCheck.toLowerCase() ) {
398
 
 
399
 
                                    this.eventQueue.push([queueItemCheckKey, 
400
 
                                        queueItemCheckValue]);
401
 
 
402
 
                                    this.eventQueue[q] = null;
403
 
                                    break;
404
 
 
405
 
                                }
406
 
                            }
407
 
                        }
408
 
                    }
409
 
                }
410
 
 
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} override Optional. If true, will override "this"  
541
 
        * within the handler to map to the scope Object passed into the method.
542
 
        * @return {Boolean} True, if the subscription was successful, 
543
 
        * otherwise false.
544
 
        */ 
545
 
        subscribeToConfigEvent: function (key, handler, obj, override) {
546
 
    
547
 
            var property = this.config[key.toLowerCase()];
548
 
    
549
 
            if (property && property.event) {
550
 
                if (!Config.alreadySubscribed(property.event, handler, obj)) {
551
 
                    property.event.subscribe(handler, obj, override);
552
 
                }
553
 
                return true;
554
 
            } else {
555
 
                return false;
556
 
            }
557
 
    
558
 
        },
559
 
        
560
 
        /**
561
 
        * Unsubscribes an external handler from the change event for any 
562
 
        * given property. 
563
 
        * @method unsubscribeFromConfigEvent
564
 
        * @param {String} key The property name
565
 
        * @param {Function} handler The handler function to use subscribe to 
566
 
        * the property's event
567
 
        * @param {Object} obj The Object to use for scoping the event 
568
 
        * handler (see CustomEvent documentation)
569
 
        * @return {Boolean} True, if the unsubscription was successful, 
570
 
        * otherwise false.
571
 
        */
572
 
        unsubscribeFromConfigEvent: function (key, handler, obj) {
573
 
            var property = this.config[key.toLowerCase()];
574
 
            if (property && property.event) {
575
 
                return property.event.unsubscribe(handler, obj);
576
 
            } else {
577
 
                return false;
578
 
            }
579
 
        },
580
 
        
581
 
        /**
582
 
        * Returns a string representation of the Config object
583
 
        * @method toString
584
 
        * @return {String} The Config object in string format.
585
 
        */
586
 
        toString: function () {
587
 
            var output = "Config";
588
 
            if (this.owner) {
589
 
                output += " [" + this.owner.toString() + "]";
590
 
            }
591
 
            return output;
592
 
        },
593
 
        
594
 
        /**
595
 
        * Returns a string representation of the Config object's current 
596
 
        * CustomEvent queue
597
 
        * @method outputEventQueue
598
 
        * @return {String} The string list of CustomEvents currently queued 
599
 
        * for execution
600
 
        */
601
 
        outputEventQueue: function () {
602
 
 
603
 
            var output = "",
604
 
                queueItem,
605
 
                q,
606
 
                nQueue = this.eventQueue.length;
607
 
              
608
 
            for (q = 0; q < nQueue; q++) {
609
 
                queueItem = this.eventQueue[q];
610
 
                if (queueItem) {
611
 
                    output += queueItem[0] + "=" + queueItem[1] + ", ";
612
 
                }
613
 
            }
614
 
            return output;
615
 
        },
616
 
 
617
 
        /**
618
 
        * Sets all properties to null, unsubscribes all listeners from each 
619
 
        * property's change event and all listeners from the configChangedEvent.
620
 
        * @method destroy
621
 
        */
622
 
        destroy: function () {
623
 
 
624
 
            var oConfig = this.config,
625
 
                sProperty,
626
 
                oProperty;
627
 
 
628
 
 
629
 
            for (sProperty in oConfig) {
630
 
            
631
 
                if (Lang.hasOwnProperty(oConfig, sProperty)) {
632
 
 
633
 
                    oProperty = oConfig[sProperty];
634
 
 
635
 
                    oProperty.event.unsubscribeAll();
636
 
                    oProperty.event = null;
637
 
 
638
 
                }
639
 
            
640
 
            }
641
 
            
642
 
            this.configChangedEvent.unsubscribeAll();
643
 
            
644
 
            this.configChangedEvent = null;
645
 
            this.owner = null;
646
 
            this.config = null;
647
 
            this.initialConfig = null;
648
 
            this.eventQueue = null;
649
 
        
650
 
        }
651
 
 
652
 
    };
653
 
    
654
 
    
655
 
    
656
 
    /**
657
 
    * Checks to determine if a particular function/Object pair are already 
658
 
    * subscribed to the specified CustomEvent
659
 
    * @method YAHOO.util.Config.alreadySubscribed
660
 
    * @static
661
 
    * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check 
662
 
    * the subscriptions
663
 
    * @param {Function} fn The function to look for in the subscribers list
664
 
    * @param {Object} obj The execution scope Object for the subscription
665
 
    * @return {Boolean} true, if the function/Object pair is already subscribed 
666
 
    * to the CustomEvent passed in
667
 
    */
668
 
    Config.alreadySubscribed = function (evt, fn, obj) {
669
 
    
670
 
        var nSubscribers = evt.subscribers.length,
671
 
            subsc,
672
 
            i;
673
 
 
674
 
        if (nSubscribers > 0) {
675
 
            i = nSubscribers - 1;
676
 
            do {
677
 
                subsc = evt.subscribers[i];
678
 
                if (subsc && subsc.obj == obj && subsc.fn == fn) {
679
 
                    return true;
680
 
                }
681
 
            }
682
 
            while (i--);
683
 
        }
684
 
 
685
 
        return false;
686
 
 
687
 
    };
688
 
 
689
 
    YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
690
 
 
691
 
}());
692
 
/**
693
 
* YAHOO.widget.DateMath is used for simple date manipulation. The class is a static utility
694
 
* used for adding, subtracting, and comparing dates.
695
 
* @namespace YAHOO.widget
696
 
* @class DateMath
697
 
*/
698
 
YAHOO.widget.DateMath = {
699
 
        /**
700
 
        * Constant field representing Day
701
 
        * @property DAY
702
 
        * @static
703
 
        * @final
704
 
        * @type String
705
 
        */
706
 
        DAY : "D",
707
 
 
708
 
        /**
709
 
        * Constant field representing Week
710
 
        * @property WEEK
711
 
        * @static
712
 
        * @final
713
 
        * @type String
714
 
        */
715
 
        WEEK : "W",
716
 
 
717
 
        /**
718
 
        * Constant field representing Year
719
 
        * @property YEAR
720
 
        * @static
721
 
        * @final
722
 
        * @type String
723
 
        */
724
 
        YEAR : "Y",
725
 
 
726
 
        /**
727
 
        * Constant field representing Month
728
 
        * @property MONTH
729
 
        * @static
730
 
        * @final
731
 
        * @type String
732
 
        */
733
 
        MONTH : "M",
734
 
 
735
 
        /**
736
 
        * Constant field representing one day, in milliseconds
737
 
        * @property ONE_DAY_MS
738
 
        * @static
739
 
        * @final
740
 
        * @type Number
741
 
        */
742
 
        ONE_DAY_MS : 1000*60*60*24,
743
 
        
744
 
        /**
745
 
         * Constant field representing the date in first week of January
746
 
         * which identifies the first week of the year.
747
 
         * <p>
748
 
         * In the U.S, Jan 1st is normally used based on a Sunday start of week.
749
 
         * ISO 8601, used widely throughout Europe, uses Jan 4th, based on a Monday start of week.
750
 
         * </p>
751
 
         * @property WEEK_ONE_JAN_DATE
752
 
         * @static
753
 
         * @type Number
754
 
         */
755
 
        WEEK_ONE_JAN_DATE : 1,
756
 
 
757
 
        /**
758
 
        * Adds the specified amount of time to the this instance.
759
 
        * @method add
760
 
        * @param {Date} date    The JavaScript Date object to perform addition on
761
 
        * @param {String} field The field constant to be used for performing addition.
762
 
        * @param {Number} amount        The number of units (measured in the field constant) to add to the date.
763
 
        * @return {Date} The resulting Date object
764
 
        */
765
 
        add : function(date, field, amount) {
766
 
                var d = new Date(date.getTime());
767
 
                switch (field) {
768
 
                        case this.MONTH:
769
 
                                var newMonth = date.getMonth() + amount;
770
 
                                var years = 0;
771
 
 
772
 
                                if (newMonth < 0) {
773
 
                                        while (newMonth < 0) {
774
 
                                                newMonth += 12;
775
 
                                                years -= 1;
776
 
                                        }
777
 
                                } else if (newMonth > 11) {
778
 
                                        while (newMonth > 11) {
779
 
                                                newMonth -= 12;
780
 
                                                years += 1;
781
 
                                        }
782
 
                                }
783
 
 
784
 
                                d.setMonth(newMonth);
785
 
                                d.setFullYear(date.getFullYear() + years);
786
 
                                break;
787
 
                        case this.DAY:
788
 
                                this._addDays(d, amount);
789
 
                                // d.setDate(date.getDate() + amount);
790
 
                                break;
791
 
                        case this.YEAR:
792
 
                                d.setFullYear(date.getFullYear() + amount);
793
 
                                break;
794
 
                        case this.WEEK:
795
 
                                this._addDays(d, (amount * 7));
796
 
                                // d.setDate(date.getDate() + (amount * 7));
797
 
                                break;
798
 
                }
799
 
                return d;
800
 
        },
801
 
 
802
 
        /**
803
 
         * Private helper method to account for bug in Safari 2 (webkit < 420)
804
 
         * when Date.setDate(n) is called with n less than -128 or greater than 127.
805
 
         * <p>
806
 
         * Fix approach and original findings are available here:
807
 
         * http://brianary.blogspot.com/2006/03/safari-date-bug.html
808
 
         * </p>
809
 
         * @method _addDays
810
 
         * @param {Date} d JavaScript date object
811
 
         * @param {Number} nDays The number of days to add to the date object (can be negative)
812
 
         * @private
813
 
         */
814
 
        _addDays : function(d, nDays) {
815
 
                if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420) {
816
 
                        if (nDays < 0) {
817
 
                                // Ensure we don't go below -128 (getDate() is always 1 to 31, so we won't go above 127)
818
 
                                for(var min = -128; nDays < min; nDays -= min) {
819
 
                                        d.setDate(d.getDate() + min);
820
 
                                }
821
 
                        } else {
822
 
                                // Ensure we don't go above 96 + 31 = 127
823
 
                                for(var max = 96; nDays > max; nDays -= max) {
824
 
                                        d.setDate(d.getDate() + max);
825
 
                                }
826
 
                        }
827
 
                        // nDays should be remainder between -128 and 96
828
 
                }
829
 
                d.setDate(d.getDate() + nDays);
830
 
        },
831
 
 
832
 
        /**
833
 
        * Subtracts the specified amount of time from the this instance.
834
 
        * @method subtract
835
 
        * @param {Date} date    The JavaScript Date object to perform subtraction on
836
 
        * @param {Number} field The this field constant to be used for performing subtraction.
837
 
        * @param {Number} amount        The number of units (measured in the field constant) to subtract from the date.
838
 
        * @return {Date} The resulting Date object
839
 
        */
840
 
        subtract : function(date, field, amount) {
841
 
                return this.add(date, field, (amount*-1));
842
 
        },
843
 
 
844
 
        /**
845
 
        * Determines whether a given date is before another date on the calendar.
846
 
        * @method before
847
 
        * @param {Date} date            The Date object to compare with the compare argument
848
 
        * @param {Date} compareTo       The Date object to use for the comparison
849
 
        * @return {Boolean} true if the date occurs before the compared date; false if not.
850
 
        */
851
 
        before : function(date, compareTo) {
852
 
                var ms = compareTo.getTime();
853
 
                if (date.getTime() < ms) {
854
 
                        return true;
855
 
                } else {
856
 
                        return false;
857
 
                }
858
 
        },
859
 
 
860
 
        /**
861
 
        * Determines whether a given date is after another date on the calendar.
862
 
        * @method after
863
 
        * @param {Date} date            The Date object to compare with the compare argument
864
 
        * @param {Date} compareTo       The Date object to use for the comparison
865
 
        * @return {Boolean} true if the date occurs after the compared date; false if not.
866
 
        */
867
 
        after : function(date, compareTo) {
868
 
                var ms = compareTo.getTime();
869
 
                if (date.getTime() > ms) {
870
 
                        return true;
871
 
                } else {
872
 
                        return false;
873
 
                }
874
 
        },
875
 
 
876
 
        /**
877
 
        * Determines whether a given date is between two other dates on the calendar.
878
 
        * @method between
879
 
        * @param {Date} date            The date to check for
880
 
        * @param {Date} dateBegin       The start of the range
881
 
        * @param {Date} dateEnd         The end of the range
882
 
        * @return {Boolean} true if the date occurs between the compared dates; false if not.
883
 
        */
884
 
        between : function(date, dateBegin, dateEnd) {
885
 
                if (this.after(date, dateBegin) && this.before(date, dateEnd)) {
886
 
                        return true;
887
 
                } else {
888
 
                        return false;
889
 
                }
890
 
        },
891
 
        
892
 
        /**
893
 
        * Retrieves a JavaScript Date object representing January 1 of any given year.
894
 
        * @method getJan1
895
 
        * @param {Number} calendarYear          The calendar year for which to retrieve January 1
896
 
        * @return {Date}        January 1 of the calendar year specified.
897
 
        */
898
 
        getJan1 : function(calendarYear) {
899
 
                return this.getDate(calendarYear,0,1);
900
 
        },
901
 
 
902
 
        /**
903
 
        * Calculates the number of days the specified date is from January 1 of the specified calendar year.
904
 
        * Passing January 1 to this function would return an offset value of zero.
905
 
        * @method getDayOffset
906
 
        * @param {Date} date    The JavaScript date for which to find the offset
907
 
        * @param {Number} calendarYear  The calendar year to use for determining the offset
908
 
        * @return {Number}      The number of days since January 1 of the given year
909
 
        */
910
 
        getDayOffset : function(date, calendarYear) {
911
 
                var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
912
 
                
913
 
                // Find the number of days the passed in date is away from the calendar year start
914
 
                var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
915
 
                return dayOffset;
916
 
        },
917
 
 
918
 
        /**
919
 
        * Calculates the week number for the given date. Can currently support standard
920
 
        * U.S. week numbers, based on Jan 1st defining the 1st week of the year, and 
921
 
        * ISO8601 week numbers, based on Jan 4th defining the 1st week of the year.
922
 
        * 
923
 
        * @method getWeekNumber
924
 
        * @param {Date} date The JavaScript date for which to find the week number
925
 
        * @param {Number} firstDayOfWeek The index of the first day of the week (0 = Sun, 1 = Mon ... 6 = Sat).
926
 
        * Defaults to 0
927
 
        * @param {Number} janDate The date in the first week of January which defines week one for the year
928
 
        * Defaults to the value of YAHOO.widget.DateMath.WEEK_ONE_JAN_DATE, which is 1 (Jan 1st). 
929
 
        * For the U.S, this is normally Jan 1st. ISO8601 uses Jan 4th to define the first week of the year.
930
 
        * 
931
 
        * @return {Number} The number of the week containing the given date.
932
 
        */
933
 
        getWeekNumber : function(date, firstDayOfWeek, janDate) {
934
 
 
935
 
                // Setup Defaults
936
 
                firstDayOfWeek = firstDayOfWeek || 0;
937
 
                janDate = janDate || this.WEEK_ONE_JAN_DATE;
938
 
 
939
 
                var targetDate = this.clearTime(date),
940
 
                        startOfWeek,
941
 
                        endOfWeek;
942
 
 
943
 
                if (targetDate.getDay() === firstDayOfWeek) { 
944
 
                        startOfWeek = targetDate;
945
 
                } else {
946
 
                        startOfWeek = this.getFirstDayOfWeek(targetDate, firstDayOfWeek);
947
 
                }
948
 
 
949
 
                var startYear = startOfWeek.getFullYear(),
950
 
                        startTime = startOfWeek.getTime();
951
 
 
952
 
                // DST shouldn't be a problem here, math is quicker than setDate();
953
 
                endOfWeek = new Date(startOfWeek.getTime() + 6*this.ONE_DAY_MS);
954
 
 
955
 
                var weekNum;
956
 
                if (startYear !== endOfWeek.getFullYear() && endOfWeek.getDate() >= janDate) {
957
 
                        // If years don't match, endOfWeek is in Jan. and if the 
958
 
                        // week has WEEK_ONE_JAN_DATE in it, it's week one by definition.
959
 
                        weekNum = 1;
960
 
                } else {
961
 
                        // Get the 1st day of the 1st week, and 
962
 
                        // find how many days away we are from it.
963
 
                        var weekOne = this.clearTime(this.getDate(startYear, 0, janDate)),
964
 
                                weekOneDayOne = this.getFirstDayOfWeek(weekOne, firstDayOfWeek);
965
 
 
966
 
                        // Round days to smoothen out 1 hr DST diff
967
 
                        var daysDiff  = Math.round((targetDate.getTime() - weekOneDayOne.getTime())/this.ONE_DAY_MS);
968
 
 
969
 
                        // Calc. Full Weeks
970
 
                        var rem = daysDiff % 7;
971
 
                        var weeksDiff = (daysDiff - rem)/7;
972
 
                        weekNum = weeksDiff + 1;
973
 
                }
974
 
                return weekNum;
975
 
        },
976
 
 
977
 
        /**
978
 
         * Get the first day of the week, for the give date. 
979
 
         * @param {Date} dt The date in the week for which the first day is required.
980
 
         * @param {Number} startOfWeek The index for the first day of the week, 0 = Sun, 1 = Mon ... 6 = Sat (defaults to 0)
981
 
         * @return {Date} The first day of the week
982
 
         */
983
 
        getFirstDayOfWeek : function (dt, startOfWeek) {
984
 
                startOfWeek = startOfWeek || 0;
985
 
                var dayOfWeekIndex = dt.getDay(),
986
 
                        dayOfWeek = (dayOfWeekIndex - startOfWeek + 7) % 7;
987
 
 
988
 
                return this.subtract(dt, this.DAY, dayOfWeek);
989
 
        },
990
 
 
991
 
        /**
992
 
        * Determines if a given week overlaps two different years.
993
 
        * @method isYearOverlapWeek
994
 
        * @param {Date} weekBeginDate   The JavaScript Date representing the first day of the week.
995
 
        * @return {Boolean}     true if the date overlaps two different years.
996
 
        */
997
 
        isYearOverlapWeek : function(weekBeginDate) {
998
 
                var overlaps = false;
999
 
                var nextWeek = this.add(weekBeginDate, this.DAY, 6);
1000
 
                if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
1001
 
                        overlaps = true;
1002
 
                }
1003
 
                return overlaps;
1004
 
        },
1005
 
 
1006
 
        /**
1007
 
        * Determines if a given week overlaps two different months.
1008
 
        * @method isMonthOverlapWeek
1009
 
        * @param {Date} weekBeginDate   The JavaScript Date representing the first day of the week.
1010
 
        * @return {Boolean}     true if the date overlaps two different months.
1011
 
        */
1012
 
        isMonthOverlapWeek : function(weekBeginDate) {
1013
 
                var overlaps = false;
1014
 
                var nextWeek = this.add(weekBeginDate, this.DAY, 6);
1015
 
                if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
1016
 
                        overlaps = true;
1017
 
                }
1018
 
                return overlaps;
1019
 
        },
1020
 
 
1021
 
        /**
1022
 
        * Gets the first day of a month containing a given date.
1023
 
        * @method findMonthStart
1024
 
        * @param {Date} date    The JavaScript Date used to calculate the month start
1025
 
        * @return {Date}                The JavaScript Date representing the first day of the month
1026
 
        */
1027
 
        findMonthStart : function(date) {
1028
 
                var start = this.getDate(date.getFullYear(), date.getMonth(), 1);
1029
 
                return start;
1030
 
        },
1031
 
 
1032
 
        /**
1033
 
        * Gets the last day of a month containing a given date.
1034
 
        * @method findMonthEnd
1035
 
        * @param {Date} date    The JavaScript Date used to calculate the month end
1036
 
        * @return {Date}                The JavaScript Date representing the last day of the month
1037
 
        */
1038
 
        findMonthEnd : function(date) {
1039
 
                var start = this.findMonthStart(date);
1040
 
                var nextMonth = this.add(start, this.MONTH, 1);
1041
 
                var end = this.subtract(nextMonth, this.DAY, 1);
1042
 
                return end;
1043
 
        },
1044
 
 
1045
 
        /**
1046
 
        * Clears the time fields from a given date, effectively setting the time to 12 noon.
1047
 
        * @method clearTime
1048
 
        * @param {Date} date    The JavaScript Date for which the time fields will be cleared
1049
 
        * @return {Date}                The JavaScript Date cleared of all time fields
1050
 
        */
1051
 
        clearTime : function(date) {
1052
 
                date.setHours(12,0,0,0);
1053
 
                return date;
1054
 
        },
1055
 
 
1056
 
        /**
1057
 
         * Returns a new JavaScript Date object, representing the given year, month and date. Time fields (hr, min, sec, ms) on the new Date object
1058
 
         * are set to 0. The method allows Date instances to be created with the a year less than 100. "new Date(year, month, date)" implementations 
1059
 
         * set the year to 19xx if a year (xx) which is less than 100 is provided.
1060
 
         * <p>
1061
 
         * <em>NOTE:</em>Validation on argument values is not performed. It is the caller's responsibility to ensure
1062
 
         * arguments are valid as per the ECMAScript-262 Date object specification for the new Date(year, month[, date]) constructor.
1063
 
         * </p>
1064
 
         * @method getDate
1065
 
         * @param {Number} y Year.
1066
 
         * @param {Number} m Month index from 0 (Jan) to 11 (Dec).
1067
 
         * @param {Number} d (optional) Date from 1 to 31. If not provided, defaults to 1.
1068
 
         * @return {Date} The JavaScript date object with year, month, date set as provided.
1069
 
         */
1070
 
        getDate : function(y, m, d) {
1071
 
                var dt = null;
1072
 
                if (YAHOO.lang.isUndefined(d)) {
1073
 
                        d = 1;
1074
 
                }
1075
 
                if (y >= 100) {
1076
 
                        dt = new Date(y, m, d);
1077
 
                } else {
1078
 
                        dt = new Date();
1079
 
                        dt.setFullYear(y);
1080
 
                        dt.setMonth(m);
1081
 
                        dt.setDate(d);
1082
 
                        dt.setHours(0,0,0,0);
1083
 
                }
1084
 
                return dt;
1085
 
        }
1086
 
};
1087
 
 
1088
 
/**
1089
 
* The Calendar component is a UI control that enables users to choose one or more dates from a graphical calendar presented in a one-month or
1090
 
* multi-month interface. Calendars are generated entirely via script and can be navigated without any page refreshes.
1091
 
* @module    calendar
1092
 
* @title    Calendar
1093
 
* @namespace  YAHOO.widget
1094
 
* @requires  yahoo,dom,event
1095
 
*/
1096
 
(function(){
1097
 
 
1098
 
        var Dom = YAHOO.util.Dom,
1099
 
                Event = YAHOO.util.Event,
1100
 
                Lang = YAHOO.lang,
1101
 
                DateMath = YAHOO.widget.DateMath;
1102
 
 
1103
 
/**
1104
 
* Calendar is the base class for the Calendar widget. In its most basic
1105
 
* implementation, it has the ability to render a calendar widget on the page
1106
 
* that can be manipulated to select a single date, move back and forth between
1107
 
* months and years.
1108
 
* <p>To construct the placeholder for the calendar widget, the code is as
1109
 
* follows:
1110
 
*       <xmp>
1111
 
*               <div id="calContainer"></div>
1112
 
*       </xmp>
1113
 
* </p>
1114
 
* <p>
1115
 
* <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
1116
 
* The Calendar can be constructed by simply providing a container ID string, 
1117
 
* or a reference to a container DIV HTMLElement (the element needs to exist 
1118
 
* in the document).
1119
 
1120
 
* E.g.:
1121
 
*       <xmp>
1122
 
*               var c = new YAHOO.widget.Calendar("calContainer", configOptions);
1123
 
*       </xmp>
1124
 
* or:
1125
 
*   <xmp>
1126
 
*       var containerDiv = YAHOO.util.Dom.get("calContainer");
1127
 
*               var c = new YAHOO.widget.Calendar(containerDiv, configOptions);
1128
 
*       </xmp>
1129
 
* </p>
1130
 
* <p>
1131
 
* If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
1132
 
* For example if an ID is not provided, and the container's ID is "calContainer", the Calendar's ID will be set to "calContainer_t".
1133
 
* </p>
1134
 
1135
 
* @namespace YAHOO.widget
1136
 
* @class Calendar
1137
 
* @constructor
1138
 
* @param {String} id optional The id of the table element that will represent the Calendar widget. As of 2.4.0, this argument is optional.
1139
 
* @param {String | HTMLElement} container The id of the container div element that will wrap the Calendar table, or a reference to a DIV element which exists in the document.
1140
 
* @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
1141
 
*/
1142
 
function Calendar(id, containerId, config) {
1143
 
        this.init.apply(this, arguments);
1144
 
}
1145
 
 
1146
 
/**
1147
 
* The path to be used for images loaded for the Calendar
1148
 
* @property YAHOO.widget.Calendar.IMG_ROOT
1149
 
* @static
1150
 
* @deprecated   You can now customize images by overriding the calclose, calnavleft and calnavright default CSS classes for the close icon, left arrow and right arrow respectively
1151
 
* @type String
1152
 
*/
1153
 
Calendar.IMG_ROOT = null;
1154
 
 
1155
 
/**
1156
 
* Type constant used for renderers to represent an individual date (M/D/Y)
1157
 
* @property YAHOO.widget.Calendar.DATE
1158
 
* @static
1159
 
* @final
1160
 
* @type String
1161
 
*/
1162
 
Calendar.DATE = "D";
1163
 
 
1164
 
/**
1165
 
* Type constant used for renderers to represent an individual date across any year (M/D)
1166
 
* @property YAHOO.widget.Calendar.MONTH_DAY
1167
 
* @static
1168
 
* @final
1169
 
* @type String
1170
 
*/
1171
 
Calendar.MONTH_DAY = "MD";
1172
 
 
1173
 
/**
1174
 
* Type constant used for renderers to represent a weekday
1175
 
* @property YAHOO.widget.Calendar.WEEKDAY
1176
 
* @static
1177
 
* @final
1178
 
* @type String
1179
 
*/
1180
 
Calendar.WEEKDAY = "WD";
1181
 
 
1182
 
/**
1183
 
* Type constant used for renderers to represent a range of individual dates (M/D/Y-M/D/Y)
1184
 
* @property YAHOO.widget.Calendar.RANGE
1185
 
* @static
1186
 
* @final
1187
 
* @type String
1188
 
*/
1189
 
Calendar.RANGE = "R";
1190
 
 
1191
 
/**
1192
 
* Type constant used for renderers to represent a month across any year
1193
 
* @property YAHOO.widget.Calendar.MONTH
1194
 
* @static
1195
 
* @final
1196
 
* @type String
1197
 
*/
1198
 
Calendar.MONTH = "M";
1199
 
 
1200
 
/**
1201
 
* Constant that represents the total number of date cells that are displayed in a given month
1202
 
* @property YAHOO.widget.Calendar.DISPLAY_DAYS
1203
 
* @static
1204
 
* @final
1205
 
* @type Number
1206
 
*/
1207
 
Calendar.DISPLAY_DAYS = 42;
1208
 
 
1209
 
/**
1210
 
* Constant used for halting the execution of the remainder of the render stack
1211
 
* @property YAHOO.widget.Calendar.STOP_RENDER
1212
 
* @static
1213
 
* @final
1214
 
* @type String
1215
 
*/
1216
 
Calendar.STOP_RENDER = "S";
1217
 
 
1218
 
/**
1219
 
* Constant used to represent short date field string formats (e.g. Tu or Feb)
1220
 
* @property YAHOO.widget.Calendar.SHORT
1221
 
* @static
1222
 
* @final
1223
 
* @type String
1224
 
*/
1225
 
Calendar.SHORT = "short";
1226
 
 
1227
 
/**
1228
 
* Constant used to represent long date field string formats (e.g. Monday or February)
1229
 
* @property YAHOO.widget.Calendar.LONG
1230
 
* @static
1231
 
* @final
1232
 
* @type String
1233
 
*/
1234
 
Calendar.LONG = "long";
1235
 
 
1236
 
/**
1237
 
* Constant used to represent medium date field string formats (e.g. Mon)
1238
 
* @property YAHOO.widget.Calendar.MEDIUM
1239
 
* @static
1240
 
* @final
1241
 
* @type String
1242
 
*/
1243
 
Calendar.MEDIUM = "medium";
1244
 
 
1245
 
/**
1246
 
* Constant used to represent single character date field string formats (e.g. M, T, W)
1247
 
* @property YAHOO.widget.Calendar.ONE_CHAR
1248
 
* @static
1249
 
* @final
1250
 
* @type String
1251
 
*/
1252
 
Calendar.ONE_CHAR = "1char";
1253
 
 
1254
 
/**
1255
 
* The set of default Config property keys and values for the Calendar
1256
 
* @property YAHOO.widget.Calendar._DEFAULT_CONFIG
1257
 
* @final
1258
 
* @static
1259
 
* @private
1260
 
* @type Object
1261
 
*/
1262
 
Calendar._DEFAULT_CONFIG = {
1263
 
        // Default values for pagedate and selected are not class level constants - they are set during instance creation 
1264
 
        PAGEDATE : {key:"pagedate", value:null},
1265
 
        SELECTED : {key:"selected", value:null},
1266
 
        TITLE : {key:"title", value:""},
1267
 
        CLOSE : {key:"close", value:false},
1268
 
        IFRAME : {key:"iframe", value:(YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) ? true : false},
1269
 
        MINDATE : {key:"mindate", value:null},
1270
 
        MAXDATE : {key:"maxdate", value:null},
1271
 
        MULTI_SELECT : {key:"multi_select", value:false},
1272
 
        START_WEEKDAY : {key:"start_weekday", value:0},
1273
 
        SHOW_WEEKDAYS : {key:"show_weekdays", value:true},
1274
 
        SHOW_WEEK_HEADER : {key:"show_week_header", value:false},
1275
 
        SHOW_WEEK_FOOTER : {key:"show_week_footer", value:false},
1276
 
        HIDE_BLANK_WEEKS : {key:"hide_blank_weeks", value:false},
1277
 
        NAV_ARROW_LEFT: {key:"nav_arrow_left", value:null} ,
1278
 
        NAV_ARROW_RIGHT : {key:"nav_arrow_right", value:null} ,
1279
 
        MONTHS_SHORT : {key:"months_short", value:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]},
1280
 
        MONTHS_LONG: {key:"months_long", value:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]},
1281
 
        WEEKDAYS_1CHAR: {key:"weekdays_1char", value:["S", "M", "T", "W", "T", "F", "S"]},
1282
 
        WEEKDAYS_SHORT: {key:"weekdays_short", value:["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]},
1283
 
        WEEKDAYS_MEDIUM: {key:"weekdays_medium", value:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]},
1284
 
        WEEKDAYS_LONG: {key:"weekdays_long", value:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]},
1285
 
        LOCALE_MONTHS:{key:"locale_months", value:"long"},
1286
 
        LOCALE_WEEKDAYS:{key:"locale_weekdays", value:"short"},
1287
 
        DATE_DELIMITER:{key:"date_delimiter", value:","},
1288
 
        DATE_FIELD_DELIMITER:{key:"date_field_delimiter", value:"/"},
1289
 
        DATE_RANGE_DELIMITER:{key:"date_range_delimiter", value:"-"},
1290
 
        MY_MONTH_POSITION:{key:"my_month_position", value:1},
1291
 
        MY_YEAR_POSITION:{key:"my_year_position", value:2},
1292
 
        MD_MONTH_POSITION:{key:"md_month_position", value:1},
1293
 
        MD_DAY_POSITION:{key:"md_day_position", value:2},
1294
 
        MDY_MONTH_POSITION:{key:"mdy_month_position", value:1},
1295
 
        MDY_DAY_POSITION:{key:"mdy_day_position", value:2},
1296
 
        MDY_YEAR_POSITION:{key:"mdy_year_position", value:3},
1297
 
        MY_LABEL_MONTH_POSITION:{key:"my_label_month_position", value:1},
1298
 
        MY_LABEL_YEAR_POSITION:{key:"my_label_year_position", value:2},
1299
 
        MY_LABEL_MONTH_SUFFIX:{key:"my_label_month_suffix", value:" "},
1300
 
        MY_LABEL_YEAR_SUFFIX:{key:"my_label_year_suffix", value:""},
1301
 
        NAV: {key:"navigator", value: null},
1302
 
        STRINGS : { 
1303
 
                key:"strings",
1304
 
                value: {
1305
 
                        previousMonth : "Previous Month",
1306
 
                        nextMonth : "Next Month",
1307
 
                        close: "Close"
1308
 
                },
1309
 
                supercedes : ["close", "title"]
1310
 
        }
1311
 
};
1312
 
 
1313
 
var DEF_CFG = Calendar._DEFAULT_CONFIG;
1314
 
 
1315
 
/**
1316
 
* The set of Custom Event types supported by the Calendar
1317
 
* @property YAHOO.widget.Calendar._EVENT_TYPES
1318
 
* @final
1319
 
* @static
1320
 
* @private
1321
 
* @type Object
1322
 
*/
1323
 
Calendar._EVENT_TYPES = {
1324
 
        BEFORE_SELECT : "beforeSelect", 
1325
 
        SELECT : "select",
1326
 
        BEFORE_DESELECT : "beforeDeselect",
1327
 
        DESELECT : "deselect",
1328
 
        CHANGE_PAGE : "changePage",
1329
 
        BEFORE_RENDER : "beforeRender",
1330
 
        RENDER : "render",
1331
 
        BEFORE_DESTROY : "beforeDestroy",
1332
 
        DESTROY : "destroy",
1333
 
        RESET : "reset",
1334
 
        CLEAR : "clear",
1335
 
        BEFORE_HIDE : "beforeHide",
1336
 
        HIDE : "hide",
1337
 
        BEFORE_SHOW : "beforeShow",
1338
 
        SHOW : "show",
1339
 
        BEFORE_HIDE_NAV : "beforeHideNav",
1340
 
        HIDE_NAV : "hideNav",
1341
 
        BEFORE_SHOW_NAV : "beforeShowNav",
1342
 
        SHOW_NAV : "showNav",
1343
 
        BEFORE_RENDER_NAV : "beforeRenderNav",
1344
 
        RENDER_NAV : "renderNav"
1345
 
};
1346
 
 
1347
 
/**
1348
 
* The set of default style constants for the Calendar
1349
 
* @property YAHOO.widget.Calendar._STYLES
1350
 
* @final
1351
 
* @static
1352
 
* @private
1353
 
* @type Object
1354
 
*/
1355
 
Calendar._STYLES = {
1356
 
        CSS_ROW_HEADER: "calrowhead",
1357
 
        CSS_ROW_FOOTER: "calrowfoot",
1358
 
        CSS_CELL : "calcell",
1359
 
        CSS_CELL_SELECTOR : "selector",
1360
 
        CSS_CELL_SELECTED : "selected",
1361
 
        CSS_CELL_SELECTABLE : "selectable",
1362
 
        CSS_CELL_RESTRICTED : "restricted",
1363
 
        CSS_CELL_TODAY : "today",
1364
 
        CSS_CELL_OOM : "oom",
1365
 
        CSS_CELL_OOB : "previous",
1366
 
        CSS_HEADER : "calheader",
1367
 
        CSS_HEADER_TEXT : "calhead",
1368
 
        CSS_BODY : "calbody",
1369
 
        CSS_WEEKDAY_CELL : "calweekdaycell",
1370
 
        CSS_WEEKDAY_ROW : "calweekdayrow",
1371
 
        CSS_FOOTER : "calfoot",
1372
 
        CSS_CALENDAR : "yui-calendar",
1373
 
        CSS_SINGLE : "single",
1374
 
        CSS_CONTAINER : "yui-calcontainer",
1375
 
        CSS_NAV_LEFT : "calnavleft",
1376
 
        CSS_NAV_RIGHT : "calnavright",
1377
 
        CSS_NAV : "calnav",
1378
 
        CSS_CLOSE : "calclose",
1379
 
        CSS_CELL_TOP : "calcelltop",
1380
 
        CSS_CELL_LEFT : "calcellleft",
1381
 
        CSS_CELL_RIGHT : "calcellright",
1382
 
        CSS_CELL_BOTTOM : "calcellbottom",
1383
 
        CSS_CELL_HOVER : "calcellhover",
1384
 
        CSS_CELL_HIGHLIGHT1 : "highlight1",
1385
 
        CSS_CELL_HIGHLIGHT2 : "highlight2",
1386
 
        CSS_CELL_HIGHLIGHT3 : "highlight3",
1387
 
        CSS_CELL_HIGHLIGHT4 : "highlight4"
1388
 
};
1389
 
 
1390
 
Calendar.prototype = {
1391
 
 
1392
 
        /**
1393
 
        * The configuration object used to set up the calendars various locale and style options.
1394
 
        * @property Config
1395
 
        * @private
1396
 
        * @deprecated Configuration properties should be set by calling Calendar.cfg.setProperty.
1397
 
        * @type Object
1398
 
        */
1399
 
        Config : null,
1400
 
 
1401
 
        /**
1402
 
        * The parent CalendarGroup, only to be set explicitly by the parent group
1403
 
        * @property parent
1404
 
        * @type CalendarGroup
1405
 
        */      
1406
 
        parent : null,
1407
 
 
1408
 
        /**
1409
 
        * The index of this item in the parent group
1410
 
        * @property index
1411
 
        * @type Number
1412
 
        */
1413
 
        index : -1,
1414
 
 
1415
 
        /**
1416
 
        * The collection of calendar table cells
1417
 
        * @property cells
1418
 
        * @type HTMLTableCellElement[]
1419
 
        */
1420
 
        cells : null,
1421
 
 
1422
 
        /**
1423
 
        * The collection of calendar cell dates that is parallel to the cells collection. The array contains dates field arrays in the format of [YYYY, M, D].
1424
 
        * @property cellDates
1425
 
        * @type Array[](Number[])
1426
 
        */
1427
 
        cellDates : null,
1428
 
 
1429
 
        /**
1430
 
        * The id that uniquely identifies this Calendar.
1431
 
        * @property id
1432
 
        * @type String
1433
 
        */
1434
 
        id : null,
1435
 
 
1436
 
        /**
1437
 
        * The unique id associated with the Calendar's container
1438
 
        * @property containerId
1439
 
        * @type String
1440
 
        */
1441
 
        containerId: null,
1442
 
 
1443
 
        /**
1444
 
        * The DOM element reference that points to this calendar's container element. The calendar will be inserted into this element when the shell is rendered.
1445
 
        * @property oDomContainer
1446
 
        * @type HTMLElement
1447
 
        */
1448
 
        oDomContainer : null,
1449
 
 
1450
 
        /**
1451
 
        * A Date object representing today's date.
1452
 
        * @property today
1453
 
        * @type Date
1454
 
        */
1455
 
        today : null,
1456
 
 
1457
 
        /**
1458
 
        * The list of render functions, along with required parameters, used to render cells. 
1459
 
        * @property renderStack
1460
 
        * @type Array[]
1461
 
        */
1462
 
        renderStack : null,
1463
 
 
1464
 
        /**
1465
 
        * A copy of the initial render functions created before rendering.
1466
 
        * @property _renderStack
1467
 
        * @private
1468
 
        * @type Array
1469
 
        */
1470
 
        _renderStack : null,
1471
 
 
1472
 
        /**
1473
 
        * A reference to the CalendarNavigator instance created for this Calendar.
1474
 
        * Will be null if the "navigator" configuration property has not been set
1475
 
        * @property oNavigator
1476
 
        * @type CalendarNavigator
1477
 
        */
1478
 
        oNavigator : null,
1479
 
 
1480
 
        /**
1481
 
        * The private list of initially selected dates.
1482
 
        * @property _selectedDates
1483
 
        * @private
1484
 
        * @type Array
1485
 
        */
1486
 
        _selectedDates : null,
1487
 
 
1488
 
        /**
1489
 
        * A map of DOM event handlers to attach to cells associated with specific CSS class names
1490
 
        * @property domEventMap
1491
 
        * @type Object
1492
 
        */
1493
 
        domEventMap : null,
1494
 
 
1495
 
        /**
1496
 
         * Protected helper used to parse Calendar constructor/init arguments.
1497
 
         *
1498
 
         * As of 2.4.0, Calendar supports a simpler constructor 
1499
 
         * signature. This method reconciles arguments
1500
 
         * received in the pre 2.4.0 and 2.4.0 formats.
1501
 
         * 
1502
 
         * @protected
1503
 
         * @method _parseArgs
1504
 
         * @param {Array} Function "arguments" array
1505
 
         * @return {Object} Object with id, container, config properties containing
1506
 
         * the reconciled argument values.
1507
 
         **/
1508
 
        _parseArgs : function(args) {
1509
 
                /*
1510
 
                   2.4.0 Constructors signatures
1511
 
 
1512
 
                   new Calendar(String)
1513
 
                   new Calendar(HTMLElement)
1514
 
                   new Calendar(String, ConfigObject)
1515
 
                   new Calendar(HTMLElement, ConfigObject)
1516
 
 
1517
 
                   Pre 2.4.0 Constructor signatures
1518
 
 
1519
 
                   new Calendar(String, String)
1520
 
                   new Calendar(String, HTMLElement)
1521
 
                   new Calendar(String, String, ConfigObject)
1522
 
                   new Calendar(String, HTMLElement, ConfigObject)
1523
 
                 */
1524
 
                var nArgs = {id:null, container:null, config:null};
1525
 
 
1526
 
                if (args && args.length && args.length > 0) {
1527
 
                        switch (args.length) {
1528
 
                                case 1:
1529
 
                                        nArgs.id = null;
1530
 
                                        nArgs.container = args[0];
1531
 
                                        nArgs.config = null;
1532
 
                                        break;
1533
 
                                case 2:
1534
 
                                        if (Lang.isObject(args[1]) && !args[1].tagName && !(args[1] instanceof String)) {
1535
 
                                                nArgs.id = null;
1536
 
                                                nArgs.container = args[0];
1537
 
                                                nArgs.config = args[1];
1538
 
                                        } else {
1539
 
                                                nArgs.id = args[0];
1540
 
                                                nArgs.container = args[1];
1541
 
                                                nArgs.config = null;
1542
 
                                        }
1543
 
                                        break;
1544
 
                                default: // 3+
1545
 
                                        nArgs.id = args[0];
1546
 
                                        nArgs.container = args[1];
1547
 
                                        nArgs.config = args[2];
1548
 
                                        break;
1549
 
                        }
1550
 
                } else {
1551
 
                }
1552
 
                return nArgs;
1553
 
        },
1554
 
 
1555
 
        /**
1556
 
        * Initializes the Calendar widget.
1557
 
        * @method init
1558
 
        *
1559
 
        * @param {String} id optional The id of the table element that will represent the Calendar widget. As of 2.4.0, this argument is optional.
1560
 
        * @param {String | HTMLElement} container The id of the container div element that will wrap the Calendar table, or a reference to a DIV element which exists in the document.
1561
 
        * @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
1562
 
        */
1563
 
        init : function(id, container, config) {
1564
 
                // Normalize 2.4.0, pre 2.4.0 args
1565
 
                var nArgs = this._parseArgs(arguments);
1566
 
 
1567
 
                id = nArgs.id;
1568
 
                container = nArgs.container;
1569
 
                config = nArgs.config;
1570
 
 
1571
 
                this.oDomContainer = Dom.get(container);
1572
 
 
1573
 
                if (!this.oDomContainer.id) {
1574
 
                        this.oDomContainer.id = Dom.generateId();
1575
 
                }
1576
 
                if (!id) {
1577
 
                        id = this.oDomContainer.id + "_t";
1578
 
                }
1579
 
 
1580
 
                this.id = id;
1581
 
                this.containerId = this.oDomContainer.id;
1582
 
 
1583
 
                this.initEvents();
1584
 
 
1585
 
                this.today = new Date();
1586
 
                DateMath.clearTime(this.today);
1587
 
 
1588
 
                /**
1589
 
                * The Config object used to hold the configuration variables for the Calendar
1590
 
                * @property cfg
1591
 
                * @type YAHOO.util.Config
1592
 
                */
1593
 
                this.cfg = new YAHOO.util.Config(this);
1594
 
 
1595
 
                /**
1596
 
                * The local object which contains the Calendar's options
1597
 
                * @property Options
1598
 
                * @type Object
1599
 
                */
1600
 
                this.Options = {};
1601
 
 
1602
 
                /**
1603
 
                * The local object which contains the Calendar's locale settings
1604
 
                * @property Locale
1605
 
                * @type Object
1606
 
                */
1607
 
                this.Locale = {};
1608
 
 
1609
 
                this.initStyles();
1610
 
 
1611
 
                Dom.addClass(this.oDomContainer, this.Style.CSS_CONTAINER);
1612
 
                Dom.addClass(this.oDomContainer, this.Style.CSS_SINGLE);
1613
 
 
1614
 
                this.cellDates = [];
1615
 
                this.cells = [];
1616
 
                this.renderStack = [];
1617
 
                this._renderStack = [];
1618
 
 
1619
 
                this.setupConfig();
1620
 
 
1621
 
                if (config) {
1622
 
                        this.cfg.applyConfig(config, true);
1623
 
                }
1624
 
 
1625
 
                this.cfg.fireQueue();
1626
 
        },
1627
 
 
1628
 
        /**
1629
 
        * Default Config listener for the iframe property. If the iframe config property is set to true, 
1630
 
        * renders the built-in IFRAME shim if the container is relatively or absolutely positioned.
1631
 
        * 
1632
 
        * @method configIframe
1633
 
        */
1634
 
        configIframe : function(type, args, obj) {
1635
 
                var useIframe = args[0];
1636
 
        
1637
 
                if (!this.parent) {
1638
 
                        if (Dom.inDocument(this.oDomContainer)) {
1639
 
                                if (useIframe) {
1640
 
                                        var pos = Dom.getStyle(this.oDomContainer, "position");
1641
 
                                        
1642
 
                                        if (pos == "absolute" || pos == "relative") {
1643
 
                                                
1644
 
                                                if (!Dom.inDocument(this.iframe)) {
1645
 
                                                        this.iframe = document.createElement("iframe");
1646
 
                                                        this.iframe.src = "javascript:false;";
1647
 
        
1648
 
                                                        Dom.setStyle(this.iframe, "opacity", "0");
1649
 
        
1650
 
                                                        if (YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) {
1651
 
                                                                Dom.addClass(this.iframe, "fixedsize");
1652
 
                                                        }
1653
 
        
1654
 
                                                        this.oDomContainer.insertBefore(this.iframe, this.oDomContainer.firstChild);
1655
 
                                                }
1656
 
                                        }
1657
 
                                } else {
1658
 
                                        if (this.iframe) {
1659
 
                                                if (this.iframe.parentNode) {
1660
 
                                                        this.iframe.parentNode.removeChild(this.iframe);
1661
 
                                                }
1662
 
                                                this.iframe = null;
1663
 
                                        }
1664
 
                                }
1665
 
                        }
1666
 
                }
1667
 
        },
1668
 
 
1669
 
        /**
1670
 
        * Default handler for the "title" property
1671
 
        * @method configTitle
1672
 
        */
1673
 
        configTitle : function(type, args, obj) {
1674
 
                var title = args[0];
1675
 
 
1676
 
                // "" disables title bar
1677
 
                if (title) {
1678
 
                        this.createTitleBar(title);
1679
 
                } else {
1680
 
                        var close = this.cfg.getProperty(DEF_CFG.CLOSE.key);
1681
 
                        if (!close) {
1682
 
                                this.removeTitleBar();
1683
 
                        } else {
1684
 
                                this.createTitleBar("&#160;");
1685
 
                        }
1686
 
                }
1687
 
        },
1688
 
        
1689
 
        /**
1690
 
        * Default handler for the "close" property
1691
 
        * @method configClose
1692
 
        */
1693
 
        configClose : function(type, args, obj) {
1694
 
                var close = args[0],
1695
 
                        title = this.cfg.getProperty(DEF_CFG.TITLE.key);
1696
 
        
1697
 
                if (close) {
1698
 
                        if (!title) {
1699
 
                                this.createTitleBar("&#160;");
1700
 
                        }
1701
 
                        this.createCloseButton();
1702
 
                } else {
1703
 
                        this.removeCloseButton();
1704
 
                        if (!title) {
1705
 
                                this.removeTitleBar();
1706
 
                        }
1707
 
                }
1708
 
        },
1709
 
 
1710
 
        /**
1711
 
        * Initializes Calendar's built-in CustomEvents
1712
 
        * @method initEvents
1713
 
        */
1714
 
        initEvents : function() {
1715
 
 
1716
 
                var defEvents = Calendar._EVENT_TYPES,
1717
 
                        CE = YAHOO.util.CustomEvent,
1718
 
                        cal = this; // To help with minification
1719
 
 
1720
 
                /**
1721
 
                * Fired before a date selection is made
1722
 
                * @event beforeSelectEvent
1723
 
                */
1724
 
                cal.beforeSelectEvent = new CE(defEvents.BEFORE_SELECT); 
1725
 
 
1726
 
                /**
1727
 
                * Fired when a date selection is made
1728
 
                * @event selectEvent
1729
 
                * @param {Array}        Array of Date field arrays in the format [YYYY, MM, DD].
1730
 
                */
1731
 
                cal.selectEvent = new CE(defEvents.SELECT);
1732
 
 
1733
 
                /**
1734
 
                * Fired before a date or set of dates is deselected
1735
 
                * @event beforeDeselectEvent
1736
 
                */
1737
 
                cal.beforeDeselectEvent = new CE(defEvents.BEFORE_DESELECT);
1738
 
 
1739
 
                /**
1740
 
                * Fired when a date or set of dates is deselected
1741
 
                * @event deselectEvent
1742
 
                * @param {Array}        Array of Date field arrays in the format [YYYY, MM, DD].
1743
 
                */
1744
 
                cal.deselectEvent = new CE(defEvents.DESELECT);
1745
 
        
1746
 
                /**
1747
 
                * Fired when the Calendar page is changed
1748
 
                * @event changePageEvent
1749
 
                */
1750
 
                cal.changePageEvent = new CE(defEvents.CHANGE_PAGE);
1751
 
        
1752
 
                /**
1753
 
                * Fired before the Calendar is rendered
1754
 
                * @event beforeRenderEvent
1755
 
                */
1756
 
                cal.beforeRenderEvent = new CE(defEvents.BEFORE_RENDER);
1757
 
        
1758
 
                /**
1759
 
                * Fired when the Calendar is rendered
1760
 
                * @event renderEvent
1761
 
                */
1762
 
                cal.renderEvent = new CE(defEvents.RENDER);
1763
 
 
1764
 
                /**
1765
 
                * Fired just before the Calendar is to be destroyed
1766
 
                * @event beforeDestroyEvent
1767
 
                */
1768
 
                cal.beforeDestroyEvent = new CE(defEvents.BEFORE_DESTROY);
1769
 
 
1770
 
                /**
1771
 
                * Fired after the Calendar is destroyed. This event should be used
1772
 
                * for notification only. When this event is fired, important Calendar instance
1773
 
                * properties, dom references and event listeners have already been 
1774
 
                * removed/dereferenced, and hence the Calendar instance is not in a usable 
1775
 
                * state.
1776
 
                *
1777
 
                * @event destroyEvent
1778
 
                */
1779
 
                cal.destroyEvent = new CE(defEvents.DESTROY);
1780
 
 
1781
 
                /**
1782
 
                * Fired when the Calendar is reset
1783
 
                * @event resetEvent
1784
 
                */
1785
 
                cal.resetEvent = new CE(defEvents.RESET);
1786
 
 
1787
 
                /**
1788
 
                * Fired when the Calendar is cleared
1789
 
                * @event clearEvent
1790
 
                */
1791
 
                cal.clearEvent = new CE(defEvents.CLEAR);
1792
 
 
1793
 
                /**
1794
 
                * Fired just before the Calendar is to be shown
1795
 
                * @event beforeShowEvent
1796
 
                */
1797
 
                cal.beforeShowEvent = new CE(defEvents.BEFORE_SHOW);
1798
 
 
1799
 
                /**
1800
 
                * Fired after the Calendar is shown
1801
 
                * @event showEvent
1802
 
                */
1803
 
                cal.showEvent = new CE(defEvents.SHOW);
1804
 
 
1805
 
                /**
1806
 
                * Fired just before the Calendar is to be hidden
1807
 
                * @event beforeHideEvent
1808
 
                */
1809
 
                cal.beforeHideEvent = new CE(defEvents.BEFORE_HIDE);
1810
 
 
1811
 
                /**
1812
 
                * Fired after the Calendar is hidden
1813
 
                * @event hideEvent
1814
 
                */
1815
 
                cal.hideEvent = new CE(defEvents.HIDE);
1816
 
 
1817
 
                /**
1818
 
                * Fired just before the CalendarNavigator is to be shown
1819
 
                * @event beforeShowNavEvent
1820
 
                */
1821
 
                cal.beforeShowNavEvent = new CE(defEvents.BEFORE_SHOW_NAV);
1822
 
        
1823
 
                /**
1824
 
                * Fired after the CalendarNavigator is shown
1825
 
                * @event showNavEvent
1826
 
                */
1827
 
                cal.showNavEvent = new CE(defEvents.SHOW_NAV);
1828
 
        
1829
 
                /**
1830
 
                * Fired just before the CalendarNavigator is to be hidden
1831
 
                * @event beforeHideNavEvent
1832
 
                */
1833
 
                cal.beforeHideNavEvent = new CE(defEvents.BEFORE_HIDE_NAV);
1834
 
        
1835
 
                /**
1836
 
                * Fired after the CalendarNavigator is hidden
1837
 
                * @event hideNavEvent
1838
 
                */
1839
 
                cal.hideNavEvent = new CE(defEvents.HIDE_NAV);
1840
 
 
1841
 
                /**
1842
 
                * Fired just before the CalendarNavigator is to be rendered
1843
 
                * @event beforeRenderNavEvent
1844
 
                */
1845
 
                cal.beforeRenderNavEvent = new CE(defEvents.BEFORE_RENDER_NAV);
1846
 
 
1847
 
                /**
1848
 
                * Fired after the CalendarNavigator is rendered
1849
 
                * @event renderNavEvent
1850
 
                */
1851
 
                cal.renderNavEvent = new CE(defEvents.RENDER_NAV);
1852
 
 
1853
 
                cal.beforeSelectEvent.subscribe(cal.onBeforeSelect, this, true);
1854
 
                cal.selectEvent.subscribe(cal.onSelect, this, true);
1855
 
                cal.beforeDeselectEvent.subscribe(cal.onBeforeDeselect, this, true);
1856
 
                cal.deselectEvent.subscribe(cal.onDeselect, this, true);
1857
 
                cal.changePageEvent.subscribe(cal.onChangePage, this, true);
1858
 
                cal.renderEvent.subscribe(cal.onRender, this, true);
1859
 
                cal.resetEvent.subscribe(cal.onReset, this, true);
1860
 
                cal.clearEvent.subscribe(cal.onClear, this, true);
1861
 
        },
1862
 
 
1863
 
        /**
1864
 
        * The default event handler for clicks on the "Previous Month" navigation UI
1865
 
        *
1866
 
        * @method doPreviousMonthNav
1867
 
        * @param {DOMEvent} e   The DOM event
1868
 
        * @param {Calendar} cal A reference to the calendar
1869
 
        */
1870
 
        doPreviousMonthNav : function(e, cal) {
1871
 
                Event.preventDefault(e);
1872
 
                // previousMonth invoked in a timeout, to allow
1873
 
                // event to bubble up, with correct target. Calling
1874
 
                // previousMonth, will call render which will remove 
1875
 
                // HTML which generated the event, resulting in an 
1876
 
                // invalid event target in certain browsers.
1877
 
                setTimeout(function() {
1878
 
                        cal.previousMonth();
1879
 
                        var navs = Dom.getElementsByClassName(cal.Style.CSS_NAV_LEFT, "a", cal.oDomContainer);
1880
 
                        if (navs && navs[0]) {
1881
 
                                try {
1882
 
                                        navs[0].focus();
1883
 
                                } catch (e) {
1884
 
                                        // ignore
1885
 
                                }
1886
 
                        }
1887
 
                }, 0);
1888
 
        },
1889
 
 
1890
 
        /**
1891
 
         * The default event handler for clicks on the "Next Month" navigation UI
1892
 
         *
1893
 
         * @method doNextMonthNav
1894
 
         * @param {DOMEvent} e  The DOM event
1895
 
         * @param {Calendar} cal        A reference to the calendar
1896
 
         */
1897
 
        doNextMonthNav : function(e, cal) {
1898
 
                Event.preventDefault(e);
1899
 
                setTimeout(function() {
1900
 
                        cal.nextMonth();
1901
 
                        var navs = Dom.getElementsByClassName(cal.Style.CSS_NAV_RIGHT, "a", cal.oDomContainer);
1902
 
                        if (navs && navs[0]) {
1903
 
                                try {
1904
 
                                        navs[0].focus();
1905
 
                                } catch (e) {
1906
 
                                        // ignore
1907
 
                                }
1908
 
                        }
1909
 
                }, 0);
1910
 
        },
1911
 
 
1912
 
        /**
1913
 
        * The default event handler for date cell selection. Currently attached to 
1914
 
        * the Calendar's bounding box, referenced by it's <a href="#property_oDomContainer">oDomContainer</a> property.
1915
 
        *
1916
 
        * @method doSelectCell
1917
 
        * @param {DOMEvent} e   The DOM event
1918
 
        * @param {Calendar} cal A reference to the calendar
1919
 
        */
1920
 
        doSelectCell : function(e, cal) {
1921
 
                var cell, d, date, index;
1922
 
 
1923
 
                var target = Event.getTarget(e),
1924
 
                        tagName = target.tagName.toLowerCase(),
1925
 
                        defSelector = false;
1926
 
 
1927
 
                while (tagName != "td" && !Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
1928
 
 
1929
 
                        if (!defSelector && tagName == "a" && Dom.hasClass(target, cal.Style.CSS_CELL_SELECTOR)) {
1930
 
                                defSelector = true;
1931
 
                        }
1932
 
 
1933
 
                        target = target.parentNode;
1934
 
                        tagName = target.tagName.toLowerCase();
1935
 
 
1936
 
                        if (target == this.oDomContainer || tagName == "html") {
1937
 
                                return;
1938
 
                        }
1939
 
                }
1940
 
 
1941
 
                if (defSelector) {
1942
 
                        // Stop link href navigation for default renderer
1943
 
                        Event.preventDefault(e);
1944
 
                }
1945
 
        
1946
 
                cell = target;
1947
 
 
1948
 
                if (Dom.hasClass(cell, cal.Style.CSS_CELL_SELECTABLE)) {
1949
 
                        index = cal.getIndexFromId(cell.id);
1950
 
                        if (index > -1) {
1951
 
                                d = cal.cellDates[index];
1952
 
                                if (d) {
1953
 
                                        date = DateMath.getDate(d[0],d[1]-1,d[2]);
1954
 
                                
1955
 
                                        var link;
1956
 
 
1957
 
                                        if (cal.Options.MULTI_SELECT) {
1958
 
                                                link = cell.getElementsByTagName("a")[0];
1959
 
                                                if (link) {
1960
 
                                                        link.blur();
1961
 
                                                }
1962
 
 
1963
 
                                                var cellDate = cal.cellDates[index];
1964
 
                                                var cellDateIndex = cal._indexOfSelectedFieldArray(cellDate);
1965
 
 
1966
 
                                                if (cellDateIndex > -1) {       
1967
 
                                                        cal.deselectCell(index);
1968
 
                                                } else {
1969
 
                                                        cal.selectCell(index);
1970
 
                                                }       
1971
 
 
1972
 
                                        } else {
1973
 
                                                link = cell.getElementsByTagName("a")[0];
1974
 
                                                if (link) {
1975
 
                                                        link.blur();
1976
 
                                                }
1977
 
                                                cal.selectCell(index);
1978
 
                                        }
1979
 
                                }
1980
 
                        }
1981
 
                }
1982
 
        },
1983
 
 
1984
 
        /**
1985
 
        * The event that is executed when the user hovers over a cell
1986
 
        * @method doCellMouseOver
1987
 
        * @param {DOMEvent} e   The event
1988
 
        * @param {Calendar} cal A reference to the calendar passed by the Event utility
1989
 
        */
1990
 
        doCellMouseOver : function(e, cal) {
1991
 
                var target;
1992
 
                if (e) {
1993
 
                        target = Event.getTarget(e);
1994
 
                } else {
1995
 
                        target = this;
1996
 
                }
1997
 
 
1998
 
                while (target.tagName && target.tagName.toLowerCase() != "td") {
1999
 
                        target = target.parentNode;
2000
 
                        if (!target.tagName || target.tagName.toLowerCase() == "html") {
2001
 
                                return;
2002
 
                        }
2003
 
                }
2004
 
 
2005
 
                if (Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
2006
 
                        Dom.addClass(target, cal.Style.CSS_CELL_HOVER);
2007
 
                }
2008
 
        },
2009
 
 
2010
 
        /**
2011
 
        * The event that is executed when the user moves the mouse out of a cell
2012
 
        * @method doCellMouseOut
2013
 
        * @param {DOMEvent} e   The event
2014
 
        * @param {Calendar} cal A reference to the calendar passed by the Event utility
2015
 
        */
2016
 
        doCellMouseOut : function(e, cal) {
2017
 
                var target;
2018
 
                if (e) {
2019
 
                        target = Event.getTarget(e);
2020
 
                } else {
2021
 
                        target = this;
2022
 
                }
2023
 
 
2024
 
                while (target.tagName && target.tagName.toLowerCase() != "td") {
2025
 
                        target = target.parentNode;
2026
 
                        if (!target.tagName || target.tagName.toLowerCase() == "html") {
2027
 
                                return;
2028
 
                        }
2029
 
                }
2030
 
 
2031
 
                if (Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
2032
 
                        Dom.removeClass(target, cal.Style.CSS_CELL_HOVER);
2033
 
                }
2034
 
        },
2035
 
 
2036
 
        setupConfig : function() {
2037
 
                var cfg = this.cfg;
2038
 
 
2039
 
                /**
2040
 
                * The month/year representing the current visible Calendar date (mm/yyyy)
2041
 
                * @config pagedate
2042
 
                * @type String | Date
2043
 
                * @default today's date
2044
 
                */
2045
 
                cfg.addProperty(DEF_CFG.PAGEDATE.key, { value:new Date(), handler:this.configPageDate } );
2046
 
 
2047
 
                /**
2048
 
                * The date or range of dates representing the current Calendar selection
2049
 
                * @config selected
2050
 
                * @type String
2051
 
                * @default []
2052
 
                */
2053
 
                cfg.addProperty(DEF_CFG.SELECTED.key, { value:[], handler:this.configSelected } );
2054
 
 
2055
 
                /**
2056
 
                * The title to display above the Calendar's month header
2057
 
                * @config title
2058
 
                * @type String
2059
 
                * @default ""
2060
 
                */
2061
 
                cfg.addProperty(DEF_CFG.TITLE.key, { value:DEF_CFG.TITLE.value, handler:this.configTitle } );
2062
 
 
2063
 
                /**
2064
 
                * Whether or not a close button should be displayed for this Calendar
2065
 
                * @config close
2066
 
                * @type Boolean
2067
 
                * @default false
2068
 
                */
2069
 
                cfg.addProperty(DEF_CFG.CLOSE.key, { value:DEF_CFG.CLOSE.value, handler:this.configClose } );
2070
 
 
2071
 
                /**
2072
 
                * Whether or not an iframe shim should be placed under the Calendar to prevent select boxes from bleeding through in Internet Explorer 6 and below.
2073
 
                * This property is enabled by default for IE6 and below. It is disabled by default for other browsers for performance reasons, but can be 
2074
 
                * enabled if required.
2075
 
                * 
2076
 
                * @config iframe
2077
 
                * @type Boolean
2078
 
                * @default true for IE6 and below, false for all other browsers
2079
 
                */
2080
 
                cfg.addProperty(DEF_CFG.IFRAME.key, { value:DEF_CFG.IFRAME.value, handler:this.configIframe, validator:cfg.checkBoolean } );
2081
 
 
2082
 
                /**
2083
 
                * The minimum selectable date in the current Calendar (mm/dd/yyyy)
2084
 
                * @config mindate
2085
 
                * @type String | Date
2086
 
                * @default null
2087
 
                */
2088
 
                cfg.addProperty(DEF_CFG.MINDATE.key, { value:DEF_CFG.MINDATE.value, handler:this.configMinDate } );
2089
 
 
2090
 
                /**
2091
 
                * The maximum selectable date in the current Calendar (mm/dd/yyyy)
2092
 
                * @config maxdate
2093
 
                * @type String | Date
2094
 
                * @default null
2095
 
                */
2096
 
                cfg.addProperty(DEF_CFG.MAXDATE.key, { value:DEF_CFG.MAXDATE.value, handler:this.configMaxDate } );
2097
 
        
2098
 
        
2099
 
                // Options properties
2100
 
        
2101
 
                /**
2102
 
                * True if the Calendar should allow multiple selections. False by default.
2103
 
                * @config MULTI_SELECT
2104
 
                * @type Boolean
2105
 
                * @default false
2106
 
                */
2107
 
                cfg.addProperty(DEF_CFG.MULTI_SELECT.key,       { value:DEF_CFG.MULTI_SELECT.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2108
 
 
2109
 
                /**
2110
 
                * The weekday the week begins on. Default is 0 (Sunday = 0, Monday = 1 ... Saturday = 6).
2111
 
                * @config START_WEEKDAY
2112
 
                * @type number
2113
 
                * @default 0
2114
 
                */
2115
 
                cfg.addProperty(DEF_CFG.START_WEEKDAY.key,      { value:DEF_CFG.START_WEEKDAY.value, handler:this.configOptions, validator:cfg.checkNumber  } );
2116
 
        
2117
 
                /**
2118
 
                * True if the Calendar should show weekday labels. True by default.
2119
 
                * @config SHOW_WEEKDAYS
2120
 
                * @type Boolean
2121
 
                * @default true
2122
 
                */
2123
 
                cfg.addProperty(DEF_CFG.SHOW_WEEKDAYS.key,      { value:DEF_CFG.SHOW_WEEKDAYS.value, handler:this.configOptions, validator:cfg.checkBoolean  } );
2124
 
        
2125
 
                /**
2126
 
                * True if the Calendar should show week row headers. False by default.
2127
 
                * @config SHOW_WEEK_HEADER
2128
 
                * @type Boolean
2129
 
                * @default false
2130
 
                */
2131
 
                cfg.addProperty(DEF_CFG.SHOW_WEEK_HEADER.key, { value:DEF_CFG.SHOW_WEEK_HEADER.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2132
 
        
2133
 
                /**
2134
 
                * True if the Calendar should show week row footers. False by default.
2135
 
                * @config SHOW_WEEK_FOOTER
2136
 
                * @type Boolean
2137
 
                * @default false
2138
 
                */      
2139
 
                cfg.addProperty(DEF_CFG.SHOW_WEEK_FOOTER.key,{ value:DEF_CFG.SHOW_WEEK_FOOTER.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2140
 
        
2141
 
                /**
2142
 
                * True if the Calendar should suppress weeks that are not a part of the current month. False by default.
2143
 
                * @config HIDE_BLANK_WEEKS
2144
 
                * @type Boolean
2145
 
                * @default false
2146
 
                */      
2147
 
                cfg.addProperty(DEF_CFG.HIDE_BLANK_WEEKS.key, { value:DEF_CFG.HIDE_BLANK_WEEKS.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2148
 
                
2149
 
                /**
2150
 
                * The image that should be used for the left navigation arrow.
2151
 
                * @config NAV_ARROW_LEFT
2152
 
                * @type String
2153
 
                * @deprecated   You can customize the image by overriding the default CSS class for the left arrow - "calnavleft"  
2154
 
                * @default null
2155
 
                */      
2156
 
                cfg.addProperty(DEF_CFG.NAV_ARROW_LEFT.key,     { value:DEF_CFG.NAV_ARROW_LEFT.value, handler:this.configOptions } );
2157
 
        
2158
 
                /**
2159
 
                * The image that should be used for the right navigation arrow.
2160
 
                * @config NAV_ARROW_RIGHT
2161
 
                * @type String
2162
 
                * @deprecated   You can customize the image by overriding the default CSS class for the right arrow - "calnavright"
2163
 
                * @default null
2164
 
                */      
2165
 
                cfg.addProperty(DEF_CFG.NAV_ARROW_RIGHT.key, { value:DEF_CFG.NAV_ARROW_RIGHT.value, handler:this.configOptions } );
2166
 
        
2167
 
                // Locale properties
2168
 
        
2169
 
                /**
2170
 
                * The short month labels for the current locale.
2171
 
                * @config MONTHS_SHORT
2172
 
                * @type String[]
2173
 
                * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
2174
 
                */
2175
 
                cfg.addProperty(DEF_CFG.MONTHS_SHORT.key,       { value:DEF_CFG.MONTHS_SHORT.value, handler:this.configLocale } );
2176
 
                
2177
 
                /**
2178
 
                * The long month labels for the current locale.
2179
 
                * @config MONTHS_LONG
2180
 
                * @type String[]
2181
 
                * @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
2182
 
                */      
2183
 
                cfg.addProperty(DEF_CFG.MONTHS_LONG.key,                { value:DEF_CFG.MONTHS_LONG.value, handler:this.configLocale } );
2184
 
 
2185
 
                /**
2186
 
                * The 1-character weekday labels for the current locale.
2187
 
                * @config WEEKDAYS_1CHAR
2188
 
                * @type String[]
2189
 
                * @default ["S", "M", "T", "W", "T", "F", "S"]
2190
 
                */      
2191
 
                cfg.addProperty(DEF_CFG.WEEKDAYS_1CHAR.key,     { value:DEF_CFG.WEEKDAYS_1CHAR.value, handler:this.configLocale } );
2192
 
                
2193
 
                /**
2194
 
                * The short weekday labels for the current locale.
2195
 
                * @config WEEKDAYS_SHORT
2196
 
                * @type String[]
2197
 
                * @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
2198
 
                */      
2199
 
                cfg.addProperty(DEF_CFG.WEEKDAYS_SHORT.key,     { value:DEF_CFG.WEEKDAYS_SHORT.value, handler:this.configLocale } );
2200
 
                
2201
 
                /**
2202
 
                * The medium weekday labels for the current locale.
2203
 
                * @config WEEKDAYS_MEDIUM
2204
 
                * @type String[]
2205
 
                * @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
2206
 
                */      
2207
 
                cfg.addProperty(DEF_CFG.WEEKDAYS_MEDIUM.key,    { value:DEF_CFG.WEEKDAYS_MEDIUM.value, handler:this.configLocale } );
2208
 
                
2209
 
                /**
2210
 
                * The long weekday labels for the current locale.
2211
 
                * @config WEEKDAYS_LONG
2212
 
                * @type String[]
2213
 
                * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
2214
 
                */      
2215
 
                cfg.addProperty(DEF_CFG.WEEKDAYS_LONG.key,      { value:DEF_CFG.WEEKDAYS_LONG.value, handler:this.configLocale } );
2216
 
        
2217
 
                /**
2218
 
                * Refreshes the locale values used to build the Calendar.
2219
 
                * @method refreshLocale
2220
 
                * @private
2221
 
                */
2222
 
                var refreshLocale = function() {
2223
 
                        cfg.refireEvent(DEF_CFG.LOCALE_MONTHS.key);
2224
 
                        cfg.refireEvent(DEF_CFG.LOCALE_WEEKDAYS.key);
2225
 
                };
2226
 
        
2227
 
                cfg.subscribeToConfigEvent(DEF_CFG.START_WEEKDAY.key, refreshLocale, this, true);
2228
 
                cfg.subscribeToConfigEvent(DEF_CFG.MONTHS_SHORT.key, refreshLocale, this, true);
2229
 
                cfg.subscribeToConfigEvent(DEF_CFG.MONTHS_LONG.key, refreshLocale, this, true);
2230
 
                cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_1CHAR.key, refreshLocale, this, true);
2231
 
                cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_SHORT.key, refreshLocale, this, true);
2232
 
                cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_MEDIUM.key, refreshLocale, this, true);
2233
 
                cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_LONG.key, refreshLocale, this, true);
2234
 
                
2235
 
                /**
2236
 
                * The setting that determines which length of month labels should be used. Possible values are "short" and "long".
2237
 
                * @config LOCALE_MONTHS
2238
 
                * @type String
2239
 
                * @default "long"
2240
 
                */      
2241
 
                cfg.addProperty(DEF_CFG.LOCALE_MONTHS.key,      { value:DEF_CFG.LOCALE_MONTHS.value, handler:this.configLocaleValues } );
2242
 
                
2243
 
                /**
2244
 
                * The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
2245
 
                * @config LOCALE_WEEKDAYS
2246
 
                * @type String
2247
 
                * @default "short"
2248
 
                */      
2249
 
                cfg.addProperty(DEF_CFG.LOCALE_WEEKDAYS.key,    { value:DEF_CFG.LOCALE_WEEKDAYS.value, handler:this.configLocaleValues } );
2250
 
        
2251
 
                /**
2252
 
                * The value used to delimit individual dates in a date string passed to various Calendar functions.
2253
 
                * @config DATE_DELIMITER
2254
 
                * @type String
2255
 
                * @default ","
2256
 
                */      
2257
 
                cfg.addProperty(DEF_CFG.DATE_DELIMITER.key,             { value:DEF_CFG.DATE_DELIMITER.value, handler:this.configLocale } );
2258
 
        
2259
 
                /**
2260
 
                * The value used to delimit date fields in a date string passed to various Calendar functions.
2261
 
                * @config DATE_FIELD_DELIMITER
2262
 
                * @type String
2263
 
                * @default "/"
2264
 
                */      
2265
 
                cfg.addProperty(DEF_CFG.DATE_FIELD_DELIMITER.key, { value:DEF_CFG.DATE_FIELD_DELIMITER.value, handler:this.configLocale } );
2266
 
        
2267
 
                /**
2268
 
                * The value used to delimit date ranges in a date string passed to various Calendar functions.
2269
 
                * @config DATE_RANGE_DELIMITER
2270
 
                * @type String
2271
 
                * @default "-"
2272
 
                */
2273
 
                cfg.addProperty(DEF_CFG.DATE_RANGE_DELIMITER.key, { value:DEF_CFG.DATE_RANGE_DELIMITER.value, handler:this.configLocale } );
2274
 
        
2275
 
                /**
2276
 
                * The position of the month in a month/year date string
2277
 
                * @config MY_MONTH_POSITION
2278
 
                * @type Number
2279
 
                * @default 1
2280
 
                */
2281
 
                cfg.addProperty(DEF_CFG.MY_MONTH_POSITION.key,  { value:DEF_CFG.MY_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2282
 
        
2283
 
                /**
2284
 
                * The position of the year in a month/year date string
2285
 
                * @config MY_YEAR_POSITION
2286
 
                * @type Number
2287
 
                * @default 2
2288
 
                */
2289
 
                cfg.addProperty(DEF_CFG.MY_YEAR_POSITION.key,   { value:DEF_CFG.MY_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2290
 
        
2291
 
                /**
2292
 
                * The position of the month in a month/day date string
2293
 
                * @config MD_MONTH_POSITION
2294
 
                * @type Number
2295
 
                * @default 1
2296
 
                */
2297
 
                cfg.addProperty(DEF_CFG.MD_MONTH_POSITION.key,  { value:DEF_CFG.MD_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2298
 
        
2299
 
                /**
2300
 
                * The position of the day in a month/year date string
2301
 
                * @config MD_DAY_POSITION
2302
 
                * @type Number
2303
 
                * @default 2
2304
 
                */
2305
 
                cfg.addProperty(DEF_CFG.MD_DAY_POSITION.key,            { value:DEF_CFG.MD_DAY_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2306
 
        
2307
 
                /**
2308
 
                * The position of the month in a month/day/year date string
2309
 
                * @config MDY_MONTH_POSITION
2310
 
                * @type Number
2311
 
                * @default 1
2312
 
                */
2313
 
                cfg.addProperty(DEF_CFG.MDY_MONTH_POSITION.key, { value:DEF_CFG.MDY_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2314
 
        
2315
 
                /**
2316
 
                * The position of the day in a month/day/year date string
2317
 
                * @config MDY_DAY_POSITION
2318
 
                * @type Number
2319
 
                * @default 2
2320
 
                */
2321
 
                cfg.addProperty(DEF_CFG.MDY_DAY_POSITION.key,   { value:DEF_CFG.MDY_DAY_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2322
 
        
2323
 
                /**
2324
 
                * The position of the year in a month/day/year date string
2325
 
                * @config MDY_YEAR_POSITION
2326
 
                * @type Number
2327
 
                * @default 3
2328
 
                */
2329
 
                cfg.addProperty(DEF_CFG.MDY_YEAR_POSITION.key,  { value:DEF_CFG.MDY_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2330
 
                
2331
 
                /**
2332
 
                * The position of the month in the month year label string used as the Calendar header
2333
 
                * @config MY_LABEL_MONTH_POSITION
2334
 
                * @type Number
2335
 
                * @default 1
2336
 
                */
2337
 
                cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_POSITION.key,    { value:DEF_CFG.MY_LABEL_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2338
 
        
2339
 
                /**
2340
 
                * The position of the year in the month year label string used as the Calendar header
2341
 
                * @config MY_LABEL_YEAR_POSITION
2342
 
                * @type Number
2343
 
                * @default 2
2344
 
                */
2345
 
                cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_POSITION.key,     { value:DEF_CFG.MY_LABEL_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2346
 
                
2347
 
                /**
2348
 
                * The suffix used after the month when rendering the Calendar header
2349
 
                * @config MY_LABEL_MONTH_SUFFIX
2350
 
                * @type String
2351
 
                * @default " "
2352
 
                */
2353
 
                cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_SUFFIX.key,      { value:DEF_CFG.MY_LABEL_MONTH_SUFFIX.value, handler:this.configLocale } );
2354
 
                
2355
 
                /**
2356
 
                * The suffix used after the year when rendering the Calendar header
2357
 
                * @config MY_LABEL_YEAR_SUFFIX
2358
 
                * @type String
2359
 
                * @default ""
2360
 
                */
2361
 
                cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_SUFFIX.key, { value:DEF_CFG.MY_LABEL_YEAR_SUFFIX.value, handler:this.configLocale } );
2362
 
 
2363
 
                /**
2364
 
                * Configuration for the Month/Year CalendarNavigator UI which allows the user to jump directly to a 
2365
 
                * specific Month/Year without having to scroll sequentially through months.
2366
 
                * <p>
2367
 
                * Setting this property to null (default value) or false, will disable the CalendarNavigator UI.
2368
 
                * </p>
2369
 
                * <p>
2370
 
                * Setting this property to true will enable the CalendarNavigatior UI with the default CalendarNavigator configuration values.
2371
 
                * </p>
2372
 
                * <p>
2373
 
                * This property can also be set to an object literal containing configuration properties for the CalendarNavigator UI.
2374
 
                * The configuration object expects the the following case-sensitive properties, with the "strings" property being a nested object.
2375
 
                * Any properties which are not provided will use the default values (defined in the CalendarNavigator class).
2376
 
                * </p>
2377
 
                * <dl>
2378
 
                * <dt>strings</dt>
2379
 
                * <dd><em>Object</em> :  An object with the properties shown below, defining the string labels to use in the Navigator's UI
2380
 
                *     <dl>
2381
 
                *         <dt>month</dt><dd><em>String</em> : The string to use for the month label. Defaults to "Month".</dd>
2382
 
                *         <dt>year</dt><dd><em>String</em> : The string to use for the year label. Defaults to "Year".</dd>
2383
 
                *         <dt>submit</dt><dd><em>String</em> : The string to use for the submit button label. Defaults to "Okay".</dd>
2384
 
                *         <dt>cancel</dt><dd><em>String</em> : The string to use for the cancel button label. Defaults to "Cancel".</dd>
2385
 
                *         <dt>invalidYear</dt><dd><em>String</em> : The string to use for invalid year values. Defaults to "Year needs to be a number".</dd>
2386
 
                *     </dl>
2387
 
                * </dd>
2388
 
                * <dt>monthFormat</dt><dd><em>String</em> : The month format to use. Either YAHOO.widget.Calendar.LONG, or YAHOO.widget.Calendar.SHORT. Defaults to YAHOO.widget.Calendar.LONG</dd>
2389
 
                * <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
2390
 
                * </dl>
2391
 
                * <p>E.g.</p>
2392
 
                * <pre>
2393
 
                * var navConfig = {
2394
 
                *         strings: {
2395
 
                *                 month:"Calendar Month",
2396
 
                *                 year:"Calendar Year",
2397
 
                *                 submit: "Submit",
2398
 
                *                 cancel: "Cancel",
2399
 
                *                 invalidYear: "Please enter a valid year"
2400
 
                *         },
2401
 
                *         monthFormat: YAHOO.widget.Calendar.SHORT,
2402
 
                *         initialFocus: "month"
2403
 
                * }
2404
 
                * </pre>
2405
 
                * @config navigator
2406
 
                * @type {Object|Boolean}
2407
 
                * @default null
2408
 
                */
2409
 
                cfg.addProperty(DEF_CFG.NAV.key, { value:DEF_CFG.NAV.value, handler:this.configNavigator } );
2410
 
 
2411
 
                /**
2412
 
                 * The map of UI strings which the Calendar UI uses.
2413
 
                 *
2414
 
                 * @config strings
2415
 
                 * @type {Object}
2416
 
                 * @default An object with the properties shown below:
2417
 
                 *     <dl>
2418
 
                 *         <dt>previousMonth</dt><dd><em>String</em> : The string to use for the "Previous Month" navigation UI. Defaults to "Previous Month".</dd>
2419
 
                 *         <dt>nextMonth</dt><dd><em>String</em> : The string to use for the "Next Month" navigation UI. Defaults to "Next Month".</dd>
2420
 
                 *         <dt>close</dt><dd><em>String</em> : The string to use for the close button label. Defaults to "Close".</dd>
2421
 
                 *     </dl>
2422
 
                 */
2423
 
                cfg.addProperty(DEF_CFG.STRINGS.key, { 
2424
 
                        value:DEF_CFG.STRINGS.value,
2425
 
                        handler:this.configStrings,
2426
 
                        validator: function(val) {
2427
 
                                return Lang.isObject(val);
2428
 
                        },
2429
 
                        supercedes:DEF_CFG.STRINGS.supercedes
2430
 
                });
2431
 
        },
2432
 
 
2433
 
        /**
2434
 
        * The default handler for the "strings" property
2435
 
        * @method configStrings
2436
 
        */
2437
 
        configStrings : function(type, args, obj) {
2438
 
                var val = Lang.merge(DEF_CFG.STRINGS.value, args[0]);
2439
 
                this.cfg.setProperty(DEF_CFG.STRINGS.key, val, true);
2440
 
        },
2441
 
 
2442
 
        /**
2443
 
        * The default handler for the "pagedate" property
2444
 
        * @method configPageDate
2445
 
        */
2446
 
        configPageDate : function(type, args, obj) {
2447
 
                this.cfg.setProperty(DEF_CFG.PAGEDATE.key, this._parsePageDate(args[0]), true);
2448
 
        },
2449
 
 
2450
 
        /**
2451
 
        * The default handler for the "mindate" property
2452
 
        * @method configMinDate
2453
 
        */
2454
 
        configMinDate : function(type, args, obj) {
2455
 
                var val = args[0];
2456
 
                if (Lang.isString(val)) {
2457
 
                        val = this._parseDate(val);
2458
 
                        this.cfg.setProperty(DEF_CFG.MINDATE.key, DateMath.getDate(val[0],(val[1]-1),val[2]));
2459
 
                }
2460
 
        },
2461
 
 
2462
 
        /**
2463
 
        * The default handler for the "maxdate" property
2464
 
        * @method configMaxDate
2465
 
        */
2466
 
        configMaxDate : function(type, args, obj) {
2467
 
                var val = args[0];
2468
 
                if (Lang.isString(val)) {
2469
 
                        val = this._parseDate(val);
2470
 
                        this.cfg.setProperty(DEF_CFG.MAXDATE.key, DateMath.getDate(val[0],(val[1]-1),val[2]));
2471
 
                }
2472
 
        },
2473
 
 
2474
 
        /**
2475
 
        * The default handler for the "selected" property
2476
 
        * @method configSelected
2477
 
        */
2478
 
        configSelected : function(type, args, obj) {
2479
 
                var selected = args[0],
2480
 
                        cfgSelected = DEF_CFG.SELECTED.key;
2481
 
                
2482
 
                if (selected) {
2483
 
                        if (Lang.isString(selected)) {
2484
 
                                this.cfg.setProperty(cfgSelected, this._parseDates(selected), true);
2485
 
                        } 
2486
 
                }
2487
 
                if (! this._selectedDates) {
2488
 
                        this._selectedDates = this.cfg.getProperty(cfgSelected);
2489
 
                }
2490
 
        },
2491
 
        
2492
 
        /**
2493
 
        * The default handler for all configuration options properties
2494
 
        * @method configOptions
2495
 
        */
2496
 
        configOptions : function(type, args, obj) {
2497
 
                this.Options[type.toUpperCase()] = args[0];
2498
 
        },
2499
 
 
2500
 
        /**
2501
 
        * The default handler for all configuration locale properties
2502
 
        * @method configLocale
2503
 
        */
2504
 
        configLocale : function(type, args, obj) {
2505
 
                this.Locale[type.toUpperCase()] = args[0];
2506
 
 
2507
 
                this.cfg.refireEvent(DEF_CFG.LOCALE_MONTHS.key);
2508
 
                this.cfg.refireEvent(DEF_CFG.LOCALE_WEEKDAYS.key);
2509
 
        },
2510
 
        
2511
 
        /**
2512
 
        * The default handler for all configuration locale field length properties
2513
 
        * @method configLocaleValues
2514
 
        */
2515
 
        configLocaleValues : function(type, args, obj) {
2516
 
 
2517
 
                type = type.toLowerCase();
2518
 
 
2519
 
                var val = args[0],
2520
 
                        cfg = this.cfg,
2521
 
                        Locale = this.Locale;
2522
 
 
2523
 
                switch (type) {
2524
 
                        case DEF_CFG.LOCALE_MONTHS.key:
2525
 
                                switch (val) {
2526
 
                                        case Calendar.SHORT:
2527
 
                                                Locale.LOCALE_MONTHS = cfg.getProperty(DEF_CFG.MONTHS_SHORT.key).concat();
2528
 
                                                break;
2529
 
                                        case Calendar.LONG:
2530
 
                                                Locale.LOCALE_MONTHS = cfg.getProperty(DEF_CFG.MONTHS_LONG.key).concat();
2531
 
                                                break;
2532
 
                                }
2533
 
                                break;
2534
 
                        case DEF_CFG.LOCALE_WEEKDAYS.key:
2535
 
                                switch (val) {
2536
 
                                        case Calendar.ONE_CHAR:
2537
 
                                                Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_1CHAR.key).concat();
2538
 
                                                break;
2539
 
                                        case Calendar.SHORT:
2540
 
                                                Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_SHORT.key).concat();
2541
 
                                                break;
2542
 
                                        case Calendar.MEDIUM:
2543
 
                                                Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_MEDIUM.key).concat();
2544
 
                                                break;
2545
 
                                        case Calendar.LONG:
2546
 
                                                Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_LONG.key).concat();
2547
 
                                                break;
2548
 
                                }
2549
 
                                
2550
 
                                var START_WEEKDAY = cfg.getProperty(DEF_CFG.START_WEEKDAY.key);
2551
 
        
2552
 
                                if (START_WEEKDAY > 0) {
2553
 
                                        for (var w=0; w < START_WEEKDAY; ++w) {
2554
 
                                                Locale.LOCALE_WEEKDAYS.push(Locale.LOCALE_WEEKDAYS.shift());
2555
 
                                        }
2556
 
                                }
2557
 
                                break;
2558
 
                }
2559
 
        },
2560
 
 
2561
 
        /**
2562
 
         * The default handler for the "navigator" property
2563
 
         * @method configNavigator
2564
 
         */
2565
 
        configNavigator : function(type, args, obj) {
2566
 
                var val = args[0];
2567
 
                if (YAHOO.widget.CalendarNavigator && (val === true || Lang.isObject(val))) {
2568
 
                        if (!this.oNavigator) {
2569
 
                                this.oNavigator = new YAHOO.widget.CalendarNavigator(this);
2570
 
                                // Cleanup DOM Refs/Events before innerHTML is removed.
2571
 
                                this.beforeRenderEvent.subscribe(function () {
2572
 
                                        if (!this.pages) {
2573
 
                                                this.oNavigator.erase();
2574
 
                                        }
2575
 
                                }, this, true);
2576
 
                        }
2577
 
                } else {
2578
 
                        if (this.oNavigator) {
2579
 
                                this.oNavigator.destroy();
2580
 
                                this.oNavigator = null;
2581
 
                        }
2582
 
                }
2583
 
        },
2584
 
 
2585
 
        /**
2586
 
        * Defines the style constants for the Calendar
2587
 
        * @method initStyles
2588
 
        */
2589
 
        initStyles : function() {
2590
 
 
2591
 
                var defStyle = Calendar._STYLES;
2592
 
 
2593
 
                this.Style = {
2594
 
                        /**
2595
 
                        * @property Style.CSS_ROW_HEADER
2596
 
                        */
2597
 
                        CSS_ROW_HEADER: defStyle.CSS_ROW_HEADER,
2598
 
                        /**
2599
 
                        * @property Style.CSS_ROW_FOOTER
2600
 
                        */
2601
 
                        CSS_ROW_FOOTER: defStyle.CSS_ROW_FOOTER,
2602
 
                        /**
2603
 
                        * @property Style.CSS_CELL
2604
 
                        */
2605
 
                        CSS_CELL : defStyle.CSS_CELL,
2606
 
                        /**
2607
 
                        * @property Style.CSS_CELL_SELECTOR
2608
 
                        */
2609
 
                        CSS_CELL_SELECTOR : defStyle.CSS_CELL_SELECTOR,
2610
 
                        /**
2611
 
                        * @property Style.CSS_CELL_SELECTED
2612
 
                        */
2613
 
                        CSS_CELL_SELECTED : defStyle.CSS_CELL_SELECTED,
2614
 
                        /**
2615
 
                        * @property Style.CSS_CELL_SELECTABLE
2616
 
                        */
2617
 
                        CSS_CELL_SELECTABLE : defStyle.CSS_CELL_SELECTABLE,
2618
 
                        /**
2619
 
                        * @property Style.CSS_CELL_RESTRICTED
2620
 
                        */
2621
 
                        CSS_CELL_RESTRICTED : defStyle.CSS_CELL_RESTRICTED,
2622
 
                        /**
2623
 
                        * @property Style.CSS_CELL_TODAY
2624
 
                        */
2625
 
                        CSS_CELL_TODAY : defStyle.CSS_CELL_TODAY,
2626
 
                        /**
2627
 
                        * @property Style.CSS_CELL_OOM
2628
 
                        */
2629
 
                        CSS_CELL_OOM : defStyle.CSS_CELL_OOM,
2630
 
                        /**
2631
 
                        * @property Style.CSS_CELL_OOB
2632
 
                        */
2633
 
                        CSS_CELL_OOB : defStyle.CSS_CELL_OOB,
2634
 
                        /**
2635
 
                        * @property Style.CSS_HEADER
2636
 
                        */
2637
 
                        CSS_HEADER : defStyle.CSS_HEADER,
2638
 
                        /**
2639
 
                        * @property Style.CSS_HEADER_TEXT
2640
 
                        */
2641
 
                        CSS_HEADER_TEXT : defStyle.CSS_HEADER_TEXT,
2642
 
                        /**
2643
 
                        * @property Style.CSS_BODY
2644
 
                        */
2645
 
                        CSS_BODY : defStyle.CSS_BODY,
2646
 
                        /**
2647
 
                        * @property Style.CSS_WEEKDAY_CELL
2648
 
                        */
2649
 
                        CSS_WEEKDAY_CELL : defStyle.CSS_WEEKDAY_CELL,
2650
 
                        /**
2651
 
                        * @property Style.CSS_WEEKDAY_ROW
2652
 
                        */
2653
 
                        CSS_WEEKDAY_ROW : defStyle.CSS_WEEKDAY_ROW,
2654
 
                        /**
2655
 
                        * @property Style.CSS_FOOTER
2656
 
                        */
2657
 
                        CSS_FOOTER : defStyle.CSS_FOOTER,
2658
 
                        /**
2659
 
                        * @property Style.CSS_CALENDAR
2660
 
                        */
2661
 
                        CSS_CALENDAR : defStyle.CSS_CALENDAR,
2662
 
                        /**
2663
 
                        * @property Style.CSS_SINGLE
2664
 
                        */
2665
 
                        CSS_SINGLE : defStyle.CSS_SINGLE,
2666
 
                        /**
2667
 
                        * @property Style.CSS_CONTAINER
2668
 
                        */
2669
 
                        CSS_CONTAINER : defStyle.CSS_CONTAINER,
2670
 
                        /**
2671
 
                        * @property Style.CSS_NAV_LEFT
2672
 
                        */
2673
 
                        CSS_NAV_LEFT : defStyle.CSS_NAV_LEFT,
2674
 
                        /**
2675
 
                        * @property Style.CSS_NAV_RIGHT
2676
 
                        */
2677
 
                        CSS_NAV_RIGHT : defStyle.CSS_NAV_RIGHT,
2678
 
                        /**
2679
 
                        * @property Style.CSS_NAV
2680
 
                        */
2681
 
                        CSS_NAV : defStyle.CSS_NAV,
2682
 
                        /**
2683
 
                        * @property Style.CSS_CLOSE
2684
 
                        */
2685
 
                        CSS_CLOSE : defStyle.CSS_CLOSE,
2686
 
                        /**
2687
 
                        * @property Style.CSS_CELL_TOP
2688
 
                        */
2689
 
                        CSS_CELL_TOP : defStyle.CSS_CELL_TOP,
2690
 
                        /**
2691
 
                        * @property Style.CSS_CELL_LEFT
2692
 
                        */
2693
 
                        CSS_CELL_LEFT : defStyle.CSS_CELL_LEFT,
2694
 
                        /**
2695
 
                        * @property Style.CSS_CELL_RIGHT
2696
 
                        */
2697
 
                        CSS_CELL_RIGHT : defStyle.CSS_CELL_RIGHT,
2698
 
                        /**
2699
 
                        * @property Style.CSS_CELL_BOTTOM
2700
 
                        */
2701
 
                        CSS_CELL_BOTTOM : defStyle.CSS_CELL_BOTTOM,
2702
 
                        /**
2703
 
                        * @property Style.CSS_CELL_HOVER
2704
 
                        */
2705
 
                        CSS_CELL_HOVER : defStyle.CSS_CELL_HOVER,
2706
 
                        /**
2707
 
                        * @property Style.CSS_CELL_HIGHLIGHT1
2708
 
                        */
2709
 
                        CSS_CELL_HIGHLIGHT1 : defStyle.CSS_CELL_HIGHLIGHT1,
2710
 
                        /**
2711
 
                        * @property Style.CSS_CELL_HIGHLIGHT2
2712
 
                        */
2713
 
                        CSS_CELL_HIGHLIGHT2 : defStyle.CSS_CELL_HIGHLIGHT2,
2714
 
                        /**
2715
 
                        * @property Style.CSS_CELL_HIGHLIGHT3
2716
 
                        */
2717
 
                        CSS_CELL_HIGHLIGHT3 : defStyle.CSS_CELL_HIGHLIGHT3,
2718
 
                        /**
2719
 
                        * @property Style.CSS_CELL_HIGHLIGHT4
2720
 
                        */
2721
 
                        CSS_CELL_HIGHLIGHT4 : defStyle.CSS_CELL_HIGHLIGHT4
2722
 
                };
2723
 
        },
2724
 
 
2725
 
        /**
2726
 
        * Builds the date label that will be displayed in the calendar header or
2727
 
        * footer, depending on configuration.
2728
 
        * @method buildMonthLabel
2729
 
        * @return       {String}        The formatted calendar month label
2730
 
        */
2731
 
        buildMonthLabel : function() {
2732
 
                return this._buildMonthLabel(this.cfg.getProperty(DEF_CFG.PAGEDATE.key));
2733
 
        },
2734
 
 
2735
 
    /**
2736
 
     * Helper method, to format a Month Year string, given a JavaScript Date, based on the 
2737
 
     * Calendar localization settings
2738
 
     * 
2739
 
     * @method _buildMonthLabel
2740
 
     * @private
2741
 
     * @param {Date} date
2742
 
     * @return {String} Formated month, year string
2743
 
     */
2744
 
        _buildMonthLabel : function(date) {
2745
 
                var     monthLabel  = this.Locale.LOCALE_MONTHS[date.getMonth()] + this.Locale.MY_LABEL_MONTH_SUFFIX,
2746
 
                        yearLabel = date.getFullYear() + this.Locale.MY_LABEL_YEAR_SUFFIX;
2747
 
 
2748
 
                if (this.Locale.MY_LABEL_MONTH_POSITION == 2 || this.Locale.MY_LABEL_YEAR_POSITION == 1) {
2749
 
                        return yearLabel + monthLabel;
2750
 
                } else {
2751
 
                        return monthLabel + yearLabel;
2752
 
                }
2753
 
        },
2754
 
        
2755
 
        /**
2756
 
        * Builds the date digit that will be displayed in calendar cells
2757
 
        * @method buildDayLabel
2758
 
        * @param {Date} workingDate     The current working date
2759
 
        * @return       {String}        The formatted day label
2760
 
        */
2761
 
        buildDayLabel : function(workingDate) {
2762
 
                return workingDate.getDate();
2763
 
        },
2764
 
        
2765
 
        /**
2766
 
         * Creates the title bar element and adds it to Calendar container DIV
2767
 
         * 
2768
 
         * @method createTitleBar
2769
 
         * @param {String} strTitle The title to display in the title bar
2770
 
         * @return The title bar element
2771
 
         */
2772
 
        createTitleBar : function(strTitle) {
2773
 
                var tDiv = Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || document.createElement("div");
2774
 
                tDiv.className = YAHOO.widget.CalendarGroup.CSS_2UPTITLE;
2775
 
                tDiv.innerHTML = strTitle;
2776
 
                this.oDomContainer.insertBefore(tDiv, this.oDomContainer.firstChild);
2777
 
        
2778
 
                Dom.addClass(this.oDomContainer, "withtitle");
2779
 
        
2780
 
                return tDiv;
2781
 
        },
2782
 
        
2783
 
        /**
2784
 
         * Removes the title bar element from the DOM
2785
 
         * 
2786
 
         * @method removeTitleBar
2787
 
         */
2788
 
        removeTitleBar : function() {
2789
 
                var tDiv = Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || null;
2790
 
                if (tDiv) {
2791
 
                        Event.purgeElement(tDiv);
2792
 
                        this.oDomContainer.removeChild(tDiv);
2793
 
                }
2794
 
                Dom.removeClass(this.oDomContainer, "withtitle");
2795
 
        },
2796
 
        
2797
 
        /**
2798
 
         * Creates the close button HTML element and adds it to Calendar container DIV
2799
 
         * 
2800
 
         * @method createCloseButton
2801
 
         * @return The close HTML element created
2802
 
         */
2803
 
        createCloseButton : function() {
2804
 
                var cssClose = YAHOO.widget.CalendarGroup.CSS_2UPCLOSE,
2805
 
                        DEPR_CLOSE_PATH = "us/my/bn/x_d.gif",
2806
 
                        lnk = Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0],
2807
 
                        strings = this.cfg.getProperty(DEF_CFG.STRINGS.key),
2808
 
                        closeStr = (strings && strings.close) ? strings.close : "";
2809
 
 
2810
 
                if (!lnk) {
2811
 
                        lnk = document.createElement("a");
2812
 
                        Event.addListener(lnk, "click", function(e, cal) {
2813
 
                                cal.hide(); 
2814
 
                                Event.preventDefault(e);
2815
 
                        }, this);
2816
 
                }
2817
 
 
2818
 
                lnk.href = "#";
2819
 
                lnk.className = "link-close";
2820
 
 
2821
 
                if (Calendar.IMG_ROOT !== null) {
2822
 
                        var img = Dom.getElementsByClassName(cssClose, "img", lnk)[0] || document.createElement("img");
2823
 
                        img.src = Calendar.IMG_ROOT + DEPR_CLOSE_PATH;
2824
 
                        img.className = cssClose;
2825
 
                        lnk.appendChild(img);
2826
 
                } else {
2827
 
                        lnk.innerHTML = '<span class="' + cssClose + ' ' + this.Style.CSS_CLOSE + '">' + closeStr + '</span>';
2828
 
                }
2829
 
                this.oDomContainer.appendChild(lnk);
2830
 
 
2831
 
                return lnk;
2832
 
        },
2833
 
        
2834
 
        /**
2835
 
         * Removes the close button HTML element from the DOM
2836
 
         * 
2837
 
         * @method removeCloseButton
2838
 
         */
2839
 
        removeCloseButton : function() {
2840
 
                var btn = Dom.getElementsByClassName("link-close", "a", this.oDomContainer)[0] || null;
2841
 
                if (btn) {
2842
 
                        Event.purgeElement(btn);
2843
 
                        this.oDomContainer.removeChild(btn);
2844
 
                }
2845
 
        },
2846
 
 
2847
 
        /**
2848
 
        * Renders the calendar header.
2849
 
        * @method renderHeader
2850
 
        * @param {Array}        html    The current working HTML array
2851
 
        * @return {Array} The current working HTML array
2852
 
        */
2853
 
        renderHeader : function(html) {
2854
 
 
2855
 
 
2856
 
                var colSpan = 7,
2857
 
                        DEPR_NAV_LEFT = "us/tr/callt.gif",
2858
 
                        DEPR_NAV_RIGHT = "us/tr/calrt.gif",
2859
 
                        cfg = this.cfg,
2860
 
                        pageDate = cfg.getProperty(DEF_CFG.PAGEDATE.key),
2861
 
                        strings= cfg.getProperty(DEF_CFG.STRINGS.key),
2862
 
                        prevStr = (strings && strings.previousMonth) ?  strings.previousMonth : "",
2863
 
                        nextStr = (strings && strings.nextMonth) ? strings.nextMonth : "",
2864
 
            monthLabel;
2865
 
 
2866
 
                if (cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key)) {
2867
 
                        colSpan += 1;
2868
 
                }
2869
 
        
2870
 
                if (cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key)) {
2871
 
                        colSpan += 1;
2872
 
                }
2873
 
 
2874
 
                html[html.length] = "<thead>";
2875
 
                html[html.length] =             "<tr>";
2876
 
                html[html.length] =                     '<th colspan="' + colSpan + '" class="' + this.Style.CSS_HEADER_TEXT + '">';
2877
 
                html[html.length] =                             '<div class="' + this.Style.CSS_HEADER + '">';
2878
 
 
2879
 
                var renderLeft, renderRight = false;
2880
 
 
2881
 
                if (this.parent) {
2882
 
                        if (this.index === 0) {
2883
 
                                renderLeft = true;
2884
 
                        }
2885
 
                        if (this.index == (this.parent.cfg.getProperty("pages") -1)) {
2886
 
                                renderRight = true;
2887
 
                        }
2888
 
                } else {
2889
 
                        renderLeft = true;
2890
 
                        renderRight = true;
2891
 
                }
2892
 
 
2893
 
                if (renderLeft) {
2894
 
                        monthLabel  = this._buildMonthLabel(DateMath.subtract(pageDate, DateMath.MONTH, 1));
2895
 
 
2896
 
                        var leftArrow = cfg.getProperty(DEF_CFG.NAV_ARROW_LEFT.key);
2897
 
                        // Check for deprecated customization - If someone set IMG_ROOT, but didn't set NAV_ARROW_LEFT, then set NAV_ARROW_LEFT to the old deprecated value
2898
 
                        if (leftArrow === null && Calendar.IMG_ROOT !== null) {
2899
 
                                leftArrow = Calendar.IMG_ROOT + DEPR_NAV_LEFT;
2900
 
                        }
2901
 
                        var leftStyle = (leftArrow === null) ? "" : ' style="background-image:url(' + leftArrow + ')"';
2902
 
                        html[html.length] = '<a class="' + this.Style.CSS_NAV_LEFT + '"' + leftStyle + ' href="#">' + prevStr + ' (' + monthLabel + ')' + '</a>';
2903
 
                }
2904
 
 
2905
 
                var lbl = this.buildMonthLabel();
2906
 
                var cal = this.parent || this;
2907
 
                if (cal.cfg.getProperty("navigator")) {
2908
 
                        lbl = "<a class=\"" + this.Style.CSS_NAV + "\" href=\"#\">" + lbl + "</a>";
2909
 
                }
2910
 
                html[html.length] = lbl;
2911
 
 
2912
 
                if (renderRight) {
2913
 
                        monthLabel  = this._buildMonthLabel(DateMath.add(pageDate, DateMath.MONTH, 1));
2914
 
 
2915
 
                        var rightArrow = cfg.getProperty(DEF_CFG.NAV_ARROW_RIGHT.key);
2916
 
                        if (rightArrow === null && Calendar.IMG_ROOT !== null) {
2917
 
                                rightArrow = Calendar.IMG_ROOT + DEPR_NAV_RIGHT;
2918
 
                        }
2919
 
                        var rightStyle = (rightArrow === null) ? "" : ' style="background-image:url(' + rightArrow + ')"';
2920
 
                        html[html.length] = '<a class="' + this.Style.CSS_NAV_RIGHT + '"' + rightStyle + ' href="#">' + nextStr + ' (' + monthLabel + ')' + '</a>';
2921
 
                }
2922
 
 
2923
 
                html[html.length] =     '</div>\n</th>\n</tr>';
2924
 
 
2925
 
                if (cfg.getProperty(DEF_CFG.SHOW_WEEKDAYS.key)) {
2926
 
                        html = this.buildWeekdays(html);
2927
 
                }
2928
 
                
2929
 
                html[html.length] = '</thead>';
2930
 
        
2931
 
                return html;
2932
 
        },
2933
 
        
2934
 
        /**
2935
 
        * Renders the Calendar's weekday headers.
2936
 
        * @method buildWeekdays
2937
 
        * @param {Array}        html    The current working HTML array
2938
 
        * @return {Array} The current working HTML array
2939
 
        */
2940
 
        buildWeekdays : function(html) {
2941
 
 
2942
 
                html[html.length] = '<tr class="' + this.Style.CSS_WEEKDAY_ROW + '">';
2943
 
 
2944
 
                if (this.cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key)) {
2945
 
                        html[html.length] = '<th>&#160;</th>';
2946
 
                }
2947
 
 
2948
 
                for(var i=0;i < this.Locale.LOCALE_WEEKDAYS.length; ++i) {
2949
 
                        html[html.length] = '<th class="calweekdaycell">' + this.Locale.LOCALE_WEEKDAYS[i] + '</th>';
2950
 
                }
2951
 
 
2952
 
                if (this.cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key)) {
2953
 
                        html[html.length] = '<th>&#160;</th>';
2954
 
                }
2955
 
 
2956
 
                html[html.length] = '</tr>';
2957
 
 
2958
 
                return html;
2959
 
        },
2960
 
        
2961
 
        /**
2962
 
        * Renders the calendar body.
2963
 
        * @method renderBody
2964
 
        * @param {Date} workingDate     The current working Date being used for the render process
2965
 
        * @param {Array}        html    The current working HTML array
2966
 
        * @return {Array} The current working HTML array
2967
 
        */
2968
 
        renderBody : function(workingDate, html) {
2969
 
 
2970
 
                var startDay = this.cfg.getProperty(DEF_CFG.START_WEEKDAY.key);
2971
 
 
2972
 
                this.preMonthDays = workingDate.getDay();
2973
 
                if (startDay > 0) {
2974
 
                        this.preMonthDays -= startDay;
2975
 
                }
2976
 
                if (this.preMonthDays < 0) {
2977
 
                        this.preMonthDays += 7;
2978
 
                }
2979
 
 
2980
 
                this.monthDays = DateMath.findMonthEnd(workingDate).getDate();
2981
 
                this.postMonthDays = Calendar.DISPLAY_DAYS-this.preMonthDays-this.monthDays;
2982
 
 
2983
 
 
2984
 
                workingDate = DateMath.subtract(workingDate, DateMath.DAY, this.preMonthDays);
2985
 
        
2986
 
                var weekNum,
2987
 
                        weekClass,
2988
 
                        weekPrefix = "w",
2989
 
                        cellPrefix = "_cell",
2990
 
                        workingDayPrefix = "wd",
2991
 
                        dayPrefix = "d",
2992
 
                        cellRenderers,
2993
 
                        renderer,
2994
 
                        t = this.today,
2995
 
                        cfg = this.cfg,
2996
 
                        todayYear = t.getFullYear(),
2997
 
                        todayMonth = t.getMonth(),
2998
 
                        todayDate = t.getDate(),
2999
 
                        useDate = cfg.getProperty(DEF_CFG.PAGEDATE.key),
3000
 
                        hideBlankWeeks = cfg.getProperty(DEF_CFG.HIDE_BLANK_WEEKS.key),
3001
 
                        showWeekFooter = cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key),
3002
 
                        showWeekHeader = cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key),
3003
 
                        mindate = cfg.getProperty(DEF_CFG.MINDATE.key),
3004
 
                        maxdate = cfg.getProperty(DEF_CFG.MAXDATE.key);
3005
 
 
3006
 
                if (mindate) {
3007
 
                        mindate = DateMath.clearTime(mindate);
3008
 
                }
3009
 
                if (maxdate) {
3010
 
                        maxdate = DateMath.clearTime(maxdate);
3011
 
                }
3012
 
 
3013
 
                html[html.length] = '<tbody class="m' + (useDate.getMonth()+1) + ' ' + this.Style.CSS_BODY + '">';
3014
 
 
3015
 
                var i = 0,
3016
 
                        tempDiv = document.createElement("div"),
3017
 
                        cell = document.createElement("td");
3018
 
 
3019
 
                tempDiv.appendChild(cell);
3020
 
 
3021
 
                var cal = this.parent || this;
3022
 
 
3023
 
                for (var r=0;r<6;r++) {
3024
 
                        weekNum = DateMath.getWeekNumber(workingDate, startDay);
3025
 
                        weekClass = weekPrefix + weekNum;
3026
 
 
3027
 
                        // Local OOM check for performance, since we already have pagedate
3028
 
                        if (r !== 0 && hideBlankWeeks === true && workingDate.getMonth() != useDate.getMonth()) {
3029
 
                                break;
3030
 
                        } else {
3031
 
                                html[html.length] = '<tr class="' + weekClass + '">';
3032
 
 
3033
 
                                if (showWeekHeader) { html = this.renderRowHeader(weekNum, html); }
3034
 
 
3035
 
                                for (var d=0; d < 7; d++){ // Render actual days
3036
 
 
3037
 
                                        cellRenderers = [];
3038
 
 
3039
 
                                        this.clearElement(cell);
3040
 
                                        cell.className = this.Style.CSS_CELL;
3041
 
                                        cell.id = this.id + cellPrefix + i;
3042
 
 
3043
 
                                        if (workingDate.getDate()               == todayDate && 
3044
 
                                                workingDate.getMonth()          == todayMonth &&
3045
 
                                                workingDate.getFullYear()       == todayYear) {
3046
 
                                                cellRenderers[cellRenderers.length]=cal.renderCellStyleToday;
3047
 
                                        }
3048
 
 
3049
 
                                        var workingArray = [workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()];
3050
 
                                        this.cellDates[this.cellDates.length] = workingArray; // Add this date to cellDates
3051
 
 
3052
 
                                        // Local OOM check for performance, since we already have pagedate
3053
 
                                        if (workingDate.getMonth() != useDate.getMonth()) {
3054
 
                                                cellRenderers[cellRenderers.length]=cal.renderCellNotThisMonth;
3055
 
                                        } else {
3056
 
                                                Dom.addClass(cell, workingDayPrefix + workingDate.getDay());
3057
 
                                                Dom.addClass(cell, dayPrefix + workingDate.getDate());
3058
 
 
3059
 
                                                for (var s=0;s<this.renderStack.length;++s) {
3060
 
 
3061
 
                                                        renderer = null;
3062
 
 
3063
 
                                                        var rArray = this.renderStack[s],
3064
 
                                                                type = rArray[0],
3065
 
                                                                month,
3066
 
                                                                day,
3067
 
                                                                year;
3068
 
 
3069
 
                                                        switch (type) {
3070
 
                                                                case Calendar.DATE:
3071
 
                                                                        month = rArray[1][1];
3072
 
                                                                        day = rArray[1][2];
3073
 
                                                                        year = rArray[1][0];
3074
 
 
3075
 
                                                                        if (workingDate.getMonth()+1 == month && workingDate.getDate() == day && workingDate.getFullYear() == year) {
3076
 
                                                                                renderer = rArray[2];
3077
 
                                                                                this.renderStack.splice(s,1);
3078
 
                                                                        }
3079
 
                                                                        break;
3080
 
                                                                case Calendar.MONTH_DAY:
3081
 
                                                                        month = rArray[1][0];
3082
 
                                                                        day = rArray[1][1];
3083
 
 
3084
 
                                                                        if (workingDate.getMonth()+1 == month && workingDate.getDate() == day) {
3085
 
                                                                                renderer = rArray[2];
3086
 
                                                                                this.renderStack.splice(s,1);
3087
 
                                                                        }
3088
 
                                                                        break;
3089
 
                                                                case Calendar.RANGE:
3090
 
                                                                        var date1 = rArray[1][0],
3091
 
                                                                                date2 = rArray[1][1],
3092
 
                                                                                d1month = date1[1],
3093
 
                                                                                d1day = date1[2],
3094
 
                                                                                d1year = date1[0],
3095
 
                                                                                d1 = DateMath.getDate(d1year, d1month-1, d1day),
3096
 
                                                                                d2month = date2[1],
3097
 
                                                                                d2day = date2[2],
3098
 
                                                                                d2year = date2[0],
3099
 
                                                                                d2 = DateMath.getDate(d2year, d2month-1, d2day);
3100
 
 
3101
 
                                                                        if (workingDate.getTime() >= d1.getTime() && workingDate.getTime() <= d2.getTime()) {
3102
 
                                                                                renderer = rArray[2];
3103
 
 
3104
 
                                                                                if (workingDate.getTime()==d2.getTime()) { 
3105
 
                                                                                        this.renderStack.splice(s,1);
3106
 
                                                                                }
3107
 
                                                                        }
3108
 
                                                                        break;
3109
 
                                                                case Calendar.WEEKDAY:
3110
 
                                                                        var weekday = rArray[1][0];
3111
 
                                                                        if (workingDate.getDay()+1 == weekday) {
3112
 
                                                                                renderer = rArray[2];
3113
 
                                                                        }
3114
 
                                                                        break;
3115
 
                                                                case Calendar.MONTH:
3116
 
                                                                        month = rArray[1][0];
3117
 
                                                                        if (workingDate.getMonth()+1 == month) {
3118
 
                                                                                renderer = rArray[2];
3119
 
                                                                        }
3120
 
                                                                        break;
3121
 
                                                        }
3122
 
 
3123
 
                                                        if (renderer) {
3124
 
                                                                cellRenderers[cellRenderers.length]=renderer;
3125
 
                                                        }
3126
 
                                                }
3127
 
 
3128
 
                                        }
3129
 
 
3130
 
                                        if (this._indexOfSelectedFieldArray(workingArray) > -1) {
3131
 
                                                cellRenderers[cellRenderers.length]=cal.renderCellStyleSelected; 
3132
 
                                        }
3133
 
 
3134
 
                                        if ((mindate && (workingDate.getTime() < mindate.getTime())) ||
3135
 
                                                (maxdate && (workingDate.getTime() > maxdate.getTime()))
3136
 
                                        ) {
3137
 
                                                cellRenderers[cellRenderers.length]=cal.renderOutOfBoundsDate;
3138
 
                                        } else {
3139
 
                                                cellRenderers[cellRenderers.length]=cal.styleCellDefault;
3140
 
                                                cellRenderers[cellRenderers.length]=cal.renderCellDefault;      
3141
 
                                        }
3142
 
 
3143
 
                                        for (var x=0; x < cellRenderers.length; ++x) {
3144
 
                                                if (cellRenderers[x].call(cal, workingDate, cell) == Calendar.STOP_RENDER) {
3145
 
                                                        break;
3146
 
                                                }
3147
 
                                        }
3148
 
 
3149
 
                                        workingDate.setTime(workingDate.getTime() + DateMath.ONE_DAY_MS);
3150
 
                                        // Just in case we crossed DST/Summertime boundaries
3151
 
                                        workingDate = DateMath.clearTime(workingDate);
3152
 
 
3153
 
                                        if (i >= 0 && i <= 6) {
3154
 
                                                Dom.addClass(cell, this.Style.CSS_CELL_TOP);
3155
 
                                        }
3156
 
                                        if ((i % 7) === 0) {
3157
 
                                                Dom.addClass(cell, this.Style.CSS_CELL_LEFT);
3158
 
                                        }
3159
 
                                        if (((i+1) % 7) === 0) {
3160
 
                                                Dom.addClass(cell, this.Style.CSS_CELL_RIGHT);
3161
 
                                        }
3162
 
 
3163
 
                                        var postDays = this.postMonthDays; 
3164
 
                                        if (hideBlankWeeks && postDays >= 7) {
3165
 
                                                var blankWeeks = Math.floor(postDays/7);
3166
 
                                                for (var p=0;p<blankWeeks;++p) {
3167
 
                                                        postDays -= 7;
3168
 
                                                }
3169
 
                                        }
3170
 
                                        
3171
 
                                        if (i >= ((this.preMonthDays+postDays+this.monthDays)-7)) {
3172
 
                                                Dom.addClass(cell, this.Style.CSS_CELL_BOTTOM);
3173
 
                                        }
3174
 
        
3175
 
                                        html[html.length] = tempDiv.innerHTML;
3176
 
                                        i++;
3177
 
                                }
3178
 
        
3179
 
                                if (showWeekFooter) { html = this.renderRowFooter(weekNum, html); }
3180
 
        
3181
 
                                html[html.length] = '</tr>';
3182
 
                        }
3183
 
                }
3184
 
        
3185
 
                html[html.length] = '</tbody>';
3186
 
        
3187
 
                return html;
3188
 
        },
3189
 
        
3190
 
        /**
3191
 
        * Renders the calendar footer. In the default implementation, there is
3192
 
        * no footer.
3193
 
        * @method renderFooter
3194
 
        * @param {Array}        html    The current working HTML array
3195
 
        * @return {Array} The current working HTML array
3196
 
        */
3197
 
        renderFooter : function(html) { return html; },
3198
 
        
3199
 
        /**
3200
 
        * Renders the calendar after it has been configured. The render() method has a specific call chain that will execute
3201
 
        * when the method is called: renderHeader, renderBody, renderFooter.
3202
 
        * Refer to the documentation for those methods for information on 
3203
 
        * individual render tasks.
3204
 
        * @method render
3205
 
        */
3206
 
        render : function() {
3207
 
                this.beforeRenderEvent.fire();
3208
 
 
3209
 
                // Find starting day of the current month
3210
 
                var workingDate = DateMath.findMonthStart(this.cfg.getProperty(DEF_CFG.PAGEDATE.key));
3211
 
 
3212
 
                this.resetRenderers();
3213
 
                this.cellDates.length = 0;
3214
 
 
3215
 
                Event.purgeElement(this.oDomContainer, true);
3216
 
 
3217
 
                var html = [];
3218
 
 
3219
 
                html[html.length] = '<table cellSpacing="0" class="' + this.Style.CSS_CALENDAR + ' y' + workingDate.getFullYear() + '" id="' + this.id + '">';
3220
 
                html = this.renderHeader(html);
3221
 
                html = this.renderBody(workingDate, html);
3222
 
                html = this.renderFooter(html);
3223
 
                html[html.length] = '</table>';
3224
 
 
3225
 
                this.oDomContainer.innerHTML = html.join("\n");
3226
 
 
3227
 
                this.applyListeners();
3228
 
                this.cells = this.oDomContainer.getElementsByTagName("td");
3229
 
        
3230
 
                this.cfg.refireEvent(DEF_CFG.TITLE.key);
3231
 
                this.cfg.refireEvent(DEF_CFG.CLOSE.key);
3232
 
                this.cfg.refireEvent(DEF_CFG.IFRAME.key);
3233
 
 
3234
 
                this.renderEvent.fire();
3235
 
        },
3236
 
 
3237
 
        /**
3238
 
        * Applies the Calendar's DOM listeners to applicable elements.
3239
 
        * @method applyListeners
3240
 
        */
3241
 
        applyListeners : function() {
3242
 
                var root = this.oDomContainer,
3243
 
                        cal = this.parent || this,
3244
 
                        anchor = "a",
3245
 
                        click = "click";
3246
 
 
3247
 
                var linkLeft = Dom.getElementsByClassName(this.Style.CSS_NAV_LEFT, anchor, root),
3248
 
                        linkRight = Dom.getElementsByClassName(this.Style.CSS_NAV_RIGHT, anchor, root);
3249
 
 
3250
 
                if (linkLeft && linkLeft.length > 0) {
3251
 
                        this.linkLeft = linkLeft[0];
3252
 
                        Event.addListener(this.linkLeft, click, this.doPreviousMonthNav, cal, true);
3253
 
                }
3254
 
 
3255
 
                if (linkRight && linkRight.length > 0) {
3256
 
                        this.linkRight = linkRight[0];
3257
 
                        Event.addListener(this.linkRight, click, this.doNextMonthNav, cal, true);
3258
 
                }
3259
 
 
3260
 
                if (cal.cfg.getProperty("navigator") !== null) {
3261
 
                        this.applyNavListeners();
3262
 
                }
3263
 
 
3264
 
                if (this.domEventMap) {
3265
 
                        var el,elements;
3266
 
                        for (var cls in this.domEventMap) {     
3267
 
                                if (Lang.hasOwnProperty(this.domEventMap, cls)) {
3268
 
                                        var items = this.domEventMap[cls];
3269
 
        
3270
 
                                        if (! (items instanceof Array)) {
3271
 
                                                items = [items];
3272
 
                                        }
3273
 
        
3274
 
                                        for (var i=0;i<items.length;i++)        {
3275
 
                                                var item = items[i];
3276
 
                                                elements = Dom.getElementsByClassName(cls, item.tag, this.oDomContainer);
3277
 
        
3278
 
                                                for (var c=0;c<elements.length;c++) {
3279
 
                                                        el = elements[c];
3280
 
                                                         Event.addListener(el, item.event, item.handler, item.scope, item.correct );
3281
 
                                                }
3282
 
                                        }
3283
 
                                }
3284
 
                        }
3285
 
                }
3286
 
 
3287
 
                Event.addListener(this.oDomContainer, "click", this.doSelectCell, this);
3288
 
                Event.addListener(this.oDomContainer, "mouseover", this.doCellMouseOver, this);
3289
 
                Event.addListener(this.oDomContainer, "mouseout", this.doCellMouseOut, this);
3290
 
        },
3291
 
 
3292
 
        applyNavListeners : function() {
3293
 
                var calParent = this.parent || this,
3294
 
                        cal = this,
3295
 
                        navBtns = Dom.getElementsByClassName(this.Style.CSS_NAV, "a", this.oDomContainer);
3296
 
 
3297
 
                if (navBtns.length > 0) {
3298
 
 
3299
 
                        Event.addListener(navBtns, "click", function (e, obj) {
3300
 
                                var target = Event.getTarget(e);
3301
 
                                // this == navBtn
3302
 
                                if (this === target || Dom.isAncestor(this, target)) {
3303
 
                                        Event.preventDefault(e);
3304
 
                                }
3305
 
                                var navigator = calParent.oNavigator;
3306
 
                                if (navigator) {
3307
 
                                        var pgdate = cal.cfg.getProperty("pagedate");
3308
 
                                        navigator.setYear(pgdate.getFullYear());
3309
 
                                        navigator.setMonth(pgdate.getMonth());
3310
 
                                        navigator.show();
3311
 
                                }
3312
 
                        });
3313
 
                }
3314
 
        },
3315
 
 
3316
 
        /**
3317
 
        * Retrieves the Date object for the specified Calendar cell
3318
 
        * @method getDateByCellId
3319
 
        * @param {String}       id      The id of the cell
3320
 
        * @return {Date} The Date object for the specified Calendar cell
3321
 
        */
3322
 
        getDateByCellId : function(id) {
3323
 
                var date = this.getDateFieldsByCellId(id);
3324
 
                return (date) ? DateMath.getDate(date[0],date[1]-1,date[2]) : null;
3325
 
        },
3326
 
        
3327
 
        /**
3328
 
        * Retrieves the Date object for the specified Calendar cell
3329
 
        * @method getDateFieldsByCellId
3330
 
        * @param {String}       id      The id of the cell
3331
 
        * @return {Array}       The array of Date fields for the specified Calendar cell
3332
 
        */
3333
 
        getDateFieldsByCellId : function(id) {
3334
 
                id = this.getIndexFromId(id);
3335
 
                return (id > -1) ? this.cellDates[id] : null;
3336
 
        },
3337
 
 
3338
 
        /**
3339
 
         * Find the Calendar's cell index for a given date.
3340
 
         * If the date is not found, the method returns -1.
3341
 
         * <p>
3342
 
         * The returned index can be used to lookup the cell HTMLElement  
3343
 
         * using the Calendar's cells array or passed to selectCell to select 
3344
 
         * cells by index. 
3345
 
         * </p>
3346
 
         *
3347
 
         * See <a href="#cells">cells</a>, <a href="#selectCell">selectCell</a>.
3348
 
         *
3349
 
         * @method getCellIndex
3350
 
         * @param {Date} date JavaScript Date object, for which to find a cell index.
3351
 
         * @return {Number} The index of the date in Calendars cellDates/cells arrays, or -1 if the date 
3352
 
         * is not on the curently rendered Calendar page.
3353
 
         */
3354
 
        getCellIndex : function(date) {
3355
 
                var idx = -1;
3356
 
                if (date) {
3357
 
                        var m = date.getMonth(),
3358
 
                                y = date.getFullYear(),
3359
 
                                d = date.getDate(),
3360
 
                                dates = this.cellDates;
3361
 
 
3362
 
                        for (var i = 0; i < dates.length; ++i) {
3363
 
                                var cellDate = dates[i];
3364
 
                                if (cellDate[0] === y && cellDate[1] === m+1 && cellDate[2] === d) {
3365
 
                                        idx = i;
3366
 
                                        break;
3367
 
                                }
3368
 
                        }
3369
 
                }
3370
 
                return idx;
3371
 
        },
3372
 
 
3373
 
        /**
3374
 
         * Given the id used to mark each Calendar cell, this method
3375
 
         * extracts the index number from the id.
3376
 
         * 
3377
 
         * @param {String} strId The cell id
3378
 
         * @return {Number} The index of the cell, or -1 if id does not contain an index number
3379
 
         */
3380
 
        getIndexFromId : function(strId) {
3381
 
                var idx = -1,
3382
 
                        li = strId.lastIndexOf("_cell");
3383
 
 
3384
 
                if (li > -1) {
3385
 
                        idx = parseInt(strId.substring(li + 5), 10);
3386
 
                }
3387
 
 
3388
 
                return idx;
3389
 
        },
3390
 
        
3391
 
        // BEGIN BUILT-IN TABLE CELL RENDERERS
3392
 
        
3393
 
        /**
3394
 
        * Renders a cell that falls before the minimum date or after the maximum date.
3395
 
        * widget class.
3396
 
        * @method renderOutOfBoundsDate
3397
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3398
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3399
 
        * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
3400
 
        *                       should not be terminated
3401
 
        */
3402
 
        renderOutOfBoundsDate : function(workingDate, cell) {
3403
 
                Dom.addClass(cell, this.Style.CSS_CELL_OOB);
3404
 
                cell.innerHTML = workingDate.getDate();
3405
 
                return Calendar.STOP_RENDER;
3406
 
        },
3407
 
        
3408
 
        /**
3409
 
        * Renders the row header for a week.
3410
 
        * @method renderRowHeader
3411
 
        * @param {Number}       weekNum The week number of the current row
3412
 
        * @param {Array}        cell    The current working HTML array
3413
 
        */
3414
 
        renderRowHeader : function(weekNum, html) {
3415
 
                html[html.length] = '<th class="calrowhead">' + weekNum + '</th>';
3416
 
                return html;
3417
 
        },
3418
 
        
3419
 
        /**
3420
 
        * Renders the row footer for a week.
3421
 
        * @method renderRowFooter
3422
 
        * @param {Number}       weekNum The week number of the current row
3423
 
        * @param {Array}        cell    The current working HTML array
3424
 
        */
3425
 
        renderRowFooter : function(weekNum, html) {
3426
 
                html[html.length] = '<th class="calrowfoot">' + weekNum + '</th>';
3427
 
                return html;
3428
 
        },
3429
 
        
3430
 
        /**
3431
 
        * Renders a single standard calendar cell in the calendar widget table.
3432
 
        * All logic for determining how a standard default cell will be rendered is 
3433
 
        * encapsulated in this method, and must be accounted for when extending the
3434
 
        * widget class.
3435
 
        * @method renderCellDefault
3436
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3437
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3438
 
        */
3439
 
        renderCellDefault : function(workingDate, cell) {
3440
 
                cell.innerHTML = '<a href="#" class="' + this.Style.CSS_CELL_SELECTOR + '">' + this.buildDayLabel(workingDate) + "</a>";
3441
 
        },
3442
 
        
3443
 
        /**
3444
 
        * Styles a selectable cell.
3445
 
        * @method styleCellDefault
3446
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3447
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3448
 
        */
3449
 
        styleCellDefault : function(workingDate, cell) {
3450
 
                Dom.addClass(cell, this.Style.CSS_CELL_SELECTABLE);
3451
 
        },
3452
 
        
3453
 
        
3454
 
        /**
3455
 
        * Renders a single standard calendar cell using the CSS hightlight1 style
3456
 
        * @method renderCellStyleHighlight1
3457
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3458
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3459
 
        */
3460
 
        renderCellStyleHighlight1 : function(workingDate, cell) {
3461
 
                Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT1);
3462
 
        },
3463
 
        
3464
 
        /**
3465
 
        * Renders a single standard calendar cell using the CSS hightlight2 style
3466
 
        * @method renderCellStyleHighlight2
3467
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3468
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3469
 
        */
3470
 
        renderCellStyleHighlight2 : function(workingDate, cell) {
3471
 
                Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT2);
3472
 
        },
3473
 
        
3474
 
        /**
3475
 
        * Renders a single standard calendar cell using the CSS hightlight3 style
3476
 
        * @method renderCellStyleHighlight3
3477
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3478
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3479
 
        */
3480
 
        renderCellStyleHighlight3 : function(workingDate, cell) {
3481
 
                Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT3);
3482
 
        },
3483
 
        
3484
 
        /**
3485
 
        * Renders a single standard calendar cell using the CSS hightlight4 style
3486
 
        * @method renderCellStyleHighlight4
3487
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3488
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3489
 
        */
3490
 
        renderCellStyleHighlight4 : function(workingDate, cell) {
3491
 
                Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT4);
3492
 
        },
3493
 
        
3494
 
        /**
3495
 
        * Applies the default style used for rendering today's date to the current calendar cell
3496
 
        * @method renderCellStyleToday
3497
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3498
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3499
 
        */
3500
 
        renderCellStyleToday : function(workingDate, cell) {
3501
 
                Dom.addClass(cell, this.Style.CSS_CELL_TODAY);
3502
 
        },
3503
 
        
3504
 
        /**
3505
 
        * Applies the default style used for rendering selected dates to the current calendar cell
3506
 
        * @method renderCellStyleSelected
3507
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3508
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3509
 
        * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
3510
 
        *                       should not be terminated
3511
 
        */
3512
 
        renderCellStyleSelected : function(workingDate, cell) {
3513
 
                Dom.addClass(cell, this.Style.CSS_CELL_SELECTED);
3514
 
        },
3515
 
        
3516
 
        /**
3517
 
        * Applies the default style used for rendering dates that are not a part of the current
3518
 
        * month (preceding or trailing the cells for the current month)
3519
 
        * @method renderCellNotThisMonth
3520
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3521
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3522
 
        * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
3523
 
        *                       should not be terminated
3524
 
        */
3525
 
        renderCellNotThisMonth : function(workingDate, cell) {
3526
 
                Dom.addClass(cell, this.Style.CSS_CELL_OOM);
3527
 
                cell.innerHTML=workingDate.getDate();
3528
 
                return Calendar.STOP_RENDER;
3529
 
        },
3530
 
        
3531
 
        /**
3532
 
        * Renders the current calendar cell as a non-selectable "black-out" date using the default
3533
 
        * restricted style.
3534
 
        * @method renderBodyCellRestricted
3535
 
        * @param {Date}                                 workingDate             The current working Date object being used to generate the calendar
3536
 
        * @param {HTMLTableCellElement} cell                    The current working cell in the calendar
3537
 
        * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
3538
 
        *                       should not be terminated
3539
 
        */
3540
 
        renderBodyCellRestricted : function(workingDate, cell) {
3541
 
                Dom.addClass(cell, this.Style.CSS_CELL);
3542
 
                Dom.addClass(cell, this.Style.CSS_CELL_RESTRICTED);
3543
 
                cell.innerHTML=workingDate.getDate();
3544
 
                return Calendar.STOP_RENDER;
3545
 
        },
3546
 
        
3547
 
        // END BUILT-IN TABLE CELL RENDERERS
3548
 
        
3549
 
        // BEGIN MONTH NAVIGATION METHODS
3550
 
        
3551
 
        /**
3552
 
        * Adds the designated number of months to the current calendar month, and sets the current
3553
 
        * calendar page date to the new month.
3554
 
        * @method addMonths
3555
 
        * @param {Number}       count   The number of months to add to the current calendar
3556
 
        */
3557
 
        addMonths : function(count) {
3558
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key;
3559
 
                this.cfg.setProperty(cfgPageDate, DateMath.add(this.cfg.getProperty(cfgPageDate), DateMath.MONTH, count));
3560
 
                this.resetRenderers();
3561
 
                this.changePageEvent.fire();
3562
 
        },
3563
 
        
3564
 
        /**
3565
 
        * Subtracts the designated number of months from the current calendar month, and sets the current
3566
 
        * calendar page date to the new month.
3567
 
        * @method subtractMonths
3568
 
        * @param {Number}       count   The number of months to subtract from the current calendar
3569
 
        */
3570
 
        subtractMonths : function(count) {
3571
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key;
3572
 
                this.cfg.setProperty(cfgPageDate, DateMath.subtract(this.cfg.getProperty(cfgPageDate), DateMath.MONTH, count));
3573
 
                this.resetRenderers();
3574
 
                this.changePageEvent.fire();
3575
 
        },
3576
 
 
3577
 
        /**
3578
 
        * Adds the designated number of years to the current calendar, and sets the current
3579
 
        * calendar page date to the new month.
3580
 
        * @method addYears
3581
 
        * @param {Number}       count   The number of years to add to the current calendar
3582
 
        */
3583
 
        addYears : function(count) {
3584
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key;
3585
 
                this.cfg.setProperty(cfgPageDate, DateMath.add(this.cfg.getProperty(cfgPageDate), DateMath.YEAR, count));
3586
 
                this.resetRenderers();
3587
 
                this.changePageEvent.fire();
3588
 
        },
3589
 
        
3590
 
        /**
3591
 
        * Subtcats the designated number of years from the current calendar, and sets the current
3592
 
        * calendar page date to the new month.
3593
 
        * @method subtractYears
3594
 
        * @param {Number}       count   The number of years to subtract from the current calendar
3595
 
        */
3596
 
        subtractYears : function(count) {
3597
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key;
3598
 
                this.cfg.setProperty(cfgPageDate, DateMath.subtract(this.cfg.getProperty(cfgPageDate), DateMath.YEAR, count));
3599
 
                this.resetRenderers();
3600
 
                this.changePageEvent.fire();
3601
 
        },
3602
 
        
3603
 
        /**
3604
 
        * Navigates to the next month page in the calendar widget.
3605
 
        * @method nextMonth
3606
 
        */
3607
 
        nextMonth : function() {
3608
 
                this.addMonths(1);
3609
 
        },
3610
 
        
3611
 
        /**
3612
 
        * Navigates to the previous month page in the calendar widget.
3613
 
        * @method previousMonth
3614
 
        */
3615
 
        previousMonth : function() {
3616
 
                this.subtractMonths(1);
3617
 
        },
3618
 
        
3619
 
        /**
3620
 
        * Navigates to the next year in the currently selected month in the calendar widget.
3621
 
        * @method nextYear
3622
 
        */
3623
 
        nextYear : function() {
3624
 
                this.addYears(1);
3625
 
        },
3626
 
        
3627
 
        /**
3628
 
        * Navigates to the previous year in the currently selected month in the calendar widget.
3629
 
        * @method previousYear
3630
 
        */
3631
 
        previousYear : function() {
3632
 
                this.subtractYears(1);
3633
 
        },
3634
 
        
3635
 
        // END MONTH NAVIGATION METHODS
3636
 
        
3637
 
        // BEGIN SELECTION METHODS
3638
 
        
3639
 
        /**
3640
 
        * Resets the calendar widget to the originally selected month and year, and 
3641
 
        * sets the calendar to the initial selection(s).
3642
 
        * @method reset
3643
 
        */
3644
 
        reset : function() {
3645
 
                this.cfg.resetProperty(DEF_CFG.SELECTED.key);
3646
 
                this.cfg.resetProperty(DEF_CFG.PAGEDATE.key);
3647
 
                this.resetEvent.fire();
3648
 
        },
3649
 
        
3650
 
        /**
3651
 
        * Clears the selected dates in the current calendar widget and sets the calendar
3652
 
        * to the current month and year.
3653
 
        * @method clear
3654
 
        */
3655
 
        clear : function() {
3656
 
                this.cfg.setProperty(DEF_CFG.SELECTED.key, []);
3657
 
                this.cfg.setProperty(DEF_CFG.PAGEDATE.key, new Date(this.today.getTime()));
3658
 
                this.clearEvent.fire();
3659
 
        },
3660
 
        
3661
 
        /**
3662
 
        * Selects a date or a collection of dates on the current calendar. This method, by default,
3663
 
        * does not call the render method explicitly. Once selection has completed, render must be 
3664
 
        * called for the changes to be reflected visually.
3665
 
        *
3666
 
        * Any dates which are OOB (out of bounds, not selectable) will not be selected and the array of 
3667
 
        * selected dates passed to the selectEvent will not contain OOB dates.
3668
 
        * 
3669
 
        * If all dates are OOB, the no state change will occur; beforeSelect and select events will not be fired.
3670
 
        *
3671
 
        * @method select
3672
 
        * @param        {String/Date/Date[]}    date    The date string of dates to select in the current calendar. Valid formats are
3673
 
        *                                                               individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
3674
 
        *                                                               Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
3675
 
        *                                                               This method can also take a JavaScript Date object or an array of Date objects.
3676
 
        * @return       {Date[]}                        Array of JavaScript Date objects representing all individual dates that are currently selected.
3677
 
        */
3678
 
        select : function(date) {
3679
 
 
3680
 
                var aToBeSelected = this._toFieldArray(date),
3681
 
                        validDates = [],
3682
 
                        selected = [],
3683
 
                        cfgSelected = DEF_CFG.SELECTED.key;
3684
 
 
3685
 
                
3686
 
                for (var a=0; a < aToBeSelected.length; ++a) {
3687
 
                        var toSelect = aToBeSelected[a];
3688
 
 
3689
 
                        if (!this.isDateOOB(this._toDate(toSelect))) {
3690
 
 
3691
 
                                if (validDates.length === 0) {
3692
 
                                        this.beforeSelectEvent.fire();
3693
 
                                        selected = this.cfg.getProperty(cfgSelected);
3694
 
                                }
3695
 
                                validDates.push(toSelect);
3696
 
 
3697
 
                                if (this._indexOfSelectedFieldArray(toSelect) == -1) { 
3698
 
                                        selected[selected.length] = toSelect;
3699
 
                                }
3700
 
                        }
3701
 
                }
3702
 
 
3703
 
 
3704
 
                if (validDates.length > 0) {
3705
 
                        if (this.parent) {
3706
 
                                this.parent.cfg.setProperty(cfgSelected, selected);
3707
 
                        } else {
3708
 
                                this.cfg.setProperty(cfgSelected, selected);
3709
 
                        }
3710
 
                        this.selectEvent.fire(validDates);
3711
 
                }
3712
 
 
3713
 
                return this.getSelectedDates();
3714
 
        },
3715
 
        
3716
 
        /**
3717
 
        * Selects a date on the current calendar by referencing the index of the cell that should be selected.
3718
 
        * This method is used to easily select a single cell (usually with a mouse click) without having to do
3719
 
        * a full render. The selected style is applied to the cell directly.
3720
 
        *
3721
 
        * If the cell is not marked with the CSS_CELL_SELECTABLE class (as is the case by default for out of month 
3722
 
        * or out of bounds cells), it will not be selected and in such a case beforeSelect and select events will not be fired.
3723
 
        * 
3724
 
        * @method selectCell
3725
 
        * @param        {Number}        cellIndex       The index of the cell to select in the current calendar. 
3726
 
        * @return       {Date[]}        Array of JavaScript Date objects representing all individual dates that are currently selected.
3727
 
        */
3728
 
        selectCell : function(cellIndex) {
3729
 
 
3730
 
                var cell = this.cells[cellIndex],
3731
 
                        cellDate = this.cellDates[cellIndex],
3732
 
                        dCellDate = this._toDate(cellDate),
3733
 
                        selectable = Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
3734
 
 
3735
 
 
3736
 
                if (selectable) {
3737
 
        
3738
 
                        this.beforeSelectEvent.fire();
3739
 
        
3740
 
                        var cfgSelected = DEF_CFG.SELECTED.key;
3741
 
                        var selected = this.cfg.getProperty(cfgSelected);
3742
 
        
3743
 
                        var selectDate = cellDate.concat();
3744
 
        
3745
 
                        if (this._indexOfSelectedFieldArray(selectDate) == -1) {
3746
 
                                selected[selected.length] = selectDate;
3747
 
                        }
3748
 
                        if (this.parent) {
3749
 
                                this.parent.cfg.setProperty(cfgSelected, selected);
3750
 
                        } else {
3751
 
                                this.cfg.setProperty(cfgSelected, selected);
3752
 
                        }
3753
 
                        this.renderCellStyleSelected(dCellDate,cell);
3754
 
                        this.selectEvent.fire([selectDate]);
3755
 
        
3756
 
                        this.doCellMouseOut.call(cell, null, this);             
3757
 
                }
3758
 
        
3759
 
                return this.getSelectedDates();
3760
 
        },
3761
 
        
3762
 
        /**
3763
 
        * Deselects a date or a collection of dates on the current calendar. This method, by default,
3764
 
        * does not call the render method explicitly. Once deselection has completed, render must be 
3765
 
        * called for the changes to be reflected visually.
3766
 
        * 
3767
 
        * The method will not attempt to deselect any dates which are OOB (out of bounds, and hence not selectable) 
3768
 
        * and the array of deselected dates passed to the deselectEvent will not contain any OOB dates.
3769
 
        * 
3770
 
        * If all dates are OOB, beforeDeselect and deselect events will not be fired.
3771
 
        * 
3772
 
        * @method deselect
3773
 
        * @param        {String/Date/Date[]}    date    The date string of dates to deselect in the current calendar. Valid formats are
3774
 
        *                                                               individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
3775
 
        *                                                               Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
3776
 
        *                                                               This method can also take a JavaScript Date object or an array of Date objects. 
3777
 
        * @return       {Date[]}                        Array of JavaScript Date objects representing all individual dates that are currently selected.
3778
 
        */
3779
 
        deselect : function(date) {
3780
 
 
3781
 
                var aToBeDeselected = this._toFieldArray(date),
3782
 
                        validDates = [],
3783
 
                        selected = [],
3784
 
                        cfgSelected = DEF_CFG.SELECTED.key;
3785
 
 
3786
 
 
3787
 
                for (var a=0; a < aToBeDeselected.length; ++a) {
3788
 
                        var toDeselect = aToBeDeselected[a];
3789
 
        
3790
 
                        if (!this.isDateOOB(this._toDate(toDeselect))) {
3791
 
        
3792
 
                                if (validDates.length === 0) {
3793
 
                                        this.beforeDeselectEvent.fire();
3794
 
                                        selected = this.cfg.getProperty(cfgSelected);
3795
 
                                }
3796
 
        
3797
 
                                validDates.push(toDeselect);
3798
 
        
3799
 
                                var index = this._indexOfSelectedFieldArray(toDeselect);
3800
 
                                if (index != -1) {      
3801
 
                                        selected.splice(index,1);
3802
 
                                }
3803
 
                        }
3804
 
                }
3805
 
        
3806
 
        
3807
 
                if (validDates.length > 0) {
3808
 
                        if (this.parent) {
3809
 
                                this.parent.cfg.setProperty(cfgSelected, selected);
3810
 
                        } else {
3811
 
                                this.cfg.setProperty(cfgSelected, selected);
3812
 
                        }
3813
 
                        this.deselectEvent.fire(validDates);
3814
 
                }
3815
 
        
3816
 
                return this.getSelectedDates();
3817
 
        },
3818
 
        
3819
 
        /**
3820
 
        * Deselects a date on the current calendar by referencing the index of the cell that should be deselected.
3821
 
        * This method is used to easily deselect a single cell (usually with a mouse click) without having to do
3822
 
        * a full render. The selected style is removed from the cell directly.
3823
 
        * 
3824
 
        * If the cell is not marked with the CSS_CELL_SELECTABLE class (as is the case by default for out of month 
3825
 
        * or out of bounds cells), the method will not attempt to deselect it and in such a case, beforeDeselect and 
3826
 
        * deselect events will not be fired.
3827
 
        * 
3828
 
        * @method deselectCell
3829
 
        * @param        {Number}        cellIndex       The index of the cell to deselect in the current calendar. 
3830
 
        * @return       {Date[]}        Array of JavaScript Date objects representing all individual dates that are currently selected.
3831
 
        */
3832
 
        deselectCell : function(cellIndex) {
3833
 
                var cell = this.cells[cellIndex],
3834
 
                        cellDate = this.cellDates[cellIndex],
3835
 
                        cellDateIndex = this._indexOfSelectedFieldArray(cellDate);
3836
 
 
3837
 
                var selectable = Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
3838
 
 
3839
 
                if (selectable) {
3840
 
 
3841
 
                        this.beforeDeselectEvent.fire();
3842
 
 
3843
 
                        var selected = this.cfg.getProperty(DEF_CFG.SELECTED.key),
3844
 
                                dCellDate = this._toDate(cellDate),
3845
 
                                selectDate = cellDate.concat();
3846
 
 
3847
 
                        if (cellDateIndex > -1) {
3848
 
                                if (this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getMonth() == dCellDate.getMonth() &&
3849
 
                                        this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getFullYear() == dCellDate.getFullYear()) {
3850
 
                                        Dom.removeClass(cell, this.Style.CSS_CELL_SELECTED);
3851
 
                                }
3852
 
                                selected.splice(cellDateIndex, 1);
3853
 
                        }
3854
 
 
3855
 
                        if (this.parent) {
3856
 
                                this.parent.cfg.setProperty(DEF_CFG.SELECTED.key, selected);
3857
 
                        } else {
3858
 
                                this.cfg.setProperty(DEF_CFG.SELECTED.key, selected);
3859
 
                        }
3860
 
 
3861
 
                        this.deselectEvent.fire([selectDate]);
3862
 
                }
3863
 
 
3864
 
                return this.getSelectedDates();
3865
 
        },
3866
 
 
3867
 
        /**
3868
 
        * Deselects all dates on the current calendar.
3869
 
        * @method deselectAll
3870
 
        * @return {Date[]}              Array of JavaScript Date objects representing all individual dates that are currently selected.
3871
 
        *                                               Assuming that this function executes properly, the return value should be an empty array.
3872
 
        *                                               However, the empty array is returned for the sake of being able to check the selection status
3873
 
        *                                               of the calendar.
3874
 
        */
3875
 
        deselectAll : function() {
3876
 
                this.beforeDeselectEvent.fire();
3877
 
                
3878
 
                var cfgSelected = DEF_CFG.SELECTED.key,
3879
 
                        selected = this.cfg.getProperty(cfgSelected),
3880
 
                        count = selected.length,
3881
 
                        sel = selected.concat();
3882
 
 
3883
 
                if (this.parent) {
3884
 
                        this.parent.cfg.setProperty(cfgSelected, []);
3885
 
                } else {
3886
 
                        this.cfg.setProperty(cfgSelected, []);
3887
 
                }
3888
 
                
3889
 
                if (count > 0) {
3890
 
                        this.deselectEvent.fire(sel);
3891
 
                }
3892
 
        
3893
 
                return this.getSelectedDates();
3894
 
        },
3895
 
        
3896
 
        // END SELECTION METHODS
3897
 
        
3898
 
        // BEGIN TYPE CONVERSION METHODS
3899
 
        
3900
 
        /**
3901
 
        * Converts a date (either a JavaScript Date object, or a date string) to the internal data structure
3902
 
        * used to represent dates: [[yyyy,mm,dd],[yyyy,mm,dd]].
3903
 
        * @method _toFieldArray
3904
 
        * @private
3905
 
        * @param        {String/Date/Date[]}    date    The date string of dates to deselect in the current calendar. Valid formats are
3906
 
        *                                                               individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
3907
 
        *                                                               Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
3908
 
        *                                                               This method can also take a JavaScript Date object or an array of Date objects. 
3909
 
        * @return {Array[](Number[])}   Array of date field arrays
3910
 
        */
3911
 
        _toFieldArray : function(date) {
3912
 
                var returnDate = [];
3913
 
        
3914
 
                if (date instanceof Date) {
3915
 
                        returnDate = [[date.getFullYear(), date.getMonth()+1, date.getDate()]];
3916
 
                } else if (Lang.isString(date)) {
3917
 
                        returnDate = this._parseDates(date);
3918
 
                } else if (Lang.isArray(date)) {
3919
 
                        for (var i=0;i<date.length;++i) {
3920
 
                                var d = date[i];
3921
 
                                returnDate[returnDate.length] = [d.getFullYear(),d.getMonth()+1,d.getDate()];
3922
 
                        }
3923
 
                }
3924
 
                
3925
 
                return returnDate;
3926
 
        },
3927
 
        
3928
 
        /**
3929
 
        * Converts a date field array [yyyy,mm,dd] to a JavaScript Date object. The date field array
3930
 
        * is the format in which dates are as provided as arguments to selectEvent and deselectEvent listeners.
3931
 
        * 
3932
 
        * @method toDate
3933
 
        * @param        {Number[]}      dateFieldArray  The date field array to convert to a JavaScript Date.
3934
 
        * @return       {Date}  JavaScript Date object representing the date field array.
3935
 
        */
3936
 
        toDate : function(dateFieldArray) {
3937
 
                return this._toDate(dateFieldArray);
3938
 
        },
3939
 
        
3940
 
        /**
3941
 
        * Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
3942
 
        * @method _toDate
3943
 
        * @private
3944
 
        * @deprecated Made public, toDate 
3945
 
        * @param        {Number[]}              dateFieldArray  The date field array to convert to a JavaScript Date.
3946
 
        * @return       {Date}  JavaScript Date object representing the date field array
3947
 
        */
3948
 
        _toDate : function(dateFieldArray) {
3949
 
                if (dateFieldArray instanceof Date) {
3950
 
                        return dateFieldArray;
3951
 
                } else {
3952
 
                        return DateMath.getDate(dateFieldArray[0],dateFieldArray[1]-1,dateFieldArray[2]);
3953
 
                }
3954
 
        },
3955
 
        
3956
 
        // END TYPE CONVERSION METHODS 
3957
 
        
3958
 
        // BEGIN UTILITY METHODS
3959
 
        
3960
 
        /**
3961
 
        * Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
3962
 
        * @method _fieldArraysAreEqual
3963
 
        * @private
3964
 
        * @param        {Number[]}      array1  The first date field array to compare
3965
 
        * @param        {Number[]}      array2  The first date field array to compare
3966
 
        * @return       {Boolean}       The boolean that represents the equality of the two arrays
3967
 
        */
3968
 
        _fieldArraysAreEqual : function(array1, array2) {
3969
 
                var match = false;
3970
 
        
3971
 
                if (array1[0]==array2[0]&&array1[1]==array2[1]&&array1[2]==array2[2]) {
3972
 
                        match=true;     
3973
 
                }
3974
 
        
3975
 
                return match;
3976
 
        },
3977
 
        
3978
 
        /**
3979
 
        * Gets the index of a date field array [yyyy,mm,dd] in the current list of selected dates.
3980
 
        * @method       _indexOfSelectedFieldArray
3981
 
        * @private
3982
 
        * @param        {Number[]}              find    The date field array to search for
3983
 
        * @return       {Number}                        The index of the date field array within the collection of selected dates.
3984
 
        *                                                               -1 will be returned if the date is not found.
3985
 
        */
3986
 
        _indexOfSelectedFieldArray : function(find) {
3987
 
                var selected = -1,
3988
 
                        seldates = this.cfg.getProperty(DEF_CFG.SELECTED.key);
3989
 
        
3990
 
                for (var s=0;s<seldates.length;++s) {
3991
 
                        var sArray = seldates[s];
3992
 
                        if (find[0]==sArray[0]&&find[1]==sArray[1]&&find[2]==sArray[2]) {
3993
 
                                selected = s;
3994
 
                                break;
3995
 
                        }
3996
 
                }
3997
 
        
3998
 
                return selected;
3999
 
        },
4000
 
        
4001
 
        /**
4002
 
        * Determines whether a given date is OOM (out of month).
4003
 
        * @method       isDateOOM
4004
 
        * @param        {Date}  date    The JavaScript Date object for which to check the OOM status
4005
 
        * @return       {Boolean}       true if the date is OOM
4006
 
        */
4007
 
        isDateOOM : function(date) {
4008
 
                return (date.getMonth() != this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getMonth());
4009
 
        },
4010
 
        
4011
 
        /**
4012
 
        * Determines whether a given date is OOB (out of bounds - less than the mindate or more than the maxdate).
4013
 
        *
4014
 
        * @method       isDateOOB
4015
 
        * @param        {Date}  date    The JavaScript Date object for which to check the OOB status
4016
 
        * @return       {Boolean}       true if the date is OOB
4017
 
        */
4018
 
        isDateOOB : function(date) {
4019
 
                var minDate = this.cfg.getProperty(DEF_CFG.MINDATE.key),
4020
 
                        maxDate = this.cfg.getProperty(DEF_CFG.MAXDATE.key),
4021
 
                        dm = DateMath;
4022
 
                
4023
 
                if (minDate) {
4024
 
                        minDate = dm.clearTime(minDate);
4025
 
                } 
4026
 
                if (maxDate) {
4027
 
                        maxDate = dm.clearTime(maxDate);
4028
 
                }
4029
 
        
4030
 
                var clearedDate = new Date(date.getTime());
4031
 
                clearedDate = dm.clearTime(clearedDate);
4032
 
        
4033
 
                return ((minDate && clearedDate.getTime() < minDate.getTime()) || (maxDate && clearedDate.getTime() > maxDate.getTime()));
4034
 
        },
4035
 
        
4036
 
        /**
4037
 
         * Parses a pagedate configuration property value. The value can either be specified as a string of form "mm/yyyy" or a Date object 
4038
 
         * and is parsed into a Date object normalized to the first day of the month. If no value is passed in, the month and year from today's date are used to create the Date object 
4039
 
         * @method      _parsePageDate
4040
 
         * @private
4041
 
         * @param {Date|String} date    Pagedate value which needs to be parsed
4042
 
         * @return {Date}       The Date object representing the pagedate
4043
 
         */
4044
 
        _parsePageDate : function(date) {
4045
 
                var parsedDate;
4046
 
 
4047
 
                if (date) {
4048
 
                        if (date instanceof Date) {
4049
 
                                parsedDate = DateMath.findMonthStart(date);
4050
 
                        } else {
4051
 
                                var month, year, aMonthYear;
4052
 
                                aMonthYear = date.split(this.cfg.getProperty(DEF_CFG.DATE_FIELD_DELIMITER.key));
4053
 
                                month = parseInt(aMonthYear[this.cfg.getProperty(DEF_CFG.MY_MONTH_POSITION.key)-1], 10)-1;
4054
 
                                year = parseInt(aMonthYear[this.cfg.getProperty(DEF_CFG.MY_YEAR_POSITION.key)-1], 10);
4055
 
 
4056
 
                                parsedDate = DateMath.getDate(year, month, 1);
4057
 
                        }
4058
 
                } else {
4059
 
                        parsedDate = DateMath.getDate(this.today.getFullYear(), this.today.getMonth(), 1);
4060
 
                }
4061
 
                return parsedDate;
4062
 
        },
4063
 
        
4064
 
        // END UTILITY METHODS
4065
 
        
4066
 
        // BEGIN EVENT HANDLERS
4067
 
        
4068
 
        /**
4069
 
        * Event executed before a date is selected in the calendar widget.
4070
 
        * @deprecated Event handlers for this event should be susbcribed to beforeSelectEvent.
4071
 
        */
4072
 
        onBeforeSelect : function() {
4073
 
                if (this.cfg.getProperty(DEF_CFG.MULTI_SELECT.key) === false) {
4074
 
                        if (this.parent) {
4075
 
                                this.parent.callChildFunction("clearAllBodyCellStyles", this.Style.CSS_CELL_SELECTED);
4076
 
                                this.parent.deselectAll();
4077
 
                        } else {
4078
 
                                this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);
4079
 
                                this.deselectAll();
4080
 
                        }
4081
 
                }
4082
 
        },
4083
 
        
4084
 
        /**
4085
 
        * Event executed when a date is selected in the calendar widget.
4086
 
        * @param        {Array} selected        An array of date field arrays representing which date or dates were selected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
4087
 
        * @deprecated Event handlers for this event should be susbcribed to selectEvent.
4088
 
        */
4089
 
        onSelect : function(selected) { },
4090
 
        
4091
 
        /**
4092
 
        * Event executed before a date is deselected in the calendar widget.
4093
 
        * @deprecated Event handlers for this event should be susbcribed to beforeDeselectEvent.
4094
 
        */
4095
 
        onBeforeDeselect : function() { },
4096
 
        
4097
 
        /**
4098
 
        * Event executed when a date is deselected in the calendar widget.
4099
 
        * @param        {Array} selected        An array of date field arrays representing which date or dates were deselected. Example: [ [2006,8,6],[2006,8,7],[2006,8,8] ]
4100
 
        * @deprecated Event handlers for this event should be susbcribed to deselectEvent.
4101
 
        */
4102
 
        onDeselect : function(deselected) { },
4103
 
        
4104
 
        /**
4105
 
        * Event executed when the user navigates to a different calendar page.
4106
 
        * @deprecated Event handlers for this event should be susbcribed to changePageEvent.
4107
 
        */
4108
 
        onChangePage : function() {
4109
 
                this.render();
4110
 
        },
4111
 
 
4112
 
        /**
4113
 
        * Event executed when the calendar widget is rendered.
4114
 
        * @deprecated Event handlers for this event should be susbcribed to renderEvent.
4115
 
        */
4116
 
        onRender : function() { },
4117
 
 
4118
 
        /**
4119
 
        * Event executed when the calendar widget is reset to its original state.
4120
 
        * @deprecated Event handlers for this event should be susbcribed to resetEvemt.
4121
 
        */
4122
 
        onReset : function() { this.render(); },
4123
 
 
4124
 
        /**
4125
 
        * Event executed when the calendar widget is completely cleared to the current month with no selections.
4126
 
        * @deprecated Event handlers for this event should be susbcribed to clearEvent.
4127
 
        */
4128
 
        onClear : function() { this.render(); },
4129
 
        
4130
 
        /**
4131
 
        * Validates the calendar widget. This method has no default implementation
4132
 
        * and must be extended by subclassing the widget.
4133
 
        * @return       Should return true if the widget validates, and false if
4134
 
        * it doesn't.
4135
 
        * @type Boolean
4136
 
        */
4137
 
        validate : function() { return true; },
4138
 
        
4139
 
        // END EVENT HANDLERS
4140
 
        
4141
 
        // BEGIN DATE PARSE METHODS
4142
 
        
4143
 
        /**
4144
 
        * Converts a date string to a date field array
4145
 
        * @private
4146
 
        * @param        {String}        sDate                   Date string. Valid formats are mm/dd and mm/dd/yyyy.
4147
 
        * @return                               A date field array representing the string passed to the method
4148
 
        * @type Array[](Number[])
4149
 
        */
4150
 
        _parseDate : function(sDate) {
4151
 
                var aDate = sDate.split(this.Locale.DATE_FIELD_DELIMITER),
4152
 
                        rArray;
4153
 
        
4154
 
                if (aDate.length == 2) {
4155
 
                        rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
4156
 
                        rArray.type = Calendar.MONTH_DAY;
4157
 
                } else {
4158
 
                        rArray = [aDate[this.Locale.MDY_YEAR_POSITION-1],aDate[this.Locale.MDY_MONTH_POSITION-1],aDate[this.Locale.MDY_DAY_POSITION-1]];
4159
 
                        rArray.type = Calendar.DATE;
4160
 
                }
4161
 
        
4162
 
                for (var i=0;i<rArray.length;i++) {
4163
 
                        rArray[i] = parseInt(rArray[i], 10);
4164
 
                }
4165
 
        
4166
 
                return rArray;
4167
 
        },
4168
 
        
4169
 
        /**
4170
 
        * Converts a multi or single-date string to an array of date field arrays
4171
 
        * @private
4172
 
        * @param        {String}        sDates          Date string with one or more comma-delimited dates. Valid formats are mm/dd, mm/dd/yyyy, mm/dd/yyyy-mm/dd/yyyy
4173
 
        * @return                                                       An array of date field arrays
4174
 
        * @type Array[](Number[])
4175
 
        */
4176
 
        _parseDates : function(sDates) {
4177
 
                var aReturn = [],
4178
 
                        aDates = sDates.split(this.Locale.DATE_DELIMITER);
4179
 
                
4180
 
                for (var d=0;d<aDates.length;++d) {
4181
 
                        var sDate = aDates[d];
4182
 
        
4183
 
                        if (sDate.indexOf(this.Locale.DATE_RANGE_DELIMITER) != -1) {
4184
 
                                // This is a range
4185
 
                                var aRange = sDate.split(this.Locale.DATE_RANGE_DELIMITER),
4186
 
                                        dateStart = this._parseDate(aRange[0]),
4187
 
                                        dateEnd = this._parseDate(aRange[1]),
4188
 
                                        fullRange = this._parseRange(dateStart, dateEnd);
4189
 
 
4190
 
                                aReturn = aReturn.concat(fullRange);
4191
 
                        } else {
4192
 
                                // This is not a range
4193
 
                                var aDate = this._parseDate(sDate);
4194
 
                                aReturn.push(aDate);
4195
 
                        }
4196
 
                }
4197
 
                return aReturn;
4198
 
        },
4199
 
        
4200
 
        /**
4201
 
        * Converts a date range to the full list of included dates
4202
 
        * @private
4203
 
        * @param        {Number[]}      startDate       Date field array representing the first date in the range
4204
 
        * @param        {Number[]}      endDate         Date field array representing the last date in the range
4205
 
        * @return                                                       An array of date field arrays
4206
 
        * @type Array[](Number[])
4207
 
        */
4208
 
        _parseRange : function(startDate, endDate) {
4209
 
                var dCurrent = DateMath.add(DateMath.getDate(startDate[0],startDate[1]-1,startDate[2]),DateMath.DAY,1),
4210
 
                        dEnd     = DateMath.getDate(endDate[0],  endDate[1]-1,  endDate[2]),
4211
 
                        results = [];
4212
 
 
4213
 
                results.push(startDate);
4214
 
                while (dCurrent.getTime() <= dEnd.getTime()) {
4215
 
                        results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
4216
 
                        dCurrent = DateMath.add(dCurrent,DateMath.DAY,1);
4217
 
                }
4218
 
                return results;
4219
 
        },
4220
 
        
4221
 
        // END DATE PARSE METHODS
4222
 
        
4223
 
        // BEGIN RENDERER METHODS
4224
 
        
4225
 
        /**
4226
 
        * Resets the render stack of the current calendar to its original pre-render value.
4227
 
        */
4228
 
        resetRenderers : function() {
4229
 
                this.renderStack = this._renderStack.concat();
4230
 
        },
4231
 
        
4232
 
        /**
4233
 
         * Removes all custom renderers added to the Calendar through the addRenderer, addMonthRenderer and 
4234
 
         * addWeekdayRenderer methods. Calendar's render method needs to be called after removing renderers 
4235
 
         * to re-render the Calendar without custom renderers applied.
4236
 
         */
4237
 
        removeRenderers : function() {
4238
 
                this._renderStack = [];
4239
 
                this.renderStack = [];
4240
 
        },
4241
 
 
4242
 
        /**
4243
 
        * Clears the inner HTML, CSS class and style information from the specified cell.
4244
 
        * @method clearElement
4245
 
        * @param        {HTMLTableCellElement} cell The cell to clear
4246
 
        */ 
4247
 
        clearElement : function(cell) {
4248
 
                cell.innerHTML = "&#160;";
4249
 
                cell.className="";
4250
 
        },
4251
 
        
4252
 
        /**
4253
 
        * Adds a renderer to the render stack. The function reference passed to this method will be executed
4254
 
        * when a date cell matches the conditions specified in the date string for this renderer.
4255
 
        * @method addRenderer
4256
 
        * @param        {String}        sDates          A date string to associate with the specified renderer. Valid formats
4257
 
        *                                                                       include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
4258
 
        * @param        {Function}      fnRender        The function executed to render cells that match the render rules for this renderer.
4259
 
        */
4260
 
        addRenderer : function(sDates, fnRender) {
4261
 
                var aDates = this._parseDates(sDates);
4262
 
                for (var i=0;i<aDates.length;++i) {
4263
 
                        var aDate = aDates[i];
4264
 
                
4265
 
                        if (aDate.length == 2) { // this is either a range or a month/day combo
4266
 
                                if (aDate[0] instanceof Array) { // this is a range
4267
 
                                        this._addRenderer(Calendar.RANGE,aDate,fnRender);
4268
 
                                } else { // this is a month/day combo
4269
 
                                        this._addRenderer(Calendar.MONTH_DAY,aDate,fnRender);
4270
 
                                }
4271
 
                        } else if (aDate.length == 3) {
4272
 
                                this._addRenderer(Calendar.DATE,aDate,fnRender);
4273
 
                        }
4274
 
                }
4275
 
        },
4276
 
        
4277
 
        /**
4278
 
        * The private method used for adding cell renderers to the local render stack.
4279
 
        * This method is called by other methods that set the renderer type prior to the method call.
4280
 
        * @method _addRenderer
4281
 
        * @private
4282
 
        * @param        {String}        type            The type string that indicates the type of date renderer being added.
4283
 
        *                                                                       Values are YAHOO.widget.Calendar.DATE, YAHOO.widget.Calendar.MONTH_DAY, YAHOO.widget.Calendar.WEEKDAY,
4284
 
        *                                                                       YAHOO.widget.Calendar.RANGE, YAHOO.widget.Calendar.MONTH
4285
 
        * @param        {Array}         aDates          An array of dates used to construct the renderer. The format varies based
4286
 
        *                                                                       on the renderer type
4287
 
        * @param        {Function}      fnRender        The function executed to render cells that match the render rules for this renderer.
4288
 
        */
4289
 
        _addRenderer : function(type, aDates, fnRender) {
4290
 
                var add = [type,aDates,fnRender];
4291
 
                this.renderStack.unshift(add);  
4292
 
                this._renderStack = this.renderStack.concat();
4293
 
        },
4294
 
 
4295
 
        /**
4296
 
        * Adds a month to the render stack. The function reference passed to this method will be executed
4297
 
        * when a date cell matches the month passed to this method.
4298
 
        * @method addMonthRenderer
4299
 
        * @param        {Number}        month           The month (1-12) to associate with this renderer
4300
 
        * @param        {Function}      fnRender        The function executed to render cells that match the render rules for this renderer.
4301
 
        */
4302
 
        addMonthRenderer : function(month, fnRender) {
4303
 
                this._addRenderer(Calendar.MONTH,[month],fnRender);
4304
 
        },
4305
 
 
4306
 
        /**
4307
 
        * Adds a weekday to the render stack. The function reference passed to this method will be executed
4308
 
        * when a date cell matches the weekday passed to this method.
4309
 
        * @method addWeekdayRenderer
4310
 
        * @param        {Number}        weekday         The weekday (Sunday = 1, Monday = 2 ... Saturday = 7) to associate with this renderer
4311
 
        * @param        {Function}      fnRender        The function executed to render cells that match the render rules for this renderer.
4312
 
        */
4313
 
        addWeekdayRenderer : function(weekday, fnRender) {
4314
 
                this._addRenderer(Calendar.WEEKDAY,[weekday],fnRender);
4315
 
        },
4316
 
 
4317
 
        // END RENDERER METHODS
4318
 
        
4319
 
        // BEGIN CSS METHODS
4320
 
        
4321
 
        /**
4322
 
        * Removes all styles from all body cells in the current calendar table.
4323
 
        * @method clearAllBodyCellStyles
4324
 
        * @param        {style} style The CSS class name to remove from all calendar body cells
4325
 
        */
4326
 
        clearAllBodyCellStyles : function(style) {
4327
 
                for (var c=0;c<this.cells.length;++c) {
4328
 
                        Dom.removeClass(this.cells[c],style);
4329
 
                }
4330
 
        },
4331
 
        
4332
 
        // END CSS METHODS
4333
 
        
4334
 
        // BEGIN GETTER/SETTER METHODS
4335
 
        /**
4336
 
        * Sets the calendar's month explicitly
4337
 
        * @method setMonth
4338
 
        * @param {Number}       month           The numeric month, from 0 (January) to 11 (December)
4339
 
        */
4340
 
        setMonth : function(month) {
4341
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key,
4342
 
                        current = this.cfg.getProperty(cfgPageDate);
4343
 
                current.setMonth(parseInt(month, 10));
4344
 
                this.cfg.setProperty(cfgPageDate, current);
4345
 
        },
4346
 
 
4347
 
        /**
4348
 
        * Sets the calendar's year explicitly.
4349
 
        * @method setYear
4350
 
        * @param {Number}       year            The numeric 4-digit year
4351
 
        */
4352
 
        setYear : function(year) {
4353
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key,
4354
 
                        current = this.cfg.getProperty(cfgPageDate);
4355
 
 
4356
 
                current.setFullYear(parseInt(year, 10));
4357
 
                this.cfg.setProperty(cfgPageDate, current);
4358
 
        },
4359
 
 
4360
 
        /**
4361
 
        * Gets the list of currently selected dates from the calendar.
4362
 
        * @method getSelectedDates
4363
 
        * @return {Date[]} An array of currently selected JavaScript Date objects.
4364
 
        */
4365
 
        getSelectedDates : function() {
4366
 
                var returnDates = [],
4367
 
                        selected = this.cfg.getProperty(DEF_CFG.SELECTED.key);
4368
 
 
4369
 
                for (var d=0;d<selected.length;++d) {
4370
 
                        var dateArray = selected[d];
4371
 
 
4372
 
                        var date = DateMath.getDate(dateArray[0],dateArray[1]-1,dateArray[2]);
4373
 
                        returnDates.push(date);
4374
 
                }
4375
 
 
4376
 
                returnDates.sort( function(a,b) { return a-b; } );
4377
 
                return returnDates;
4378
 
        },
4379
 
 
4380
 
        /// END GETTER/SETTER METHODS ///
4381
 
        
4382
 
        /**
4383
 
        * Hides the Calendar's outer container from view.
4384
 
        * @method hide
4385
 
        */
4386
 
        hide : function() {
4387
 
                if (this.beforeHideEvent.fire()) {
4388
 
                        this.oDomContainer.style.display = "none";
4389
 
                        this.hideEvent.fire();
4390
 
                }
4391
 
        },
4392
 
 
4393
 
        /**
4394
 
        * Shows the Calendar's outer container.
4395
 
        * @method show
4396
 
        */
4397
 
        show : function() {
4398
 
                if (this.beforeShowEvent.fire()) {
4399
 
                        this.oDomContainer.style.display = "block";
4400
 
                        this.showEvent.fire();
4401
 
                }
4402
 
        },
4403
 
 
4404
 
        /**
4405
 
        * Returns a string representing the current browser.
4406
 
        * @deprecated As of 2.3.0, environment information is available in YAHOO.env.ua
4407
 
        * @see YAHOO.env.ua
4408
 
        * @property browser
4409
 
        * @type String
4410
 
        */
4411
 
        browser : (function() {
4412
 
                                var ua = navigator.userAgent.toLowerCase();
4413
 
                                          if (ua.indexOf('opera')!=-1) { // Opera (check first in case of spoof)
4414
 
                                                 return 'opera';
4415
 
                                          } else if (ua.indexOf('msie 7')!=-1) { // IE7
4416
 
                                                 return 'ie7';
4417
 
                                          } else if (ua.indexOf('msie') !=-1) { // IE
4418
 
                                                 return 'ie';
4419
 
                                          } else if (ua.indexOf('safari')!=-1) { // Safari (check before Gecko because it includes "like Gecko")
4420
 
                                                 return 'safari';
4421
 
                                          } else if (ua.indexOf('gecko') != -1) { // Gecko
4422
 
                                                 return 'gecko';
4423
 
                                          } else {
4424
 
                                                 return false;
4425
 
                                          }
4426
 
                                })(),
4427
 
        /**
4428
 
        * Returns a string representation of the object.
4429
 
        * @method toString
4430
 
        * @return {String}      A string representation of the Calendar object.
4431
 
        */
4432
 
        toString : function() {
4433
 
                return "Calendar " + this.id;
4434
 
        },
4435
 
 
4436
 
        /**
4437
 
         * Destroys the Calendar instance. The method will remove references
4438
 
         * to HTML elements, remove any event listeners added by the Calendar,
4439
 
         * and destroy the Config and CalendarNavigator instances it has created.
4440
 
         *
4441
 
         * @method destroy
4442
 
         */
4443
 
        destroy : function() {
4444
 
 
4445
 
                if (this.beforeDestroyEvent.fire()) {
4446
 
                        var cal = this;
4447
 
 
4448
 
                        // Child objects
4449
 
                        if (cal.navigator) {
4450
 
                                cal.navigator.destroy();
4451
 
                        }
4452
 
 
4453
 
                        if (cal.cfg) {
4454
 
                                cal.cfg.destroy();
4455
 
                        }
4456
 
 
4457
 
                        // DOM event listeners
4458
 
                        Event.purgeElement(cal.oDomContainer, true);
4459
 
 
4460
 
                        // Generated markup/DOM - Not removing the container DIV since we didn't create it.
4461
 
                        Dom.removeClass(cal.oDomContainer, "withtitle");
4462
 
                        Dom.removeClass(cal.oDomContainer, cal.Style.CSS_CONTAINER);
4463
 
                        Dom.removeClass(cal.oDomContainer, cal.Style.CSS_SINGLE);
4464
 
                        cal.oDomContainer.innerHTML = "";
4465
 
 
4466
 
                        // JS-to-DOM references
4467
 
                        cal.oDomContainer = null;
4468
 
                        cal.cells = null;
4469
 
 
4470
 
                        this.destroyEvent.fire();
4471
 
                }
4472
 
        }
4473
 
};
4474
 
 
4475
 
YAHOO.widget.Calendar = Calendar;
4476
 
 
4477
 
/**
4478
 
* @namespace YAHOO.widget
4479
 
* @class Calendar_Core
4480
 
* @extends YAHOO.widget.Calendar
4481
 
* @deprecated The old Calendar_Core class is no longer necessary.
4482
 
*/
4483
 
YAHOO.widget.Calendar_Core = YAHOO.widget.Calendar;
4484
 
 
4485
 
YAHOO.widget.Cal_Core = YAHOO.widget.Calendar;
4486
 
 
4487
 
})();
4488
 
 
4489
 
(function() {
4490
 
 
4491
 
        var Dom = YAHOO.util.Dom,
4492
 
                DateMath = YAHOO.widget.DateMath,
4493
 
                Event = YAHOO.util.Event,
4494
 
                Lang = YAHOO.lang,
4495
 
                Calendar = YAHOO.widget.Calendar;
4496
 
 
4497
 
/**
4498
 
* YAHOO.widget.CalendarGroup is a special container class for YAHOO.widget.Calendar. This class facilitates
4499
 
* the ability to have multi-page calendar views that share a single dataset and are
4500
 
* dependent on each other.
4501
 
*
4502
 
* The calendar group instance will refer to each of its elements using a 0-based index.
4503
 
* For example, to construct the placeholder for a calendar group widget with id "cal1" and
4504
 
* containerId of "cal1Container", the markup would be as follows:
4505
 
*       <xmp>
4506
 
*               <div id="cal1Container_0"></div>
4507
 
*               <div id="cal1Container_1"></div>
4508
 
*       </xmp>
4509
 
* The tables for the calendars ("cal1_0" and "cal1_1") will be inserted into those containers.
4510
 
4511
 
* <p>
4512
 
* <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
4513
 
* The CalendarGroup can be constructed by simply providing a container ID string, 
4514
 
* or a reference to a container DIV HTMLElement (the element needs to exist 
4515
 
* in the document).
4516
 
4517
 
* E.g.:
4518
 
*       <xmp>
4519
 
*               var c = new YAHOO.widget.CalendarGroup("calContainer", configOptions);
4520
 
*       </xmp>
4521
 
* or:
4522
 
*   <xmp>
4523
 
*       var containerDiv = YAHOO.util.Dom.get("calContainer");
4524
 
*               var c = new YAHOO.widget.CalendarGroup(containerDiv, configOptions);
4525
 
*       </xmp>
4526
 
* </p>
4527
 
* <p>
4528
 
* If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
4529
 
* For example if an ID is not provided, and the container's ID is "calContainer", the CalendarGroup's ID will be set to "calContainer_t".
4530
 
* </p>
4531
 
4532
 
* @namespace YAHOO.widget
4533
 
* @class CalendarGroup
4534
 
* @constructor
4535
 
* @param {String} id optional The id of the table element that will represent the CalendarGroup widget. As of 2.4.0, this argument is optional.
4536
 
* @param {String | HTMLElement} container The id of the container div element that will wrap the CalendarGroup table, or a reference to a DIV element which exists in the document.
4537
 
* @param {Object} config optional The configuration object containing the initial configuration values for the CalendarGroup.
4538
 
*/
4539
 
function CalendarGroup(id, containerId, config) {
4540
 
        if (arguments.length > 0) {
4541
 
                this.init.apply(this, arguments);
4542
 
        }
4543
 
}
4544
 
 
4545
 
/**
4546
 
* The set of default Config property keys and values for the CalendarGroup
4547
 
* @property YAHOO.widget.CalendarGroup._DEFAULT_CONFIG
4548
 
* @final
4549
 
* @static
4550
 
* @private
4551
 
* @type Object
4552
 
*/
4553
 
CalendarGroup._DEFAULT_CONFIG = Calendar._DEFAULT_CONFIG;
4554
 
CalendarGroup._DEFAULT_CONFIG.PAGES = {key:"pages", value:2};
4555
 
 
4556
 
var DEF_CFG = CalendarGroup._DEFAULT_CONFIG;
4557
 
 
4558
 
CalendarGroup.prototype = {
4559
 
 
4560
 
        /**
4561
 
        * Initializes the calendar group. All subclasses must call this method in order for the
4562
 
        * group to be initialized properly.
4563
 
        * @method init
4564
 
        * @param {String} id optional The id of the table element that will represent the CalendarGroup widget. As of 2.4.0, this argument is optional.
4565
 
        * @param {String | HTMLElement} container The id of the container div element that will wrap the CalendarGroup table, or a reference to a DIV element which exists in the document.
4566
 
        * @param {Object} config optional The configuration object containing the initial configuration values for the CalendarGroup.
4567
 
        */
4568
 
        init : function(id, container, config) {
4569
 
 
4570
 
                // Normalize 2.4.0, pre 2.4.0 args
4571
 
                var nArgs = this._parseArgs(arguments);
4572
 
 
4573
 
                id = nArgs.id;
4574
 
                container = nArgs.container;
4575
 
                config = nArgs.config;
4576
 
 
4577
 
                this.oDomContainer = Dom.get(container);
4578
 
 
4579
 
                if (!this.oDomContainer.id) {
4580
 
                        this.oDomContainer.id = Dom.generateId();
4581
 
                }
4582
 
                if (!id) {
4583
 
                        id = this.oDomContainer.id + "_t";
4584
 
                }
4585
 
 
4586
 
                /**
4587
 
                * The unique id associated with the CalendarGroup
4588
 
                * @property id
4589
 
                * @type String
4590
 
                */
4591
 
                this.id = id;
4592
 
 
4593
 
                /**
4594
 
                * The unique id associated with the CalendarGroup container
4595
 
                * @property containerId
4596
 
                * @type String
4597
 
                */
4598
 
                this.containerId = this.oDomContainer.id;
4599
 
 
4600
 
                this.initEvents();
4601
 
                this.initStyles();
4602
 
 
4603
 
                /**
4604
 
                * The collection of Calendar pages contained within the CalendarGroup
4605
 
                * @property pages
4606
 
                * @type YAHOO.widget.Calendar[]
4607
 
                */
4608
 
                this.pages = [];
4609
 
 
4610
 
                Dom.addClass(this.oDomContainer, CalendarGroup.CSS_CONTAINER);
4611
 
                Dom.addClass(this.oDomContainer, CalendarGroup.CSS_MULTI_UP);
4612
 
 
4613
 
                /**
4614
 
                * The Config object used to hold the configuration variables for the CalendarGroup
4615
 
                * @property cfg
4616
 
                * @type YAHOO.util.Config
4617
 
                */
4618
 
                this.cfg = new YAHOO.util.Config(this);
4619
 
 
4620
 
                /**
4621
 
                * The local object which contains the CalendarGroup's options
4622
 
                * @property Options
4623
 
                * @type Object
4624
 
                */
4625
 
                this.Options = {};
4626
 
 
4627
 
                /**
4628
 
                * The local object which contains the CalendarGroup's locale settings
4629
 
                * @property Locale
4630
 
                * @type Object
4631
 
                */
4632
 
                this.Locale = {};
4633
 
 
4634
 
                this.setupConfig();
4635
 
 
4636
 
                if (config) {
4637
 
                        this.cfg.applyConfig(config, true);
4638
 
                }
4639
 
 
4640
 
                this.cfg.fireQueue();
4641
 
 
4642
 
                // OPERA HACK FOR MISWRAPPED FLOATS
4643
 
                if (YAHOO.env.ua.opera){
4644
 
                        this.renderEvent.subscribe(this._fixWidth, this, true);
4645
 
                        this.showEvent.subscribe(this._fixWidth, this, true);
4646
 
                }
4647
 
 
4648
 
        },
4649
 
 
4650
 
        setupConfig : function() {
4651
 
 
4652
 
                var cfg = this.cfg;
4653
 
 
4654
 
                /**
4655
 
                * The number of pages to include in the CalendarGroup. This value can only be set once, in the CalendarGroup's constructor arguments.
4656
 
                * @config pages
4657
 
                * @type Number
4658
 
                * @default 2
4659
 
                */
4660
 
                cfg.addProperty(DEF_CFG.PAGES.key, { value:DEF_CFG.PAGES.value, validator:cfg.checkNumber, handler:this.configPages } );
4661
 
 
4662
 
                /**
4663
 
                * The month/year representing the current visible Calendar date (mm/yyyy)
4664
 
                * @config pagedate
4665
 
                * @type String | Date
4666
 
                * @default today's date
4667
 
                */
4668
 
                cfg.addProperty(DEF_CFG.PAGEDATE.key, { value:new Date(), handler:this.configPageDate } );
4669
 
 
4670
 
                /**
4671
 
                * The date or range of dates representing the current Calendar selection
4672
 
                *
4673
 
                * @config selected
4674
 
                * @type String
4675
 
                * @default []
4676
 
                */
4677
 
                cfg.addProperty(DEF_CFG.SELECTED.key, { value:[], handler:this.configSelected } );
4678
 
 
4679
 
                /**
4680
 
                * The title to display above the CalendarGroup's month header
4681
 
                * @config title
4682
 
                * @type String
4683
 
                * @default ""
4684
 
                */
4685
 
                cfg.addProperty(DEF_CFG.TITLE.key, { value:DEF_CFG.TITLE.value, handler:this.configTitle } );
4686
 
 
4687
 
                /**
4688
 
                * Whether or not a close button should be displayed for this CalendarGroup
4689
 
                * @config close
4690
 
                * @type Boolean
4691
 
                * @default false
4692
 
                */
4693
 
                cfg.addProperty(DEF_CFG.CLOSE.key, { value:DEF_CFG.CLOSE.value, handler:this.configClose } );
4694
 
 
4695
 
                /**
4696
 
                * Whether or not an iframe shim should be placed under the Calendar to prevent select boxes from bleeding through in Internet Explorer 6 and below.
4697
 
                * This property is enabled by default for IE6 and below. It is disabled by default for other browsers for performance reasons, but can be 
4698
 
                * enabled if required.
4699
 
                * 
4700
 
                * @config iframe
4701
 
                * @type Boolean
4702
 
                * @default true for IE6 and below, false for all other browsers
4703
 
                */
4704
 
                cfg.addProperty(DEF_CFG.IFRAME.key, { value:DEF_CFG.IFRAME.value, handler:this.configIframe, validator:cfg.checkBoolean } );
4705
 
        
4706
 
                /**
4707
 
                * The minimum selectable date in the current Calendar (mm/dd/yyyy)
4708
 
                * @config mindate
4709
 
                * @type String | Date
4710
 
                * @default null
4711
 
                */
4712
 
                cfg.addProperty(DEF_CFG.MINDATE.key, { value:DEF_CFG.MINDATE.value, handler:this.delegateConfig } );
4713
 
        
4714
 
                /**
4715
 
                * The maximum selectable date in the current Calendar (mm/dd/yyyy)
4716
 
                * @config maxdate
4717
 
                * @type String | Date
4718
 
                * @default null
4719
 
                */
4720
 
                cfg.addProperty(DEF_CFG.MAXDATE.key, { value:DEF_CFG.MAXDATE.value, handler:this.delegateConfig  } );
4721
 
        
4722
 
                // Options properties
4723
 
 
4724
 
                /**
4725
 
                * True if the Calendar should allow multiple selections. False by default.
4726
 
                * @config MULTI_SELECT
4727
 
                * @type Boolean
4728
 
                * @default false
4729
 
                */
4730
 
                cfg.addProperty(DEF_CFG.MULTI_SELECT.key,       { value:DEF_CFG.MULTI_SELECT.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4731
 
 
4732
 
                /**
4733
 
                * The weekday the week begins on. Default is 0 (Sunday).
4734
 
                * @config START_WEEKDAY
4735
 
                * @type number
4736
 
                * @default 0
4737
 
                */      
4738
 
                cfg.addProperty(DEF_CFG.START_WEEKDAY.key,      { value:DEF_CFG.START_WEEKDAY.value, handler:this.delegateConfig, validator:cfg.checkNumber  } );
4739
 
                
4740
 
                /**
4741
 
                * True if the Calendar should show weekday labels. True by default.
4742
 
                * @config SHOW_WEEKDAYS
4743
 
                * @type Boolean
4744
 
                * @default true
4745
 
                */      
4746
 
                cfg.addProperty(DEF_CFG.SHOW_WEEKDAYS.key,      { value:DEF_CFG.SHOW_WEEKDAYS.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4747
 
                
4748
 
                /**
4749
 
                * True if the Calendar should show week row headers. False by default.
4750
 
                * @config SHOW_WEEK_HEADER
4751
 
                * @type Boolean
4752
 
                * @default false
4753
 
                */      
4754
 
                cfg.addProperty(DEF_CFG.SHOW_WEEK_HEADER.key,{ value:DEF_CFG.SHOW_WEEK_HEADER.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4755
 
                
4756
 
                /**
4757
 
                * True if the Calendar should show week row footers. False by default.
4758
 
                * @config SHOW_WEEK_FOOTER
4759
 
                * @type Boolean
4760
 
                * @default false
4761
 
                */
4762
 
                cfg.addProperty(DEF_CFG.SHOW_WEEK_FOOTER.key,{ value:DEF_CFG.SHOW_WEEK_FOOTER.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4763
 
                
4764
 
                /**
4765
 
                * True if the Calendar should suppress weeks that are not a part of the current month. False by default.
4766
 
                * @config HIDE_BLANK_WEEKS
4767
 
                * @type Boolean
4768
 
                * @default false
4769
 
                */              
4770
 
                cfg.addProperty(DEF_CFG.HIDE_BLANK_WEEKS.key,{ value:DEF_CFG.HIDE_BLANK_WEEKS.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4771
 
                
4772
 
                /**
4773
 
                * The image that should be used for the left navigation arrow.
4774
 
                * @config NAV_ARROW_LEFT
4775
 
                * @type String
4776
 
                * @deprecated   You can customize the image by overriding the default CSS class for the left arrow - "calnavleft"
4777
 
                * @default null
4778
 
                */              
4779
 
                cfg.addProperty(DEF_CFG.NAV_ARROW_LEFT.key,     { value:DEF_CFG.NAV_ARROW_LEFT.value, handler:this.delegateConfig } );
4780
 
                
4781
 
                /**
4782
 
                * The image that should be used for the right navigation arrow.
4783
 
                * @config NAV_ARROW_RIGHT
4784
 
                * @type String
4785
 
                * @deprecated   You can customize the image by overriding the default CSS class for the right arrow - "calnavright"
4786
 
                * @default null
4787
 
                */              
4788
 
                cfg.addProperty(DEF_CFG.NAV_ARROW_RIGHT.key,    { value:DEF_CFG.NAV_ARROW_RIGHT.value, handler:this.delegateConfig } );
4789
 
        
4790
 
                // Locale properties
4791
 
                
4792
 
                /**
4793
 
                * The short month labels for the current locale.
4794
 
                * @config MONTHS_SHORT
4795
 
                * @type String[]
4796
 
                * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
4797
 
                */
4798
 
                cfg.addProperty(DEF_CFG.MONTHS_SHORT.key,       { value:DEF_CFG.MONTHS_SHORT.value, handler:this.delegateConfig } );
4799
 
                
4800
 
                /**
4801
 
                * The long month labels for the current locale.
4802
 
                * @config MONTHS_LONG
4803
 
                * @type String[]
4804
 
                * @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
4805
 
                */              
4806
 
                cfg.addProperty(DEF_CFG.MONTHS_LONG.key,                { value:DEF_CFG.MONTHS_LONG.value, handler:this.delegateConfig } );
4807
 
                
4808
 
                /**
4809
 
                * The 1-character weekday labels for the current locale.
4810
 
                * @config WEEKDAYS_1CHAR
4811
 
                * @type String[]
4812
 
                * @default ["S", "M", "T", "W", "T", "F", "S"]
4813
 
                */              
4814
 
                cfg.addProperty(DEF_CFG.WEEKDAYS_1CHAR.key,     { value:DEF_CFG.WEEKDAYS_1CHAR.value, handler:this.delegateConfig } );
4815
 
                
4816
 
                /**
4817
 
                * The short weekday labels for the current locale.
4818
 
                * @config WEEKDAYS_SHORT
4819
 
                * @type String[]
4820
 
                * @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
4821
 
                */              
4822
 
                cfg.addProperty(DEF_CFG.WEEKDAYS_SHORT.key,     { value:DEF_CFG.WEEKDAYS_SHORT.value, handler:this.delegateConfig } );
4823
 
                
4824
 
                /**
4825
 
                * The medium weekday labels for the current locale.
4826
 
                * @config WEEKDAYS_MEDIUM
4827
 
                * @type String[]
4828
 
                * @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
4829
 
                */              
4830
 
                cfg.addProperty(DEF_CFG.WEEKDAYS_MEDIUM.key,    { value:DEF_CFG.WEEKDAYS_MEDIUM.value, handler:this.delegateConfig } );
4831
 
                
4832
 
                /**
4833
 
                * The long weekday labels for the current locale.
4834
 
                * @config WEEKDAYS_LONG
4835
 
                * @type String[]
4836
 
                * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
4837
 
                */              
4838
 
                cfg.addProperty(DEF_CFG.WEEKDAYS_LONG.key,      { value:DEF_CFG.WEEKDAYS_LONG.value, handler:this.delegateConfig } );
4839
 
        
4840
 
                /**
4841
 
                * The setting that determines which length of month labels should be used. Possible values are "short" and "long".
4842
 
                * @config LOCALE_MONTHS
4843
 
                * @type String
4844
 
                * @default "long"
4845
 
                */
4846
 
                cfg.addProperty(DEF_CFG.LOCALE_MONTHS.key,      { value:DEF_CFG.LOCALE_MONTHS.value, handler:this.delegateConfig } );
4847
 
        
4848
 
                /**
4849
 
                * The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
4850
 
                * @config LOCALE_WEEKDAYS
4851
 
                * @type String
4852
 
                * @default "short"
4853
 
                */      
4854
 
                cfg.addProperty(DEF_CFG.LOCALE_WEEKDAYS.key,    { value:DEF_CFG.LOCALE_WEEKDAYS.value, handler:this.delegateConfig } );
4855
 
        
4856
 
                /**
4857
 
                * The value used to delimit individual dates in a date string passed to various Calendar functions.
4858
 
                * @config DATE_DELIMITER
4859
 
                * @type String
4860
 
                * @default ","
4861
 
                */
4862
 
                cfg.addProperty(DEF_CFG.DATE_DELIMITER.key,             { value:DEF_CFG.DATE_DELIMITER.value, handler:this.delegateConfig } );
4863
 
        
4864
 
                /**
4865
 
                * The value used to delimit date fields in a date string passed to various Calendar functions.
4866
 
                * @config DATE_FIELD_DELIMITER
4867
 
                * @type String
4868
 
                * @default "/"
4869
 
                */      
4870
 
                cfg.addProperty(DEF_CFG.DATE_FIELD_DELIMITER.key,{ value:DEF_CFG.DATE_FIELD_DELIMITER.value, handler:this.delegateConfig } );
4871
 
        
4872
 
                /**
4873
 
                * The value used to delimit date ranges in a date string passed to various Calendar functions.
4874
 
                * @config DATE_RANGE_DELIMITER
4875
 
                * @type String
4876
 
                * @default "-"
4877
 
                */
4878
 
                cfg.addProperty(DEF_CFG.DATE_RANGE_DELIMITER.key,{ value:DEF_CFG.DATE_RANGE_DELIMITER.value, handler:this.delegateConfig } );
4879
 
        
4880
 
                /**
4881
 
                * The position of the month in a month/year date string
4882
 
                * @config MY_MONTH_POSITION
4883
 
                * @type Number
4884
 
                * @default 1
4885
 
                */
4886
 
                cfg.addProperty(DEF_CFG.MY_MONTH_POSITION.key,  { value:DEF_CFG.MY_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4887
 
                
4888
 
                /**
4889
 
                * The position of the year in a month/year date string
4890
 
                * @config MY_YEAR_POSITION
4891
 
                * @type Number
4892
 
                * @default 2
4893
 
                */      
4894
 
                cfg.addProperty(DEF_CFG.MY_YEAR_POSITION.key,   { value:DEF_CFG.MY_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4895
 
                
4896
 
                /**
4897
 
                * The position of the month in a month/day date string
4898
 
                * @config MD_MONTH_POSITION
4899
 
                * @type Number
4900
 
                * @default 1
4901
 
                */      
4902
 
                cfg.addProperty(DEF_CFG.MD_MONTH_POSITION.key,  { value:DEF_CFG.MD_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4903
 
                
4904
 
                /**
4905
 
                * The position of the day in a month/year date string
4906
 
                * @config MD_DAY_POSITION
4907
 
                * @type Number
4908
 
                * @default 2
4909
 
                */      
4910
 
                cfg.addProperty(DEF_CFG.MD_DAY_POSITION.key,            { value:DEF_CFG.MD_DAY_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4911
 
                
4912
 
                /**
4913
 
                * The position of the month in a month/day/year date string
4914
 
                * @config MDY_MONTH_POSITION
4915
 
                * @type Number
4916
 
                * @default 1
4917
 
                */      
4918
 
                cfg.addProperty(DEF_CFG.MDY_MONTH_POSITION.key, { value:DEF_CFG.MDY_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4919
 
                
4920
 
                /**
4921
 
                * The position of the day in a month/day/year date string
4922
 
                * @config MDY_DAY_POSITION
4923
 
                * @type Number
4924
 
                * @default 2
4925
 
                */      
4926
 
                cfg.addProperty(DEF_CFG.MDY_DAY_POSITION.key,   { value:DEF_CFG.MDY_DAY_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4927
 
                
4928
 
                /**
4929
 
                * The position of the year in a month/day/year date string
4930
 
                * @config MDY_YEAR_POSITION
4931
 
                * @type Number
4932
 
                * @default 3
4933
 
                */      
4934
 
                cfg.addProperty(DEF_CFG.MDY_YEAR_POSITION.key,  { value:DEF_CFG.MDY_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4935
 
        
4936
 
                /**
4937
 
                * The position of the month in the month year label string used as the Calendar header
4938
 
                * @config MY_LABEL_MONTH_POSITION
4939
 
                * @type Number
4940
 
                * @default 1
4941
 
                */
4942
 
                cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_POSITION.key,    { value:DEF_CFG.MY_LABEL_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4943
 
        
4944
 
                /**
4945
 
                * The position of the year in the month year label string used as the Calendar header
4946
 
                * @config MY_LABEL_YEAR_POSITION
4947
 
                * @type Number
4948
 
                * @default 2
4949
 
                */
4950
 
                cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_POSITION.key,     { value:DEF_CFG.MY_LABEL_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4951
 
 
4952
 
                /**
4953
 
                * The suffix used after the month when rendering the Calendar header
4954
 
                * @config MY_LABEL_MONTH_SUFFIX
4955
 
                * @type String
4956
 
                * @default " "
4957
 
                */
4958
 
                cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_SUFFIX.key,      { value:DEF_CFG.MY_LABEL_MONTH_SUFFIX.value, handler:this.delegateConfig } );
4959
 
                
4960
 
                /**
4961
 
                * The suffix used after the year when rendering the Calendar header
4962
 
                * @config MY_LABEL_YEAR_SUFFIX
4963
 
                * @type String
4964
 
                * @default ""
4965
 
                */
4966
 
                cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_SUFFIX.key, { value:DEF_CFG.MY_LABEL_YEAR_SUFFIX.value, handler:this.delegateConfig } );
4967
 
 
4968
 
                /**
4969
 
                * Configuration for the Month Year Navigation UI. By default it is disabled
4970
 
                * @config NAV
4971
 
                * @type Object
4972
 
                * @default null
4973
 
                */
4974
 
                cfg.addProperty(DEF_CFG.NAV.key, { value:DEF_CFG.NAV.value, handler:this.configNavigator } );
4975
 
 
4976
 
                /**
4977
 
                 * The map of UI strings which the CalendarGroup UI uses.
4978
 
                 *
4979
 
                 * @config strings
4980
 
                 * @type {Object}
4981
 
                 * @default An object with the properties shown below:
4982
 
                 *     <dl>
4983
 
                 *         <dt>previousMonth</dt><dd><em>String</em> : The string to use for the "Previous Month" navigation UI. Defaults to "Previous Month".</dd>
4984
 
                 *         <dt>nextMonth</dt><dd><em>String</em> : The string to use for the "Next Month" navigation UI. Defaults to "Next Month".</dd>
4985
 
                 *         <dt>close</dt><dd><em>String</em> : The string to use for the close button label. Defaults to "Close".</dd>
4986
 
                 *     </dl>
4987
 
                 */
4988
 
                cfg.addProperty(DEF_CFG.STRINGS.key, { 
4989
 
                        value:DEF_CFG.STRINGS.value, 
4990
 
                        handler:this.configStrings, 
4991
 
                        validator: function(val) {
4992
 
                                return Lang.isObject(val);
4993
 
                        },
4994
 
                        supercedes: DEF_CFG.STRINGS.supercedes
4995
 
                });
4996
 
        },
4997
 
 
4998
 
        /**
4999
 
        * Initializes CalendarGroup's built-in CustomEvents
5000
 
        * @method initEvents
5001
 
        */
5002
 
        initEvents : function() {
5003
 
 
5004
 
                var me = this,
5005
 
                        strEvent = "Event",
5006
 
                        CE = YAHOO.util.CustomEvent;
5007
 
 
5008
 
                /**
5009
 
                * Proxy subscriber to subscribe to the CalendarGroup's child Calendars' CustomEvents
5010
 
                * @method sub
5011
 
                * @private
5012
 
                * @param {Function} fn  The function to subscribe to this CustomEvent
5013
 
                * @param {Object}       obj     The CustomEvent's scope object
5014
 
                * @param {Boolean}      bOverride       Whether or not to apply scope correction
5015
 
                */
5016
 
                var sub = function(fn, obj, bOverride) {
5017
 
                        for (var p=0;p<me.pages.length;++p) {
5018
 
                                var cal = me.pages[p];
5019
 
                                cal[this.type + strEvent].subscribe(fn, obj, bOverride);
5020
 
                        }
5021
 
                };
5022
 
 
5023
 
                /**
5024
 
                * Proxy unsubscriber to unsubscribe from the CalendarGroup's child Calendars' CustomEvents
5025
 
                * @method unsub
5026
 
                * @private
5027
 
                * @param {Function} fn  The function to subscribe to this CustomEvent
5028
 
                * @param {Object}       obj     The CustomEvent's scope object
5029
 
                */
5030
 
                var unsub = function(fn, obj) {
5031
 
                        for (var p=0;p<me.pages.length;++p) {
5032
 
                                var cal = me.pages[p];
5033
 
                                cal[this.type + strEvent].unsubscribe(fn, obj);
5034
 
                        }
5035
 
                };
5036
 
 
5037
 
                var defEvents = Calendar._EVENT_TYPES;
5038
 
 
5039
 
                /**
5040
 
                * Fired before a date selection is made
5041
 
                * @event beforeSelectEvent
5042
 
                */
5043
 
                me.beforeSelectEvent = new CE(defEvents.BEFORE_SELECT);
5044
 
                me.beforeSelectEvent.subscribe = sub; me.beforeSelectEvent.unsubscribe = unsub;
5045
 
 
5046
 
                /**
5047
 
                * Fired when a date selection is made
5048
 
                * @event selectEvent
5049
 
                * @param {Array}        Array of Date field arrays in the format [YYYY, MM, DD].
5050
 
                */
5051
 
                me.selectEvent = new CE(defEvents.SELECT); 
5052
 
                me.selectEvent.subscribe = sub; me.selectEvent.unsubscribe = unsub;
5053
 
 
5054
 
                /**
5055
 
                * Fired before a date or set of dates is deselected
5056
 
                * @event beforeDeselectEvent
5057
 
                */
5058
 
                me.beforeDeselectEvent = new CE(defEvents.BEFORE_DESELECT); 
5059
 
                me.beforeDeselectEvent.subscribe = sub; me.beforeDeselectEvent.unsubscribe = unsub;
5060
 
 
5061
 
                /**
5062
 
                * Fired when a date or set of dates has been deselected
5063
 
                * @event deselectEvent
5064
 
                * @param {Array}        Array of Date field arrays in the format [YYYY, MM, DD].
5065
 
                */
5066
 
                me.deselectEvent = new CE(defEvents.DESELECT); 
5067
 
                me.deselectEvent.subscribe = sub; me.deselectEvent.unsubscribe = unsub;
5068
 
                
5069
 
                /**
5070
 
                * Fired when the Calendar page is changed
5071
 
                * @event changePageEvent
5072
 
                */
5073
 
                me.changePageEvent = new CE(defEvents.CHANGE_PAGE); 
5074
 
                me.changePageEvent.subscribe = sub; me.changePageEvent.unsubscribe = unsub;
5075
 
 
5076
 
                /**
5077
 
                * Fired before the Calendar is rendered
5078
 
                * @event beforeRenderEvent
5079
 
                */
5080
 
                me.beforeRenderEvent = new CE(defEvents.BEFORE_RENDER);
5081
 
                me.beforeRenderEvent.subscribe = sub; me.beforeRenderEvent.unsubscribe = unsub;
5082
 
        
5083
 
                /**
5084
 
                * Fired when the Calendar is rendered
5085
 
                * @event renderEvent
5086
 
                */
5087
 
                me.renderEvent = new CE(defEvents.RENDER);
5088
 
                me.renderEvent.subscribe = sub; me.renderEvent.unsubscribe = unsub;
5089
 
        
5090
 
                /**
5091
 
                * Fired when the Calendar is reset
5092
 
                * @event resetEvent
5093
 
                */
5094
 
                me.resetEvent = new CE(defEvents.RESET); 
5095
 
                me.resetEvent.subscribe = sub; me.resetEvent.unsubscribe = unsub;
5096
 
        
5097
 
                /**
5098
 
                * Fired when the Calendar is cleared
5099
 
                * @event clearEvent
5100
 
                */
5101
 
                me.clearEvent = new CE(defEvents.CLEAR);
5102
 
                me.clearEvent.subscribe = sub; me.clearEvent.unsubscribe = unsub;
5103
 
 
5104
 
                /**
5105
 
                * Fired just before the CalendarGroup is to be shown
5106
 
                * @event beforeShowEvent
5107
 
                */
5108
 
                me.beforeShowEvent = new CE(defEvents.BEFORE_SHOW);
5109
 
        
5110
 
                /**
5111
 
                * Fired after the CalendarGroup is shown
5112
 
                * @event showEvent
5113
 
                */
5114
 
                me.showEvent = new CE(defEvents.SHOW);
5115
 
        
5116
 
                /**
5117
 
                * Fired just before the CalendarGroup is to be hidden
5118
 
                * @event beforeHideEvent
5119
 
                */
5120
 
                me.beforeHideEvent = new CE(defEvents.BEFORE_HIDE);
5121
 
        
5122
 
                /**
5123
 
                * Fired after the CalendarGroup is hidden
5124
 
                * @event hideEvent
5125
 
                */
5126
 
                me.hideEvent = new CE(defEvents.HIDE);
5127
 
 
5128
 
                /**
5129
 
                * Fired just before the CalendarNavigator is to be shown
5130
 
                * @event beforeShowNavEvent
5131
 
                */
5132
 
                me.beforeShowNavEvent = new CE(defEvents.BEFORE_SHOW_NAV);
5133
 
        
5134
 
                /**
5135
 
                * Fired after the CalendarNavigator is shown
5136
 
                * @event showNavEvent
5137
 
                */
5138
 
                me.showNavEvent = new CE(defEvents.SHOW_NAV);
5139
 
        
5140
 
                /**
5141
 
                * Fired just before the CalendarNavigator is to be hidden
5142
 
                * @event beforeHideNavEvent
5143
 
                */
5144
 
                me.beforeHideNavEvent = new CE(defEvents.BEFORE_HIDE_NAV);
5145
 
 
5146
 
                /**
5147
 
                * Fired after the CalendarNavigator is hidden
5148
 
                * @event hideNavEvent
5149
 
                */
5150
 
                me.hideNavEvent = new CE(defEvents.HIDE_NAV);
5151
 
 
5152
 
                /**
5153
 
                * Fired just before the CalendarNavigator is to be rendered
5154
 
                * @event beforeRenderNavEvent
5155
 
                */
5156
 
                me.beforeRenderNavEvent = new CE(defEvents.BEFORE_RENDER_NAV);
5157
 
 
5158
 
                /**
5159
 
                * Fired after the CalendarNavigator is rendered
5160
 
                * @event renderNavEvent
5161
 
                */
5162
 
                me.renderNavEvent = new CE(defEvents.RENDER_NAV);
5163
 
 
5164
 
                /**
5165
 
                * Fired just before the CalendarGroup is to be destroyed
5166
 
                * @event beforeDestroyEvent
5167
 
                */
5168
 
                me.beforeDestroyEvent = new CE(defEvents.BEFORE_DESTROY);
5169
 
 
5170
 
                /**
5171
 
                * Fired after the CalendarGroup is destroyed. This event should be used
5172
 
                * for notification only. When this event is fired, important CalendarGroup instance
5173
 
                * properties, dom references and event listeners have already been 
5174
 
                * removed/dereferenced, and hence the CalendarGroup instance is not in a usable 
5175
 
                * state.
5176
 
                *
5177
 
                * @event destroyEvent
5178
 
                */
5179
 
                me.destroyEvent = new CE(defEvents.DESTROY);
5180
 
        },
5181
 
        
5182
 
        /**
5183
 
        * The default Config handler for the "pages" property
5184
 
        * @method configPages
5185
 
        * @param {String} type  The CustomEvent type (usually the property name)
5186
 
        * @param {Object[]}     args    The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
5187
 
        * @param {Object} obj   The scope object. For configuration handlers, this will usually equal the owner.
5188
 
        */
5189
 
        configPages : function(type, args, obj) {
5190
 
                var pageCount = args[0],
5191
 
                        cfgPageDate = DEF_CFG.PAGEDATE.key,
5192
 
                        sep = "_",
5193
 
                        caldate,
5194
 
                        firstPageDate = null,
5195
 
                        groupCalClass = "groupcal",
5196
 
                        firstClass = "first-of-type",
5197
 
                        lastClass = "last-of-type";
5198
 
 
5199
 
                for (var p=0;p<pageCount;++p) {
5200
 
                        var calId = this.id + sep + p,
5201
 
                                calContainerId = this.containerId + sep + p,
5202
 
                                childConfig = this.cfg.getConfig();
5203
 
 
5204
 
                        childConfig.close = false;
5205
 
                        childConfig.title = false;
5206
 
                        childConfig.navigator = null;
5207
 
 
5208
 
                        if (p > 0) {
5209
 
                                caldate = new Date(firstPageDate);
5210
 
                                this._setMonthOnDate(caldate, caldate.getMonth() + p);
5211
 
                                childConfig.pageDate = caldate;
5212
 
                        }
5213
 
 
5214
 
                        var cal = this.constructChild(calId, calContainerId, childConfig);
5215
 
 
5216
 
                        Dom.removeClass(cal.oDomContainer, this.Style.CSS_SINGLE);
5217
 
                        Dom.addClass(cal.oDomContainer, groupCalClass);
5218
 
 
5219
 
                        if (p===0) {
5220
 
                                firstPageDate = cal.cfg.getProperty(cfgPageDate);
5221
 
                                Dom.addClass(cal.oDomContainer, firstClass);
5222
 
                        }
5223
 
        
5224
 
                        if (p==(pageCount-1)) {
5225
 
                                Dom.addClass(cal.oDomContainer, lastClass);
5226
 
                        }
5227
 
        
5228
 
                        cal.parent = this;
5229
 
                        cal.index = p; 
5230
 
        
5231
 
                        this.pages[this.pages.length] = cal;
5232
 
                }
5233
 
        },
5234
 
        
5235
 
        /**
5236
 
        * The default Config handler for the "pagedate" property
5237
 
        * @method configPageDate
5238
 
        * @param {String} type  The CustomEvent type (usually the property name)
5239
 
        * @param {Object[]}     args    The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
5240
 
        * @param {Object} obj   The scope object. For configuration handlers, this will usually equal the owner.
5241
 
        */
5242
 
        configPageDate : function(type, args, obj) {
5243
 
                var val = args[0],
5244
 
                        firstPageDate;
5245
 
 
5246
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key;
5247
 
                
5248
 
                for (var p=0;p<this.pages.length;++p) {
5249
 
                        var cal = this.pages[p];
5250
 
                        if (p === 0) {
5251
 
                                firstPageDate = cal._parsePageDate(val);
5252
 
                                cal.cfg.setProperty(cfgPageDate, firstPageDate);
5253
 
                        } else {
5254
 
                                var pageDate = new Date(firstPageDate);
5255
 
                                this._setMonthOnDate(pageDate, pageDate.getMonth() + p);
5256
 
                                cal.cfg.setProperty(cfgPageDate, pageDate);
5257
 
                        }
5258
 
                }
5259
 
        },
5260
 
        
5261
 
        /**
5262
 
        * The default Config handler for the CalendarGroup "selected" property
5263
 
        * @method configSelected
5264
 
        * @param {String} type  The CustomEvent type (usually the property name)
5265
 
        * @param {Object[]}     args    The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
5266
 
        * @param {Object} obj   The scope object. For configuration handlers, this will usually equal the owner.
5267
 
        */
5268
 
        configSelected : function(type, args, obj) {
5269
 
                var cfgSelected = DEF_CFG.SELECTED.key;
5270
 
                this.delegateConfig(type, args, obj);
5271
 
                var selected = (this.pages.length > 0) ? this.pages[0].cfg.getProperty(cfgSelected) : []; 
5272
 
                this.cfg.setProperty(cfgSelected, selected, true);
5273
 
        },
5274
 
 
5275
 
        
5276
 
        /**
5277
 
        * Delegates a configuration property to the CustomEvents associated with the CalendarGroup's children
5278
 
        * @method delegateConfig
5279
 
        * @param {String} type  The CustomEvent type (usually the property name)
5280
 
        * @param {Object[]}     args    The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
5281
 
        * @param {Object} obj   The scope object. For configuration handlers, this will usually equal the owner.
5282
 
        */
5283
 
        delegateConfig : function(type, args, obj) {
5284
 
                var val = args[0];
5285
 
                var cal;
5286
 
        
5287
 
                for (var p=0;p<this.pages.length;p++) {
5288
 
                        cal = this.pages[p];
5289
 
                        cal.cfg.setProperty(type, val);
5290
 
                }
5291
 
        },
5292
 
 
5293
 
        /**
5294
 
        * Adds a function to all child Calendars within this CalendarGroup.
5295
 
        * @method setChildFunction
5296
 
        * @param {String}               fnName          The name of the function
5297
 
        * @param {Function}             fn                      The function to apply to each Calendar page object
5298
 
        */
5299
 
        setChildFunction : function(fnName, fn) {
5300
 
                var pageCount = this.cfg.getProperty(DEF_CFG.PAGES.key);
5301
 
        
5302
 
                for (var p=0;p<pageCount;++p) {
5303
 
                        this.pages[p][fnName] = fn;
5304
 
                }
5305
 
        },
5306
 
 
5307
 
        /**
5308
 
        * Calls a function within all child Calendars within this CalendarGroup.
5309
 
        * @method callChildFunction
5310
 
        * @param {String}               fnName          The name of the function
5311
 
        * @param {Array}                args            The arguments to pass to the function
5312
 
        */
5313
 
        callChildFunction : function(fnName, args) {
5314
 
                var pageCount = this.cfg.getProperty(DEF_CFG.PAGES.key);
5315
 
 
5316
 
                for (var p=0;p<pageCount;++p) {
5317
 
                        var page = this.pages[p];
5318
 
                        if (page[fnName]) {
5319
 
                                var fn = page[fnName];
5320
 
                                fn.call(page, args);
5321
 
                        }
5322
 
                }       
5323
 
        },
5324
 
 
5325
 
        /**
5326
 
        * Constructs a child calendar. This method can be overridden if a subclassed version of the default
5327
 
        * calendar is to be used.
5328
 
        * @method constructChild
5329
 
        * @param {String}       id                      The id of the table element that will represent the calendar widget
5330
 
        * @param {String}       containerId     The id of the container div element that will wrap the calendar table
5331
 
        * @param {Object}       config          The configuration object containing the Calendar's arguments
5332
 
        * @return {YAHOO.widget.Calendar}       The YAHOO.widget.Calendar instance that is constructed
5333
 
        */
5334
 
        constructChild : function(id,containerId,config) {
5335
 
                var container = document.getElementById(containerId);
5336
 
                if (! container) {
5337
 
                        container = document.createElement("div");
5338
 
                        container.id = containerId;
5339
 
                        this.oDomContainer.appendChild(container);
5340
 
                }
5341
 
                return new Calendar(id,containerId,config);
5342
 
        },
5343
 
        
5344
 
        /**
5345
 
        * Sets the calendar group's month explicitly. This month will be set into the first
5346
 
        * page of the multi-page calendar, and all other months will be iterated appropriately.
5347
 
        * @method setMonth
5348
 
        * @param {Number}       month           The numeric month, from 0 (January) to 11 (December)
5349
 
        */
5350
 
        setMonth : function(month) {
5351
 
                month = parseInt(month, 10);
5352
 
                var currYear;
5353
 
 
5354
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key;
5355
 
 
5356
 
                for (var p=0; p<this.pages.length; ++p) {
5357
 
                        var cal = this.pages[p];
5358
 
                        var pageDate = cal.cfg.getProperty(cfgPageDate);
5359
 
                        if (p === 0) {
5360
 
                                currYear = pageDate.getFullYear();
5361
 
                        } else {
5362
 
                                pageDate.setFullYear(currYear);
5363
 
                        }
5364
 
                        this._setMonthOnDate(pageDate, month+p); 
5365
 
                        cal.cfg.setProperty(cfgPageDate, pageDate);
5366
 
                }
5367
 
        },
5368
 
 
5369
 
        /**
5370
 
        * Sets the calendar group's year explicitly. This year will be set into the first
5371
 
        * page of the multi-page calendar, and all other months will be iterated appropriately.
5372
 
        * @method setYear
5373
 
        * @param {Number}       year            The numeric 4-digit year
5374
 
        */
5375
 
        setYear : function(year) {
5376
 
        
5377
 
                var cfgPageDate = DEF_CFG.PAGEDATE.key;
5378
 
        
5379
 
                year = parseInt(year, 10);
5380
 
                for (var p=0;p<this.pages.length;++p) {
5381
 
                        var cal = this.pages[p];
5382
 
                        var pageDate = cal.cfg.getProperty(cfgPageDate);
5383
 
        
5384
 
                        if ((pageDate.getMonth()+1) == 1 && p>0) {
5385
 
                                year+=1;
5386
 
                        }
5387
 
                        cal.setYear(year);
5388
 
                }
5389
 
        },
5390
 
 
5391
 
        /**
5392
 
        * Calls the render function of all child calendars within the group.
5393
 
        * @method render
5394
 
        */
5395
 
        render : function() {
5396
 
                this.renderHeader();
5397
 
                for (var p=0;p<this.pages.length;++p) {
5398
 
                        var cal = this.pages[p];
5399
 
                        cal.render();
5400
 
                }
5401
 
                this.renderFooter();
5402
 
        },
5403
 
 
5404
 
        /**
5405
 
        * Selects a date or a collection of dates on the current calendar. This method, by default,
5406
 
        * does not call the render method explicitly. Once selection has completed, render must be 
5407
 
        * called for the changes to be reflected visually.
5408
 
        * @method select
5409
 
        * @param        {String/Date/Date[]}    date    The date string of dates to select in the current calendar. Valid formats are
5410
 
        *                                                               individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
5411
 
        *                                                               Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
5412
 
        *                                                               This method can also take a JavaScript Date object or an array of Date objects.
5413
 
        * @return       {Date[]}                        Array of JavaScript Date objects representing all individual dates that are currently selected.
5414
 
        */
5415
 
        select : function(date) {
5416
 
                for (var p=0;p<this.pages.length;++p) {
5417
 
                        var cal = this.pages[p];
5418
 
                        cal.select(date);
5419
 
                }
5420
 
                return this.getSelectedDates();
5421
 
        },
5422
 
 
5423
 
        /**
5424
 
        * Selects dates in the CalendarGroup based on the cell index provided. This method is used to select cells without having to do a full render. The selected style is applied to the cells directly.
5425
 
        * The value of the MULTI_SELECT Configuration attribute will determine the set of dates which get selected. 
5426
 
        * <ul>
5427
 
        *    <li>If MULTI_SELECT is false, selectCell will select the cell at the specified index for only the last displayed Calendar page.</li>
5428
 
        *    <li>If MULTI_SELECT is true, selectCell will select the cell at the specified index, on each displayed Calendar page.</li>
5429
 
        * </ul>
5430
 
        * @method selectCell
5431
 
        * @param        {Number}        cellIndex       The index of the cell to be selected. 
5432
 
        * @return       {Date[]}        Array of JavaScript Date objects representing all individual dates that are currently selected.
5433
 
        */
5434
 
        selectCell : function(cellIndex) {
5435
 
                for (var p=0;p<this.pages.length;++p) {
5436
 
                        var cal = this.pages[p];
5437
 
                        cal.selectCell(cellIndex);
5438
 
                }
5439
 
                return this.getSelectedDates();
5440
 
        },
5441
 
        
5442
 
        /**
5443
 
        * Deselects a date or a collection of dates on the current calendar. This method, by default,
5444
 
        * does not call the render method explicitly. Once deselection has completed, render must be 
5445
 
        * called for the changes to be reflected visually.
5446
 
        * @method deselect
5447
 
        * @param        {String/Date/Date[]}    date    The date string of dates to deselect in the current calendar. Valid formats are
5448
 
        *                                                               individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
5449
 
        *                                                               Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
5450
 
        *                                                               This method can also take a JavaScript Date object or an array of Date objects. 
5451
 
        * @return       {Date[]}                        Array of JavaScript Date objects representing all individual dates that are currently selected.
5452
 
        */
5453
 
        deselect : function(date) {
5454
 
                for (var p=0;p<this.pages.length;++p) {
5455
 
                        var cal = this.pages[p];
5456
 
                        cal.deselect(date);
5457
 
                }
5458
 
                return this.getSelectedDates();
5459
 
        },
5460
 
        
5461
 
        /**
5462
 
        * Deselects all dates on the current calendar.
5463
 
        * @method deselectAll
5464
 
        * @return {Date[]}              Array of JavaScript Date objects representing all individual dates that are currently selected.
5465
 
        *                                               Assuming that this function executes properly, the return value should be an empty array.
5466
 
        *                                               However, the empty array is returned for the sake of being able to check the selection status
5467
 
        *                                               of the calendar.
5468
 
        */
5469
 
        deselectAll : function() {
5470
 
                for (var p=0;p<this.pages.length;++p) {
5471
 
                        var cal = this.pages[p];
5472
 
                        cal.deselectAll();
5473
 
                }
5474
 
                return this.getSelectedDates();
5475
 
        },
5476
 
 
5477
 
        /**
5478
 
        * Deselects dates in the CalendarGroup based on the cell index provided. This method is used to select cells without having to do a full render. The selected style is applied to the cells directly.
5479
 
        * deselectCell will deselect the cell at the specified index on each displayed Calendar page.
5480
 
        *
5481
 
        * @method deselectCell
5482
 
        * @param        {Number}        cellIndex       The index of the cell to deselect. 
5483
 
        * @return       {Date[]}        Array of JavaScript Date objects representing all individual dates that are currently selected.
5484
 
        */
5485
 
        deselectCell : function(cellIndex) {
5486
 
                for (var p=0;p<this.pages.length;++p) {
5487
 
                        var cal = this.pages[p];
5488
 
                        cal.deselectCell(cellIndex);
5489
 
                }
5490
 
                return this.getSelectedDates();
5491
 
        },
5492
 
 
5493
 
        /**
5494
 
        * Resets the calendar widget to the originally selected month and year, and 
5495
 
        * sets the calendar to the initial selection(s).
5496
 
        * @method reset
5497
 
        */
5498
 
        reset : function() {
5499
 
                for (var p=0;p<this.pages.length;++p) {
5500
 
                        var cal = this.pages[p];
5501
 
                        cal.reset();
5502
 
                }
5503
 
        },
5504
 
 
5505
 
        /**
5506
 
        * Clears the selected dates in the current calendar widget and sets the calendar
5507
 
        * to the current month and year.
5508
 
        * @method clear
5509
 
        */
5510
 
        clear : function() {
5511
 
                for (var p=0;p<this.pages.length;++p) {
5512
 
                        var cal = this.pages[p];
5513
 
                        cal.clear();
5514
 
                }
5515
 
 
5516
 
                this.cfg.setProperty(DEF_CFG.SELECTED.key, []);
5517
 
                this.cfg.setProperty(DEF_CFG.PAGEDATE.key, new Date(this.pages[0].today.getTime()));
5518
 
                this.render();
5519
 
        },
5520
 
 
5521
 
        /**
5522
 
        * Navigates to the next month page in the calendar widget.
5523
 
        * @method nextMonth
5524
 
        */
5525
 
        nextMonth : function() {
5526
 
                for (var p=0;p<this.pages.length;++p) {
5527
 
                        var cal = this.pages[p];
5528
 
                        cal.nextMonth();
5529
 
                }
5530
 
        },
5531
 
        
5532
 
        /**
5533
 
        * Navigates to the previous month page in the calendar widget.
5534
 
        * @method previousMonth
5535
 
        */
5536
 
        previousMonth : function() {
5537
 
                for (var p=this.pages.length-1;p>=0;--p) {
5538
 
                        var cal = this.pages[p];
5539
 
                        cal.previousMonth();
5540
 
                }
5541
 
        },
5542
 
        
5543
 
        /**
5544
 
        * Navigates to the next year in the currently selected month in the calendar widget.
5545
 
        * @method nextYear
5546
 
        */
5547
 
        nextYear : function() {
5548
 
                for (var p=0;p<this.pages.length;++p) {
5549
 
                        var cal = this.pages[p];
5550
 
                        cal.nextYear();
5551
 
                }
5552
 
        },
5553
 
 
5554
 
        /**
5555
 
        * Navigates to the previous year in the currently selected month in the calendar widget.
5556
 
        * @method previousYear
5557
 
        */
5558
 
        previousYear : function() {
5559
 
                for (var p=0;p<this.pages.length;++p) {
5560
 
                        var cal = this.pages[p];
5561
 
                        cal.previousYear();
5562
 
                }
5563
 
        },
5564
 
 
5565
 
        /**
5566
 
        * Gets the list of currently selected dates from the calendar.
5567
 
        * @return                       An array of currently selected JavaScript Date objects.
5568
 
        * @type Date[]
5569
 
        */
5570
 
        getSelectedDates : function() { 
5571
 
                var returnDates = [];
5572
 
                var selected = this.cfg.getProperty(DEF_CFG.SELECTED.key);
5573
 
                for (var d=0;d<selected.length;++d) {
5574
 
                        var dateArray = selected[d];
5575
 
 
5576
 
                        var date = DateMath.getDate(dateArray[0],dateArray[1]-1,dateArray[2]);
5577
 
                        returnDates.push(date);
5578
 
                }
5579
 
 
5580
 
                returnDates.sort( function(a,b) { return a-b; } );
5581
 
                return returnDates;
5582
 
        },
5583
 
 
5584
 
        /**
5585
 
        * Adds a renderer to the render stack. The function reference passed to this method will be executed
5586
 
        * when a date cell matches the conditions specified in the date string for this renderer.
5587
 
        * @method addRenderer
5588
 
        * @param        {String}        sDates          A date string to associate with the specified renderer. Valid formats
5589
 
        *                                                                       include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
5590
 
        * @param        {Function}      fnRender        The function executed to render cells that match the render rules for this renderer.
5591
 
        */
5592
 
        addRenderer : function(sDates, fnRender) {
5593
 
                for (var p=0;p<this.pages.length;++p) {
5594
 
                        var cal = this.pages[p];
5595
 
                        cal.addRenderer(sDates, fnRender);
5596
 
                }
5597
 
        },
5598
 
 
5599
 
        /**
5600
 
        * Adds a month to the render stack. The function reference passed to this method will be executed
5601
 
        * when a date cell matches the month passed to this method.
5602
 
        * @method addMonthRenderer
5603
 
        * @param        {Number}        month           The month (1-12) to associate with this renderer
5604
 
        * @param        {Function}      fnRender        The function executed to render cells that match the render rules for this renderer.
5605
 
        */
5606
 
        addMonthRenderer : function(month, fnRender) {
5607
 
                for (var p=0;p<this.pages.length;++p) {
5608
 
                        var cal = this.pages[p];
5609
 
                        cal.addMonthRenderer(month, fnRender);
5610
 
                }
5611
 
        },
5612
 
 
5613
 
        /**
5614
 
        * Adds a weekday to the render stack. The function reference passed to this method will be executed
5615
 
        * when a date cell matches the weekday passed to this method.
5616
 
        * @method addWeekdayRenderer
5617
 
        * @param        {Number}        weekday         The weekday (1-7) to associate with this renderer. 1=Sunday, 2=Monday etc.
5618
 
        * @param        {Function}      fnRender        The function executed to render cells that match the render rules for this renderer.
5619
 
        */
5620
 
        addWeekdayRenderer : function(weekday, fnRender) {
5621
 
                for (var p=0;p<this.pages.length;++p) {
5622
 
                        var cal = this.pages[p];
5623
 
                        cal.addWeekdayRenderer(weekday, fnRender);
5624
 
                }
5625
 
        },
5626
 
 
5627
 
        /**
5628
 
         * Removes all custom renderers added to the CalendarGroup through the addRenderer, addMonthRenderer and 
5629
 
         * addWeekRenderer methods. CalendarGroup's render method needs to be called to after removing renderers 
5630
 
         * to see the changes applied.
5631
 
         * 
5632
 
         * @method removeRenderers
5633
 
         */
5634
 
        removeRenderers : function() {
5635
 
                this.callChildFunction("removeRenderers");
5636
 
        },
5637
 
 
5638
 
        /**
5639
 
        * Renders the header for the CalendarGroup.
5640
 
        * @method renderHeader
5641
 
        */
5642
 
        renderHeader : function() {
5643
 
                // EMPTY DEFAULT IMPL
5644
 
        },
5645
 
 
5646
 
        /**
5647
 
        * Renders a footer for the 2-up calendar container. By default, this method is
5648
 
        * unimplemented.
5649
 
        * @method renderFooter
5650
 
        */
5651
 
        renderFooter : function() {
5652
 
                // EMPTY DEFAULT IMPL
5653
 
        },
5654
 
 
5655
 
        /**
5656
 
        * Adds the designated number of months to the current calendar month, and sets the current
5657
 
        * calendar page date to the new month.
5658
 
        * @method addMonths
5659
 
        * @param {Number}       count   The number of months to add to the current calendar
5660
 
        */
5661
 
        addMonths : function(count) {
5662
 
                this.callChildFunction("addMonths", count);
5663
 
        },
5664
 
        
5665
 
        /**
5666
 
        * Subtracts the designated number of months from the current calendar month, and sets the current
5667
 
        * calendar page date to the new month.
5668
 
        * @method subtractMonths
5669
 
        * @param {Number}       count   The number of months to subtract from the current calendar
5670
 
        */
5671
 
        subtractMonths : function(count) {
5672
 
                this.callChildFunction("subtractMonths", count);
5673
 
        },
5674
 
 
5675
 
        /**
5676
 
        * Adds the designated number of years to the current calendar, and sets the current
5677
 
        * calendar page date to the new month.
5678
 
        * @method addYears
5679
 
        * @param {Number}       count   The number of years to add to the current calendar
5680
 
        */
5681
 
        addYears : function(count) {
5682
 
                this.callChildFunction("addYears", count);
5683
 
        },
5684
 
 
5685
 
        /**
5686
 
        * Subtcats the designated number of years from the current calendar, and sets the current
5687
 
        * calendar page date to the new month.
5688
 
        * @method subtractYears
5689
 
        * @param {Number}       count   The number of years to subtract from the current calendar
5690
 
        */
5691
 
        subtractYears : function(count) {
5692
 
                this.callChildFunction("subtractYears", count);
5693
 
        },
5694
 
 
5695
 
        /**
5696
 
         * Returns the Calendar page instance which has a pagedate (month/year) matching the given date. 
5697
 
         * Returns null if no match is found.
5698
 
         * 
5699
 
         * @method getCalendarPage
5700
 
         * @param {Date} date The JavaScript Date object for which a Calendar page is to be found.
5701
 
         * @return {Calendar} The Calendar page instance representing the month to which the date 
5702
 
         * belongs.
5703
 
         */
5704
 
        getCalendarPage : function(date) {
5705
 
                var cal = null;
5706
 
                if (date) {
5707
 
                        var y = date.getFullYear(),
5708
 
                                m = date.getMonth();
5709
 
 
5710
 
                        var pages = this.pages;
5711
 
                        for (var i = 0; i < pages.length; ++i) {
5712
 
                                var pageDate = pages[i].cfg.getProperty("pagedate");
5713
 
                                if (pageDate.getFullYear() === y && pageDate.getMonth() === m) {
5714
 
                                        cal = pages[i];
5715
 
                                        break;
5716
 
                                }
5717
 
                        }
5718
 
                }
5719
 
                return cal;
5720
 
        },
5721
 
 
5722
 
        /**
5723
 
        * Sets the month on a Date object, taking into account year rollover if the month is less than 0 or greater than 11.
5724
 
        * The Date object passed in is modified. It should be cloned before passing it into this method if the original value needs to be maintained
5725
 
        * @method       _setMonthOnDate
5726
 
        * @private
5727
 
        * @param        {Date}  date    The Date object on which to set the month index
5728
 
        * @param        {Number}        iMonth  The month index to set
5729
 
        */
5730
 
        _setMonthOnDate : function(date, iMonth) {
5731
 
                // Bug in Safari 1.3, 2.0 (WebKit build < 420), Date.setMonth does not work consistently if iMonth is not 0-11
5732
 
                if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420 && (iMonth < 0 || iMonth > 11)) {
5733
 
                        var newDate = DateMath.add(date, DateMath.MONTH, iMonth-date.getMonth());
5734
 
                        date.setTime(newDate.getTime());
5735
 
                } else {
5736
 
                        date.setMonth(iMonth);
5737
 
                }
5738
 
        },
5739
 
        
5740
 
        /**
5741
 
         * Fixes the width of the CalendarGroup container element, to account for miswrapped floats
5742
 
         * @method _fixWidth
5743
 
         * @private
5744
 
         */
5745
 
        _fixWidth : function() {
5746
 
                var w = 0;
5747
 
                for (var p=0;p<this.pages.length;++p) {
5748
 
                        var cal = this.pages[p];
5749
 
                        w += cal.oDomContainer.offsetWidth;
5750
 
                }
5751
 
                if (w > 0) {
5752
 
                        this.oDomContainer.style.width = w + "px";
5753
 
                }
5754
 
        },
5755
 
        
5756
 
        /**
5757
 
        * Returns a string representation of the object.
5758
 
        * @method toString
5759
 
        * @return {String}      A string representation of the CalendarGroup object.
5760
 
        */
5761
 
        toString : function() {
5762
 
                return "CalendarGroup " + this.id;
5763
 
        },
5764
 
 
5765
 
        /**
5766
 
         * Destroys the CalendarGroup instance. The method will remove references
5767
 
         * to HTML elements, remove any event listeners added by the CalendarGroup.
5768
 
         * 
5769
 
         * It will also destroy the Config and CalendarNavigator instances created by the 
5770
 
         * CalendarGroup and the individual Calendar instances created for each page.
5771
 
         *
5772
 
         * @method destroy
5773
 
         */
5774
 
        destroy : function() {
5775
 
 
5776
 
                if (this.beforeDestroyEvent.fire()) {
5777
 
 
5778
 
                        var cal = this;
5779
 
        
5780
 
                        // Child objects
5781
 
                        if (cal.navigator) {
5782
 
                                cal.navigator.destroy();
5783
 
                        }
5784
 
        
5785
 
                        if (cal.cfg) {
5786
 
                                cal.cfg.destroy();
5787
 
                        }
5788
 
        
5789
 
                        // DOM event listeners
5790
 
                        Event.purgeElement(cal.oDomContainer, true);
5791
 
        
5792
 
                        // Generated markup/DOM - Not removing the container DIV since we didn't create it.
5793
 
                        Dom.removeClass(cal.oDomContainer, CalendarGroup.CSS_CONTAINER);
5794
 
                        Dom.removeClass(cal.oDomContainer, CalendarGroup.CSS_MULTI_UP);
5795
 
                        
5796
 
                        for (var i = 0, l = cal.pages.length; i < l; i++) {
5797
 
                                cal.pages[i].destroy();
5798
 
                                cal.pages[i] = null;
5799
 
                        }
5800
 
        
5801
 
                        cal.oDomContainer.innerHTML = "";
5802
 
        
5803
 
                        // JS-to-DOM references
5804
 
                        cal.oDomContainer = null;
5805
 
        
5806
 
                        this.destroyEvent.fire();
5807
 
                }
5808
 
        }
5809
 
};
5810
 
 
5811
 
/**
5812
 
* CSS class representing the container for the calendar
5813
 
* @property YAHOO.widget.CalendarGroup.CSS_CONTAINER
5814
 
* @static
5815
 
* @final
5816
 
* @type String
5817
 
*/
5818
 
CalendarGroup.CSS_CONTAINER = "yui-calcontainer";
5819
 
 
5820
 
/**
5821
 
* CSS class representing the container for the calendar
5822
 
* @property YAHOO.widget.CalendarGroup.CSS_MULTI_UP
5823
 
* @static
5824
 
* @final
5825
 
* @type String
5826
 
*/
5827
 
CalendarGroup.CSS_MULTI_UP = "multi";
5828
 
 
5829
 
/**
5830
 
* CSS class representing the title for the 2-up calendar
5831
 
* @property YAHOO.widget.CalendarGroup.CSS_2UPTITLE
5832
 
* @static
5833
 
* @final
5834
 
* @type String
5835
 
*/
5836
 
CalendarGroup.CSS_2UPTITLE = "title";
5837
 
 
5838
 
/**
5839
 
* CSS class representing the close icon for the 2-up calendar
5840
 
* @property YAHOO.widget.CalendarGroup.CSS_2UPCLOSE
5841
 
* @static
5842
 
* @final
5843
 
* @deprecated   Along with Calendar.IMG_ROOT and NAV_ARROW_LEFT, NAV_ARROW_RIGHT configuration properties.
5844
 
*                                       Calendar's <a href="YAHOO.widget.Calendar.html#Style.CSS_CLOSE">Style.CSS_CLOSE</a> property now represents the CSS class used to render the close icon
5845
 
* @type String
5846
 
*/
5847
 
CalendarGroup.CSS_2UPCLOSE = "close-icon";
5848
 
 
5849
 
YAHOO.lang.augmentProto(CalendarGroup, Calendar, "buildDayLabel",
5850
 
                                                                                                 "buildMonthLabel",
5851
 
                                                                                                 "renderOutOfBoundsDate",
5852
 
                                                                                                 "renderRowHeader",
5853
 
                                                                                                 "renderRowFooter",
5854
 
                                                                                                 "renderCellDefault",
5855
 
                                                                                                 "styleCellDefault",
5856
 
                                                                                                 "renderCellStyleHighlight1",
5857
 
                                                                                                 "renderCellStyleHighlight2",
5858
 
                                                                                                 "renderCellStyleHighlight3",
5859
 
                                                                                                 "renderCellStyleHighlight4",
5860
 
                                                                                                 "renderCellStyleToday",
5861
 
                                                                                                 "renderCellStyleSelected",
5862
 
                                                                                                 "renderCellNotThisMonth",
5863
 
                                                                                                 "renderBodyCellRestricted",
5864
 
                                                                                                 "initStyles",
5865
 
                                                                                                 "configTitle",
5866
 
                                                                                                 "configClose",
5867
 
                                                                                                 "configIframe",
5868
 
                                                                                                 "configStrings",
5869
 
                                                                                                 "configNavigator",
5870
 
                                                                                                 "createTitleBar",
5871
 
                                                                                                 "createCloseButton",
5872
 
                                                                                                 "removeTitleBar",
5873
 
                                                                                                 "removeCloseButton",
5874
 
                                                                                                 "hide",
5875
 
                                                                                                 "show",
5876
 
                                                                                                 "toDate",
5877
 
                                                                                                 "_toDate",
5878
 
                                                                                                 "_parseArgs",
5879
 
                                                                                                 "browser");
5880
 
 
5881
 
YAHOO.widget.CalGrp = CalendarGroup;
5882
 
YAHOO.widget.CalendarGroup = CalendarGroup;
5883
 
 
5884
 
/**
5885
 
* @class YAHOO.widget.Calendar2up
5886
 
* @extends YAHOO.widget.CalendarGroup
5887
 
* @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
5888
 
*/
5889
 
YAHOO.widget.Calendar2up = function(id, containerId, config) {
5890
 
        this.init(id, containerId, config);
5891
 
};
5892
 
 
5893
 
YAHOO.extend(YAHOO.widget.Calendar2up, CalendarGroup);
5894
 
 
5895
 
/**
5896
 
* @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
5897
 
*/
5898
 
YAHOO.widget.Cal2up = YAHOO.widget.Calendar2up;
5899
 
 
5900
 
})();
5901
 
 
5902
 
/**
5903
 
 * The CalendarNavigator is used along with a Calendar/CalendarGroup to 
5904
 
 * provide a Month/Year popup navigation control, allowing the user to navigate 
5905
 
 * to a specific month/year in the Calendar/CalendarGroup without having to 
5906
 
 * scroll through months sequentially
5907
 
 *
5908
 
 * @namespace YAHOO.widget
5909
 
 * @class CalendarNavigator
5910
 
 * @constructor
5911
 
 * @param {Calendar|CalendarGroup} cal The instance of the Calendar or CalendarGroup to which this CalendarNavigator should be attached.
5912
 
 */
5913
 
YAHOO.widget.CalendarNavigator = function(cal) {
5914
 
        this.init(cal);
5915
 
};
5916
 
 
5917
 
(function() {
5918
 
        // Setup static properties (inside anon fn, so that we can use shortcuts)
5919
 
        var CN = YAHOO.widget.CalendarNavigator;
5920
 
 
5921
 
        /**
5922
 
         * YAHOO.widget.CalendarNavigator.CLASSES contains constants
5923
 
         * for the class values applied to the CalendarNaviatgator's 
5924
 
         * DOM elements
5925
 
         * @property YAHOO.widget.CalendarNavigator.CLASSES
5926
 
         * @type Object
5927
 
         * @static
5928
 
         */
5929
 
        CN.CLASSES = {
5930
 
                /**
5931
 
                 * Class applied to the Calendar Navigator's bounding box
5932
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.NAV
5933
 
                 * @type String
5934
 
                 * @static
5935
 
                 */
5936
 
                NAV :"yui-cal-nav",
5937
 
                /**
5938
 
                 * Class applied to the Calendar/CalendarGroup's bounding box to indicate
5939
 
                 * the Navigator is currently visible
5940
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.NAV_VISIBLE
5941
 
                 * @type String
5942
 
                 * @static
5943
 
                 */
5944
 
                NAV_VISIBLE: "yui-cal-nav-visible",
5945
 
                /**
5946
 
                 * Class applied to the Navigator mask's bounding box
5947
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.MASK
5948
 
                 * @type String
5949
 
                 * @static
5950
 
                 */
5951
 
                MASK : "yui-cal-nav-mask",
5952
 
                /**
5953
 
                 * Class applied to the year label/control bounding box
5954
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.YEAR
5955
 
                 * @type String
5956
 
                 * @static
5957
 
                 */
5958
 
                YEAR : "yui-cal-nav-y",
5959
 
                /**
5960
 
                 * Class applied to the month label/control bounding box
5961
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.MONTH
5962
 
                 * @type String
5963
 
                 * @static
5964
 
                 */
5965
 
                MONTH : "yui-cal-nav-m",
5966
 
                /**
5967
 
                 * Class applied to the submit/cancel button's bounding box
5968
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.BUTTONS
5969
 
                 * @type String
5970
 
                 * @static
5971
 
                 */
5972
 
                BUTTONS : "yui-cal-nav-b",
5973
 
                /**
5974
 
                 * Class applied to buttons wrapping element
5975
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.BUTTON
5976
 
                 * @type String
5977
 
                 * @static
5978
 
                 */
5979
 
                BUTTON : "yui-cal-nav-btn",
5980
 
                /**
5981
 
                 * Class applied to the validation error area's bounding box
5982
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.ERROR
5983
 
                 * @type String
5984
 
                 * @static
5985
 
                 */
5986
 
                ERROR : "yui-cal-nav-e",
5987
 
                /**
5988
 
                 * Class applied to the year input control
5989
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.YEAR_CTRL
5990
 
                 * @type String
5991
 
                 * @static
5992
 
                 */
5993
 
                YEAR_CTRL : "yui-cal-nav-yc",
5994
 
                /**
5995
 
                 * Class applied to the month input control
5996
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.MONTH_CTRL
5997
 
                 * @type String
5998
 
                 * @static
5999
 
                 */
6000
 
                MONTH_CTRL : "yui-cal-nav-mc",
6001
 
                /**
6002
 
                 * Class applied to controls with invalid data (e.g. a year input field with invalid an year)
6003
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.INVALID
6004
 
                 * @type String
6005
 
                 * @static
6006
 
                 */
6007
 
                INVALID : "yui-invalid",
6008
 
                /**
6009
 
                 * Class applied to default controls
6010
 
                 * @property YAHOO.widget.CalendarNavigator.CLASSES.DEFAULT
6011
 
                 * @type String
6012
 
                 * @static
6013
 
                 */
6014
 
                DEFAULT : "yui-default"
6015
 
        };
6016
 
 
6017
 
        /**
6018
 
         * Object literal containing the default configuration values for the CalendarNavigator
6019
 
         * The configuration object is expected to follow the format below, with the properties being
6020
 
         * case sensitive.
6021
 
         * <dl>
6022
 
         * <dt>strings</dt>
6023
 
         * <dd><em>Object</em> :  An object with the properties shown below, defining the string labels to use in the Navigator's UI
6024
 
         *     <dl>
6025
 
         *         <dt>month</dt><dd><em>String</em> : The string to use for the month label. Defaults to "Month".</dd>
6026
 
         *         <dt>year</dt><dd><em>String</em> : The string to use for the year label. Defaults to "Year".</dd>
6027
 
         *         <dt>submit</dt><dd><em>String</em> : The string to use for the submit button label. Defaults to "Okay".</dd>
6028
 
         *         <dt>cancel</dt><dd><em>String</em> : The string to use for the cancel button label. Defaults to "Cancel".</dd>
6029
 
         *         <dt>invalidYear</dt><dd><em>String</em> : The string to use for invalid year values. Defaults to "Year needs to be a number".</dd>
6030
 
         *     </dl>
6031
 
         * </dd>
6032
 
         * <dt>monthFormat</dt><dd><em>String</em> : The month format to use. Either YAHOO.widget.Calendar.LONG, or YAHOO.widget.Calendar.SHORT. Defaults to YAHOO.widget.Calendar.LONG</dd>
6033
 
         * <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
6034
 
         * </dl>
6035
 
         * @property _DEFAULT_CFG
6036
 
         * @protected
6037
 
         * @type Object
6038
 
         * @static
6039
 
         */
6040
 
        CN._DEFAULT_CFG = {
6041
 
                strings : {
6042
 
                        month: "Month",
6043
 
                        year: "Year",
6044
 
                        submit: "Okay",
6045
 
                        cancel: "Cancel",
6046
 
                        invalidYear : "Year needs to be a number"
6047
 
                },
6048
 
                monthFormat: YAHOO.widget.Calendar.LONG,
6049
 
                initialFocus: "year"
6050
 
        };
6051
 
 
6052
 
        /**
6053
 
         * The suffix added to the Calendar/CalendarGroup's ID, to generate
6054
 
         * a unique ID for the Navigator and it's bounding box.
6055
 
         * @property YAHOO.widget.CalendarNavigator.ID_SUFFIX
6056
 
         * @static
6057
 
         * @type String
6058
 
         * @final
6059
 
         */
6060
 
        CN.ID_SUFFIX = "_nav";
6061
 
        /**
6062
 
         * The suffix added to the Navigator's ID, to generate
6063
 
         * a unique ID for the month control.
6064
 
         * @property YAHOO.widget.CalendarNavigator.MONTH_SUFFIX
6065
 
         * @static
6066
 
         * @type String 
6067
 
         * @final
6068
 
         */
6069
 
        CN.MONTH_SUFFIX = "_month";
6070
 
        /**
6071
 
         * The suffix added to the Navigator's ID, to generate
6072
 
         * a unique ID for the year control.
6073
 
         * @property YAHOO.widget.CalendarNavigator.YEAR_SUFFIX
6074
 
         * @static
6075
 
         * @type String
6076
 
         * @final
6077
 
         */
6078
 
        CN.YEAR_SUFFIX = "_year";
6079
 
        /**
6080
 
         * The suffix added to the Navigator's ID, to generate
6081
 
         * a unique ID for the error bounding box.
6082
 
         * @property YAHOO.widget.CalendarNavigator.ERROR_SUFFIX
6083
 
         * @static
6084
 
         * @type String
6085
 
         * @final
6086
 
         */
6087
 
        CN.ERROR_SUFFIX = "_error";
6088
 
        /**
6089
 
         * The suffix added to the Navigator's ID, to generate
6090
 
         * a unique ID for the "Cancel" button.
6091
 
         * @property YAHOO.widget.CalendarNavigator.CANCEL_SUFFIX
6092
 
         * @static
6093
 
         * @type String
6094
 
         * @final
6095
 
         */
6096
 
        CN.CANCEL_SUFFIX = "_cancel";
6097
 
        /**
6098
 
         * The suffix added to the Navigator's ID, to generate
6099
 
         * a unique ID for the "Submit" button.
6100
 
         * @property YAHOO.widget.CalendarNavigator.SUBMIT_SUFFIX
6101
 
         * @static
6102
 
         * @type String
6103
 
         * @final
6104
 
         */
6105
 
        CN.SUBMIT_SUFFIX = "_submit";
6106
 
 
6107
 
        /**
6108
 
         * The number of digits to which the year input control is to be limited.
6109
 
         * @property YAHOO.widget.CalendarNavigator.YR_MAX_DIGITS
6110
 
         * @static
6111
 
         * @type Number
6112
 
         */
6113
 
        CN.YR_MAX_DIGITS = 4;
6114
 
 
6115
 
        /**
6116
 
         * The amount by which to increment the current year value,
6117
 
         * when the arrow up/down key is pressed on the year control
6118
 
         * @property YAHOO.widget.CalendarNavigator.YR_MINOR_INC
6119
 
         * @static
6120
 
         * @type Number
6121
 
         */
6122
 
        CN.YR_MINOR_INC = 1;
6123
 
 
6124
 
        /**
6125
 
         * The amount by which to increment the current year value,
6126
 
         * when the page up/down key is pressed on the year control
6127
 
         * @property YAHOO.widget.CalendarNavigator.YR_MAJOR_INC
6128
 
         * @static
6129
 
         * @type Number
6130
 
         */
6131
 
        CN.YR_MAJOR_INC = 10;
6132
 
 
6133
 
        /**
6134
 
         * Artificial delay (in ms) between the time the Navigator is hidden
6135
 
         * and the Calendar/CalendarGroup state is updated. Allows the user
6136
 
         * the see the Calendar/CalendarGroup page changing. If set to 0
6137
 
         * the Calendar/CalendarGroup page will be updated instantly
6138
 
         * @property YAHOO.widget.CalendarNavigator.UPDATE_DELAY
6139
 
         * @static
6140
 
         * @type Number
6141
 
         */
6142
 
        CN.UPDATE_DELAY = 50;
6143
 
 
6144
 
        /**
6145
 
         * Regular expression used to validate the year input
6146
 
         * @property YAHOO.widget.CalendarNavigator.YR_PATTERN
6147
 
         * @static
6148
 
         * @type RegExp
6149
 
         */
6150
 
        CN.YR_PATTERN = /^\d+$/;
6151
 
        /**
6152
 
         * Regular expression used to trim strings
6153
 
         * @property YAHOO.widget.CalendarNavigator.TRIM
6154
 
         * @static
6155
 
         * @type RegExp
6156
 
         */
6157
 
        CN.TRIM = /^\s*(.*?)\s*$/;
6158
 
})();
6159
 
 
6160
 
YAHOO.widget.CalendarNavigator.prototype = {
6161
 
 
6162
 
        /**
6163
 
         * The unique ID for this CalendarNavigator instance
6164
 
         * @property id
6165
 
         * @type String
6166
 
         */
6167
 
        id : null,
6168
 
 
6169
 
        /**
6170
 
         * The Calendar/CalendarGroup instance to which the navigator belongs
6171
 
         * @property cal
6172
 
         * @type {Calendar|CalendarGroup}
6173
 
         */
6174
 
        cal : null,
6175
 
 
6176
 
        /**
6177
 
         * Reference to the HTMLElement used to render the navigator's bounding box
6178
 
         * @property navEl
6179
 
         * @type HTMLElement
6180
 
         */
6181
 
        navEl : null,
6182
 
 
6183
 
        /**
6184
 
         * Reference to the HTMLElement used to render the navigator's mask
6185
 
         * @property maskEl
6186
 
         * @type HTMLElement
6187
 
         */
6188
 
        maskEl : null,
6189
 
 
6190
 
        /**
6191
 
         * Reference to the HTMLElement used to input the year
6192
 
         * @property yearEl
6193
 
         * @type HTMLElement
6194
 
         */
6195
 
        yearEl : null,
6196
 
 
6197
 
        /**
6198
 
         * Reference to the HTMLElement used to input the month
6199
 
         * @property monthEl
6200
 
         * @type HTMLElement
6201
 
         */
6202
 
        monthEl : null,
6203
 
 
6204
 
        /**
6205
 
         * Reference to the HTMLElement used to display validation errors
6206
 
         * @property errorEl
6207
 
         * @type HTMLElement
6208
 
         */
6209
 
        errorEl : null,
6210
 
 
6211
 
        /**
6212
 
         * Reference to the HTMLElement used to update the Calendar/Calendar group
6213
 
         * with the month/year values
6214
 
         * @property submitEl
6215
 
         * @type HTMLElement
6216
 
         */
6217
 
        submitEl : null,
6218
 
        
6219
 
        /**
6220
 
         * Reference to the HTMLElement used to hide the navigator without updating the 
6221
 
         * Calendar/Calendar group
6222
 
         * @property cancelEl
6223
 
         * @type HTMLElement
6224
 
         */
6225
 
        cancelEl : null,
6226
 
 
6227
 
        /** 
6228
 
         * Reference to the first focusable control in the navigator (by default monthEl)
6229
 
         * @property firstCtrl
6230
 
         * @type HTMLElement
6231
 
         */
6232
 
        firstCtrl : null,
6233
 
        
6234
 
        /** 
6235
 
         * Reference to the last focusable control in the navigator (by default cancelEl)
6236
 
         * @property lastCtrl
6237
 
         * @type HTMLElement
6238
 
         */
6239
 
        lastCtrl : null,
6240
 
 
6241
 
        /**
6242
 
         * The document containing the Calendar/Calendar group instance
6243
 
         * @protected
6244
 
         * @property _doc
6245
 
         * @type HTMLDocument
6246
 
         */
6247
 
        _doc : null,
6248
 
 
6249
 
        /**
6250
 
         * Internal state property for the current year displayed in the navigator
6251
 
         * @protected
6252
 
         * @property _year
6253
 
         * @type Number
6254
 
         */
6255
 
        _year: null,
6256
 
        
6257
 
        /**
6258
 
         * Internal state property for the current month index displayed in the navigator
6259
 
         * @protected
6260
 
         * @property _month
6261
 
         * @type Number
6262
 
         */
6263
 
        _month: 0,
6264
 
 
6265
 
        /**
6266
 
         * Private internal state property which indicates whether or not the 
6267
 
         * Navigator has been rendered.
6268
 
         * @private
6269
 
         * @property __rendered
6270
 
         * @type Boolean
6271
 
         */
6272
 
        __rendered: false,
6273
 
 
6274
 
        /**
6275
 
         * Init lifecycle method called as part of construction
6276
 
         * 
6277
 
         * @method init
6278
 
         * @param {Calendar} cal The instance of the Calendar or CalendarGroup to which this CalendarNavigator should be attached
6279
 
         */
6280
 
        init : function(cal) {
6281
 
                var calBox = cal.oDomContainer;
6282
 
 
6283
 
                this.cal = cal;
6284
 
                this.id = calBox.id + YAHOO.widget.CalendarNavigator.ID_SUFFIX;
6285
 
                this._doc = calBox.ownerDocument;
6286
 
 
6287
 
                /**
6288
 
                 * Private flag, to identify IE Quirks
6289
 
                 * @private
6290
 
                 * @property __isIEQuirks
6291
 
                 */
6292
 
                var ie = YAHOO.env.ua.ie;
6293
 
                this.__isIEQuirks = (ie && ((ie <= 6) || (this._doc.compatMode == "BackCompat")));
6294
 
        },
6295
 
 
6296
 
        /**
6297
 
         * Displays the navigator and mask, updating the input controls to reflect the 
6298
 
         * currently set month and year. The show method will invoke the render method
6299
 
         * if the navigator has not been renderered already, allowing for lazy rendering
6300
 
         * of the control.
6301
 
         * 
6302
 
         * The show method will fire the Calendar/CalendarGroup's beforeShowNav and showNav events
6303
 
         * 
6304
 
         * @method show
6305
 
         */
6306
 
        show : function() {
6307
 
                var CLASSES = YAHOO.widget.CalendarNavigator.CLASSES;
6308
 
 
6309
 
                if (this.cal.beforeShowNavEvent.fire()) {
6310
 
                        if (!this.__rendered) {
6311
 
                                this.render();
6312
 
                        }
6313
 
                        this.clearErrors();
6314
 
 
6315
 
                        this._updateMonthUI();
6316
 
                        this._updateYearUI();
6317
 
                        this._show(this.navEl, true);
6318
 
 
6319
 
                        this.setInitialFocus();
6320
 
                        this.showMask();
6321
 
 
6322
 
                        YAHOO.util.Dom.addClass(this.cal.oDomContainer, CLASSES.NAV_VISIBLE);
6323
 
                        this.cal.showNavEvent.fire();
6324
 
                }
6325
 
        },
6326
 
 
6327
 
        /**
6328
 
         * Hides the navigator and mask
6329
 
         * 
6330
 
         * The show method will fire the Calendar/CalendarGroup's beforeHideNav event and hideNav events
6331
 
         * @method hide
6332
 
         */
6333
 
        hide : function() {
6334
 
                var CLASSES = YAHOO.widget.CalendarNavigator.CLASSES;
6335
 
 
6336
 
                if (this.cal.beforeHideNavEvent.fire()) {
6337
 
                        this._show(this.navEl, false);
6338
 
                        this.hideMask();
6339
 
                        YAHOO.util.Dom.removeClass(this.cal.oDomContainer, CLASSES.NAV_VISIBLE);
6340
 
                        this.cal.hideNavEvent.fire();
6341
 
                }
6342
 
        },
6343
 
        
6344
 
 
6345
 
        /**
6346
 
         * Displays the navigator's mask element
6347
 
         * 
6348
 
         * @method showMask
6349
 
         */
6350
 
        showMask : function() {
6351
 
                this._show(this.maskEl, true);
6352
 
                if (this.__isIEQuirks) {
6353
 
                        this._syncMask();
6354
 
                }
6355
 
        },
6356
 
 
6357
 
        /**
6358
 
         * Hides the navigator's mask element
6359
 
         * 
6360
 
         * @method hideMask
6361
 
         */
6362
 
        hideMask : function() {
6363
 
                this._show(this.maskEl, false);
6364
 
        },
6365
 
 
6366
 
        /**
6367
 
         * Returns the current month set on the navigator
6368
 
         * 
6369
 
         * Note: This may not be the month set in the UI, if 
6370
 
         * the UI contains an invalid value.
6371
 
         * 
6372
 
         * @method getMonth
6373
 
         * @return {Number} The Navigator's current month index
6374
 
         */
6375
 
        getMonth: function() {
6376
 
                return this._month;
6377
 
        },
6378
 
 
6379
 
        /**
6380
 
         * Returns the current year set on the navigator
6381
 
         * 
6382
 
         * Note: This may not be the year set in the UI, if 
6383
 
         * the UI contains an invalid value.
6384
 
         * 
6385
 
         * @method getYear
6386
 
         * @return {Number} The Navigator's current year value
6387
 
         */
6388
 
        getYear: function() {
6389
 
                return this._year;
6390
 
        },
6391
 
 
6392
 
        /**
6393
 
         * Sets the current month on the Navigator, and updates the UI
6394
 
         * 
6395
 
         * @method setMonth
6396
 
         * @param {Number} nMonth The month index, from 0 (Jan) through 11 (Dec).
6397
 
         */
6398
 
        setMonth : function(nMonth) {
6399
 
                if (nMonth >= 0 && nMonth < 12) {
6400
 
                        this._month = nMonth;
6401
 
                }
6402
 
                this._updateMonthUI();
6403
 
        },
6404
 
 
6405
 
        /**
6406
 
         * Sets the current year on the Navigator, and updates the UI. If the 
6407
 
         * provided year is invalid, it will not be set.
6408
 
         * 
6409
 
         * @method setYear
6410
 
         * @param {Number} nYear The full year value to set the Navigator to.
6411
 
         */
6412
 
        setYear : function(nYear) {
6413
 
                var yrPattern = YAHOO.widget.CalendarNavigator.YR_PATTERN;
6414
 
                if (YAHOO.lang.isNumber(nYear) && yrPattern.test(nYear+"")) {
6415
 
                        this._year = nYear;
6416
 
                }
6417
 
                this._updateYearUI();
6418
 
        },
6419
 
 
6420
 
        /**
6421
 
         * Renders the HTML for the navigator, adding it to the 
6422
 
         * document and attaches event listeners if it has not 
6423
 
         * already been rendered.
6424
 
         * 
6425
 
         * @method render
6426
 
         */
6427
 
        render: function() {
6428
 
                this.cal.beforeRenderNavEvent.fire();
6429
 
                if (!this.__rendered) {
6430
 
                        this.createNav();
6431
 
                        this.createMask();
6432
 
                        this.applyListeners();
6433
 
                        this.__rendered = true;
6434
 
                }
6435
 
                this.cal.renderNavEvent.fire();
6436
 
        },
6437
 
 
6438
 
        /**
6439
 
         * Creates the navigator's containing HTMLElement, it's contents, and appends 
6440
 
         * the containg element to the Calendar/CalendarGroup's container.
6441
 
         * 
6442
 
         * @method createNav
6443
 
         */
6444
 
        createNav : function() {
6445
 
                var NAV = YAHOO.widget.CalendarNavigator;
6446
 
                var doc = this._doc;
6447
 
 
6448
 
                var d = doc.createElement("div");
6449
 
                d.className = NAV.CLASSES.NAV;
6450
 
 
6451
 
                var htmlBuf = this.renderNavContents([]);
6452
 
 
6453
 
                d.innerHTML = htmlBuf.join('');
6454
 
                this.cal.oDomContainer.appendChild(d);
6455
 
 
6456
 
                this.navEl = d;
6457
 
 
6458
 
                this.yearEl = doc.getElementById(this.id + NAV.YEAR_SUFFIX);
6459
 
                this.monthEl = doc.getElementById(this.id + NAV.MONTH_SUFFIX);
6460
 
                this.errorEl = doc.getElementById(this.id + NAV.ERROR_SUFFIX);
6461
 
                this.submitEl = doc.getElementById(this.id + NAV.SUBMIT_SUFFIX);
6462
 
                this.cancelEl = doc.getElementById(this.id + NAV.CANCEL_SUFFIX);
6463
 
 
6464
 
                if (YAHOO.env.ua.gecko && this.yearEl && this.yearEl.type == "text") {
6465
 
                        // Avoid XUL error on focus, select [ https://bugzilla.mozilla.org/show_bug.cgi?id=236791, 
6466
 
                        // supposedly fixed in 1.8.1, but there are reports of it still being around for methods other than blur ]
6467
 
                        this.yearEl.setAttribute("autocomplete", "off");
6468
 
                }
6469
 
 
6470
 
                this._setFirstLastElements();
6471
 
        },
6472
 
 
6473
 
        /**
6474
 
         * Creates the Mask HTMLElement and appends it to the Calendar/CalendarGroups
6475
 
         * container.
6476
 
         * 
6477
 
         * @method createMask
6478
 
         */
6479
 
        createMask : function() {
6480
 
                var C = YAHOO.widget.CalendarNavigator.CLASSES;
6481
 
 
6482
 
                var d = this._doc.createElement("div");
6483
 
                d.className = C.MASK;
6484
 
 
6485
 
                this.cal.oDomContainer.appendChild(d);
6486
 
                this.maskEl = d;
6487
 
        },
6488
 
 
6489
 
        /**
6490
 
         * Used to set the width/height of the mask in pixels to match the Calendar Container.
6491
 
         * Currently only used for IE6 or IE in quirks mode. The other A-Grade browser are handled using CSS (width/height 100%).
6492
 
         * <p>
6493
 
         * The method is also registered as an HTMLElement resize listener on the Calendars container element.
6494
 
         * </p>
6495
 
         * @protected
6496
 
         * @method _syncMask
6497
 
         */
6498
 
        _syncMask : function() {
6499
 
                var c = this.cal.oDomContainer;
6500
 
                if (c && this.maskEl) {
6501
 
                        var r = YAHOO.util.Dom.getRegion(c);
6502
 
                        YAHOO.util.Dom.setStyle(this.maskEl, "width", r.right - r.left + "px");
6503
 
                        YAHOO.util.Dom.setStyle(this.maskEl, "height", r.bottom - r.top + "px");
6504
 
                }
6505
 
        },
6506
 
 
6507
 
        /**
6508
 
         * Renders the contents of the navigator
6509
 
         * 
6510
 
         * @method renderNavContents
6511
 
         * 
6512
 
         * @param {Array} html The HTML buffer to append the HTML to.
6513
 
         * @return {Array} A reference to the buffer passed in.
6514
 
         */
6515
 
        renderNavContents : function(html) {
6516
 
                var NAV = YAHOO.widget.CalendarNavigator,
6517
 
                        C = NAV.CLASSES,
6518
 
                        h = html; // just to use a shorter name
6519
 
 
6520
 
                h[h.length] = '<div class="' + C.MONTH + '">';
6521
 
                this.renderMonth(h);
6522
 
                h[h.length] = '</div>';
6523
 
                h[h.length] = '<div class="' + C.YEAR + '">';
6524
 
                this.renderYear(h);
6525
 
                h[h.length] = '</div>';
6526
 
                h[h.length] = '<div class="' + C.BUTTONS + '">';
6527
 
                this.renderButtons(h);
6528
 
                h[h.length] = '</div>';
6529
 
                h[h.length] = '<div class="' + C.ERROR + '" id="' + this.id + NAV.ERROR_SUFFIX + '"></div>';
6530
 
 
6531
 
                return h;
6532
 
        },
6533
 
 
6534
 
        /**
6535
 
         * Renders the month label and control for the navigator
6536
 
         * 
6537
 
         * @method renderNavContents
6538
 
         * @param {Array} html The HTML buffer to append the HTML to.
6539
 
         * @return {Array} A reference to the buffer passed in.
6540
 
         */
6541
 
        renderMonth : function(html) {
6542
 
                var NAV = YAHOO.widget.CalendarNavigator,
6543
 
                        C = NAV.CLASSES;
6544
 
 
6545
 
                var id = this.id + NAV.MONTH_SUFFIX,
6546
 
                        mf = this.__getCfg("monthFormat"),
6547
 
                        months = this.cal.cfg.getProperty((mf == YAHOO.widget.Calendar.SHORT) ? "MONTHS_SHORT" : "MONTHS_LONG"),
6548
 
                        h = html;
6549
 
 
6550
 
                if (months && months.length > 0) {
6551
 
                        h[h.length] = '<label for="' + id + '">';
6552
 
                        h[h.length] = this.__getCfg("month", true);
6553
 
                        h[h.length] = '</label>';
6554
 
                        h[h.length] = '<select name="' + id + '" id="' + id + '" class="' + C.MONTH_CTRL + '">';
6555
 
                        for (var i = 0; i < months.length; i++) {
6556
 
                                h[h.length] = '<option value="' + i + '">';
6557
 
                                h[h.length] = months[i];
6558
 
                                h[h.length] = '</option>';
6559
 
                        }
6560
 
                        h[h.length] = '</select>';
6561
 
                }
6562
 
                return h;
6563
 
        },
6564
 
 
6565
 
        /**
6566
 
         * Renders the year label and control for the navigator
6567
 
         * 
6568
 
         * @method renderYear
6569
 
         * @param {Array} html The HTML buffer to append the HTML to.
6570
 
         * @return {Array} A reference to the buffer passed in.
6571
 
         */
6572
 
        renderYear : function(html) {
6573
 
                var NAV = YAHOO.widget.CalendarNavigator,
6574
 
                        C = NAV.CLASSES;
6575
 
 
6576
 
                var id = this.id + NAV.YEAR_SUFFIX,
6577
 
                        size = NAV.YR_MAX_DIGITS,
6578
 
                        h = html;
6579
 
 
6580
 
                h[h.length] = '<label for="' + id + '">';
6581
 
                h[h.length] = this.__getCfg("year", true);
6582
 
                h[h.length] = '</label>';
6583
 
                h[h.length] = '<input type="text" name="' + id + '" id="' + id + '" class="' + C.YEAR_CTRL + '" maxlength="' + size + '"/>';
6584
 
                return h;
6585
 
        },
6586
 
 
6587
 
        /**
6588
 
         * Renders the submit/cancel buttons for the navigator
6589
 
         * 
6590
 
         * @method renderButton
6591
 
         * @return {String} The HTML created for the Button UI
6592
 
         */
6593
 
        renderButtons : function(html) {
6594
 
                var C = YAHOO.widget.CalendarNavigator.CLASSES;
6595
 
                var h = html;
6596
 
 
6597
 
                h[h.length] = '<span class="' + C.BUTTON + ' ' + C.DEFAULT + '">';
6598
 
                h[h.length] = '<button type="button" id="' + this.id + '_submit' + '">';
6599
 
                h[h.length] = this.__getCfg("submit", true);
6600
 
                h[h.length] = '</button>';
6601
 
                h[h.length] = '</span>';
6602
 
                h[h.length] = '<span class="' + C.BUTTON +'">';
6603
 
                h[h.length] = '<button type="button" id="' + this.id + '_cancel' + '">';
6604
 
                h[h.length] = this.__getCfg("cancel", true);
6605
 
                h[h.length] = '</button>';
6606
 
                h[h.length] = '</span>';
6607
 
 
6608
 
                return h;
6609
 
        },
6610
 
 
6611
 
        /**
6612
 
         * Attaches DOM event listeners to the rendered elements
6613
 
         * <p>
6614
 
         * The method will call applyKeyListeners, to setup keyboard specific 
6615
 
         * listeners
6616
 
         * </p>
6617
 
         * @method applyListeners
6618
 
         */
6619
 
        applyListeners : function() {
6620
 
                var E = YAHOO.util.Event;
6621
 
 
6622
 
                function yearUpdateHandler() {
6623
 
                        if (this.validate()) {
6624
 
                                this.setYear(this._getYearFromUI());
6625
 
                        }
6626
 
                }
6627
 
 
6628
 
                function monthUpdateHandler() {
6629
 
                        this.setMonth(this._getMonthFromUI());
6630
 
                }
6631
 
 
6632
 
                E.on(this.submitEl, "click", this.submit, this, true);
6633
 
                E.on(this.cancelEl, "click", this.cancel, this, true);
6634
 
                E.on(this.yearEl, "blur", yearUpdateHandler, this, true);
6635
 
                E.on(this.monthEl, "change", monthUpdateHandler, this, true);
6636
 
 
6637
 
                if (this.__isIEQuirks) {
6638
 
                        YAHOO.util.Event.on(this.cal.oDomContainer, "resize", this._syncMask, this, true);
6639
 
                }
6640
 
 
6641
 
                this.applyKeyListeners();
6642
 
        },
6643
 
 
6644
 
        /**
6645
 
         * Removes/purges DOM event listeners from the rendered elements
6646
 
         * 
6647
 
         * @method purgeListeners
6648
 
         */
6649
 
        purgeListeners : function() {
6650
 
                var E = YAHOO.util.Event;
6651
 
                E.removeListener(this.submitEl, "click", this.submit);
6652
 
                E.removeListener(this.cancelEl, "click", this.cancel);
6653
 
                E.removeListener(this.yearEl, "blur");
6654
 
                E.removeListener(this.monthEl, "change");
6655
 
                if (this.__isIEQuirks) {
6656
 
                        E.removeListener(this.cal.oDomContainer, "resize", this._syncMask);
6657
 
                }
6658
 
 
6659
 
                this.purgeKeyListeners();
6660
 
        },
6661
 
 
6662
 
        /**
6663
 
         * Attaches DOM listeners for keyboard support. 
6664
 
         * Tab/Shift-Tab looping, Enter Key Submit on Year element,
6665
 
         * Up/Down/PgUp/PgDown year increment on Year element
6666
 
         * <p>
6667
 
         * NOTE: MacOSX Safari 2.x doesn't let you tab to buttons and 
6668
 
         * MacOSX Gecko does not let you tab to buttons or select controls,
6669
 
         * so for these browsers, Tab/Shift-Tab looping is limited to the 
6670
 
         * elements which can be reached using the tab key.
6671
 
         * </p>
6672
 
         * @method applyKeyListeners
6673
 
         */
6674
 
        applyKeyListeners : function() {
6675
 
                var E = YAHOO.util.Event,
6676
 
                        ua = YAHOO.env.ua;
6677
 
 
6678
 
                // IE/Safari 3.1 doesn't fire keypress for arrow/pg keys (non-char keys)
6679
 
                var arrowEvt = (ua.ie || ua.webkit) ? "keydown" : "keypress";
6680
 
 
6681
 
                // - IE/Safari 3.1 doesn't fire keypress for non-char keys
6682
 
                // - Opera doesn't allow us to cancel keydown or keypress for tab, but 
6683
 
                //   changes focus successfully on keydown (keypress is too late to change focus - opera's already moved on).
6684
 
                var tabEvt = (ua.ie || ua.opera || ua.webkit) ? "keydown" : "keypress";
6685
 
 
6686
 
                // Everyone likes keypress for Enter (char keys) - whoo hoo!
6687
 
                E.on(this.yearEl, "keypress", this._handleEnterKey, this, true);
6688
 
 
6689
 
                E.on(this.yearEl, arrowEvt, this._handleDirectionKeys, this, true);
6690
 
                E.on(this.lastCtrl, tabEvt, this._handleTabKey, this, true);
6691
 
                E.on(this.firstCtrl, tabEvt, this._handleShiftTabKey, this, true);
6692
 
        },
6693
 
 
6694
 
        /**
6695
 
         * Removes/purges DOM listeners for keyboard support
6696
 
         *
6697
 
         * @method purgeKeyListeners
6698
 
         */
6699
 
        purgeKeyListeners : function() {
6700
 
                var E = YAHOO.util.Event,
6701
 
                        ua = YAHOO.env.ua;
6702
 
 
6703
 
                var arrowEvt = (ua.ie || ua.webkit) ? "keydown" : "keypress";
6704
 
                var tabEvt = (ua.ie || ua.opera || ua.webkit) ? "keydown" : "keypress";
6705
 
 
6706
 
                E.removeListener(this.yearEl, "keypress", this._handleEnterKey);
6707
 
                E.removeListener(this.yearEl, arrowEvt, this._handleDirectionKeys);
6708
 
                E.removeListener(this.lastCtrl, tabEvt, this._handleTabKey);
6709
 
                E.removeListener(this.firstCtrl, tabEvt, this._handleShiftTabKey);
6710
 
        },
6711
 
 
6712
 
        /**
6713
 
         * Updates the Calendar/CalendarGroup's pagedate with the currently set month and year if valid.
6714
 
         * <p>
6715
 
         * If the currently set month/year is invalid, a validation error will be displayed and the 
6716
 
         * Calendar/CalendarGroup's pagedate will not be updated.
6717
 
         * </p>
6718
 
         * @method submit
6719
 
         */
6720
 
        submit : function() {
6721
 
                if (this.validate()) {
6722
 
                        this.hide();
6723
 
 
6724
 
                        this.setMonth(this._getMonthFromUI());
6725
 
                        this.setYear(this._getYearFromUI());
6726
 
 
6727
 
                        var cal = this.cal;
6728
 
 
6729
 
                        // Artificial delay, just to help the user see something changed
6730
 
                        var delay = YAHOO.widget.CalendarNavigator.UPDATE_DELAY;
6731
 
                        if (delay > 0) {
6732
 
                                var nav = this;
6733
 
                                window.setTimeout(function(){ nav._update(cal); }, delay);
6734
 
                        } else {
6735
 
                                this._update(cal);
6736
 
                        }
6737
 
                }
6738
 
        },
6739
 
 
6740
 
        /**
6741
 
         * Updates the Calendar rendered state, based on the state of the CalendarNavigator
6742
 
         * @method _update
6743
 
         * @param cal The Calendar instance to update
6744
 
         * @protected
6745
 
         */
6746
 
        _update : function(cal) {
6747
 
                cal.setYear(this.getYear());
6748
 
                cal.setMonth(this.getMonth());
6749
 
                cal.render();
6750
 
        },
6751
 
 
6752
 
        /**
6753
 
         * Hides the navigator and mask, without updating the Calendar/CalendarGroup's state
6754
 
         * 
6755
 
         * @method cancel
6756
 
         */
6757
 
        cancel : function() {
6758
 
                this.hide();
6759
 
        },
6760
 
 
6761
 
        /**
6762
 
         * Validates the current state of the UI controls
6763
 
         * 
6764
 
         * @method validate
6765
 
         * @return {Boolean} true, if the current UI state contains valid values, false if not
6766
 
         */
6767
 
        validate : function() {
6768
 
                if (this._getYearFromUI() !== null) {
6769
 
                        this.clearErrors();
6770
 
                        return true;
6771
 
                } else {
6772
 
                        this.setYearError();
6773
 
                        this.setError(this.__getCfg("invalidYear", true));
6774
 
                        return false;
6775
 
                }
6776
 
        },
6777
 
 
6778
 
        /**
6779
 
         * Displays an error message in the Navigator's error panel
6780
 
         * @method setError
6781
 
         * @param {String} msg The error message to display
6782
 
         */
6783
 
        setError : function(msg) {
6784
 
                if (this.errorEl) {
6785
 
                        this.errorEl.innerHTML = msg;
6786
 
                        this._show(this.errorEl, true);
6787
 
                }
6788
 
        },
6789
 
 
6790
 
        /**
6791
 
         * Clears the navigator's error message and hides the error panel
6792
 
         * @method clearError 
6793
 
         */
6794
 
        clearError : function() {
6795
 
                if (this.errorEl) {
6796
 
                        this.errorEl.innerHTML = "";
6797
 
                        this._show(this.errorEl, false);
6798
 
                }
6799
 
        },
6800
 
 
6801
 
        /**
6802
 
         * Displays the validation error UI for the year control
6803
 
         * @method setYearError
6804
 
         */
6805
 
        setYearError : function() {
6806
 
                YAHOO.util.Dom.addClass(this.yearEl, YAHOO.widget.CalendarNavigator.CLASSES.INVALID);
6807
 
        },
6808
 
 
6809
 
        /**
6810
 
         * Removes the validation error UI for the year control
6811
 
         * @method clearYearError
6812
 
         */
6813
 
        clearYearError : function() {
6814
 
                YAHOO.util.Dom.removeClass(this.yearEl, YAHOO.widget.CalendarNavigator.CLASSES.INVALID);
6815
 
        },
6816
 
 
6817
 
        /**
6818
 
         * Clears all validation and error messages in the UI
6819
 
         * @method clearErrors
6820
 
         */
6821
 
        clearErrors : function() {
6822
 
                this.clearError();
6823
 
                this.clearYearError();
6824
 
        },
6825
 
 
6826
 
        /**
6827
 
         * Sets the initial focus, based on the configured value
6828
 
         * @method setInitialFocus
6829
 
         */
6830
 
        setInitialFocus : function() {
6831
 
                var el = this.submitEl,
6832
 
                        f = this.__getCfg("initialFocus");
6833
 
 
6834
 
                if (f && f.toLowerCase) {
6835
 
                        f = f.toLowerCase();
6836
 
                        if (f == "year") {
6837
 
                                el = this.yearEl;
6838
 
                                try {
6839
 
                                        this.yearEl.select();
6840
 
                                } catch (selErr) {
6841
 
                                        // Ignore;
6842
 
                                }
6843
 
                        } else if (f == "month") {
6844
 
                                el = this.monthEl;
6845
 
                        }
6846
 
                }
6847
 
 
6848
 
                if (el && YAHOO.lang.isFunction(el.focus)) {
6849
 
                        try {
6850
 
                                el.focus();
6851
 
                        } catch (focusErr) {
6852
 
                                // TODO: Fall back if focus fails?
6853
 
                        }
6854
 
                }
6855
 
        },
6856
 
 
6857
 
        /**
6858
 
         * Removes all renderered HTML elements for the Navigator from
6859
 
         * the DOM, purges event listeners and clears (nulls) any property
6860
 
         * references to HTML references
6861
 
         * @method erase
6862
 
         */
6863
 
        erase : function() {
6864
 
                if (this.__rendered) {
6865
 
                        this.purgeListeners();
6866
 
 
6867
 
                        // Clear out innerHTML references
6868
 
                        this.yearEl = null;
6869
 
                        this.monthEl = null;
6870
 
                        this.errorEl = null;
6871
 
                        this.submitEl = null;
6872
 
                        this.cancelEl = null;
6873
 
                        this.firstCtrl = null;
6874
 
                        this.lastCtrl = null;
6875
 
                        if (this.navEl) {
6876
 
                                this.navEl.innerHTML = "";
6877
 
                        }
6878
 
 
6879
 
                        var p = this.navEl.parentNode;
6880
 
                        if (p) {
6881
 
                                p.removeChild(this.navEl);
6882
 
                        }
6883
 
                        this.navEl = null;
6884
 
 
6885
 
                        var pm = this.maskEl.parentNode;
6886
 
                        if (pm) {
6887
 
                                pm.removeChild(this.maskEl);
6888
 
                        }
6889
 
                        this.maskEl = null;
6890
 
                        this.__rendered = false;
6891
 
                }
6892
 
        },
6893
 
 
6894
 
        /**
6895
 
         * Destroys the Navigator object and any HTML references
6896
 
         * @method destroy
6897
 
         */
6898
 
        destroy : function() {
6899
 
                this.erase();
6900
 
                this._doc = null;
6901
 
                this.cal = null;
6902
 
                this.id = null;
6903
 
        },
6904
 
 
6905
 
        /**
6906
 
         * Protected implementation to handle how UI elements are 
6907
 
         * hidden/shown.
6908
 
         *
6909
 
         * @method _show
6910
 
         * @protected
6911
 
         */
6912
 
        _show : function(el, bShow) {
6913
 
                if (el) {
6914
 
                        YAHOO.util.Dom.setStyle(el, "display", (bShow) ? "block" : "none");
6915
 
                }
6916
 
        },
6917
 
 
6918
 
        /**
6919
 
         * Returns the month value (index), from the month UI element
6920
 
         * @protected
6921
 
         * @method _getMonthFromUI
6922
 
         * @return {Number} The month index, or 0 if a UI element for the month
6923
 
         * is not found
6924
 
         */
6925
 
        _getMonthFromUI : function() {
6926
 
                if (this.monthEl) {
6927
 
                        return this.monthEl.selectedIndex;
6928
 
                } else {
6929
 
                        return 0; // Default to Jan
6930
 
                }
6931
 
        },
6932
 
 
6933
 
        /**
6934
 
         * Returns the year value, from the Navitator's year UI element
6935
 
         * @protected
6936
 
         * @method _getYearFromUI
6937
 
         * @return {Number} The year value set in the UI, if valid. null is returned if 
6938
 
         * the UI does not contain a valid year value.
6939
 
         */
6940
 
        _getYearFromUI : function() {
6941
 
                var NAV = YAHOO.widget.CalendarNavigator;
6942
 
 
6943
 
                var yr = null;
6944
 
                if (this.yearEl) {
6945
 
                        var value = this.yearEl.value;
6946
 
                        value = value.replace(NAV.TRIM, "$1");
6947
 
 
6948
 
                        if (NAV.YR_PATTERN.test(value)) {
6949
 
                                yr = parseInt(value, 10);
6950
 
                        }
6951
 
                }
6952
 
                return yr;
6953
 
        },
6954
 
 
6955
 
        /**
6956
 
         * Updates the Navigator's year UI, based on the year value set on the Navigator object
6957
 
         * @protected
6958
 
         * @method _updateYearUI
6959
 
         */
6960
 
        _updateYearUI : function() {
6961
 
                if (this.yearEl && this._year !== null) {
6962
 
                        this.yearEl.value = this._year;
6963
 
                }
6964
 
        },
6965
 
 
6966
 
        /**
6967
 
         * Updates the Navigator's month UI, based on the month value set on the Navigator object
6968
 
         * @protected
6969
 
         * @method _updateMonthUI
6970
 
         */
6971
 
        _updateMonthUI : function() {
6972
 
                if (this.monthEl) {
6973
 
                        this.monthEl.selectedIndex = this._month;
6974
 
                }
6975
 
        },
6976
 
 
6977
 
        /**
6978
 
         * Sets up references to the first and last focusable element in the Navigator's UI
6979
 
         * in terms of tab order (Naviagator's firstEl and lastEl properties). The references
6980
 
         * are used to control modality by looping around from the first to the last control
6981
 
         * and visa versa for tab/shift-tab navigation.
6982
 
         * <p>
6983
 
         * See <a href="#applyKeyListeners">applyKeyListeners</a>
6984
 
         * </p>
6985
 
         * @protected
6986
 
         * @method _setFirstLastElements
6987
 
         */
6988
 
        _setFirstLastElements : function() {
6989
 
                this.firstCtrl = this.monthEl;
6990
 
                this.lastCtrl = this.cancelEl;
6991
 
 
6992
 
                // Special handling for MacOSX.
6993
 
                // - Safari 2.x can't focus on buttons
6994
 
                // - Gecko can't focus on select boxes or buttons
6995
 
                if (this.__isMac) {
6996
 
                        if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420){
6997
 
                                this.firstCtrl = this.monthEl;
6998
 
                                this.lastCtrl = this.yearEl;
6999
 
                        }
7000
 
                        if (YAHOO.env.ua.gecko) {
7001
 
                                this.firstCtrl = this.yearEl;
7002
 
                                this.lastCtrl = this.yearEl;
7003
 
                        }
7004
 
                }
7005
 
        },
7006
 
 
7007
 
        /**
7008
 
         * Default Keyboard event handler to capture Enter 
7009
 
         * on the Navigator's year control (yearEl)
7010
 
         * 
7011
 
         * @method _handleEnterKey
7012
 
         * @protected
7013
 
         * @param {Event} e The DOM event being handled
7014
 
         */
7015
 
        _handleEnterKey : function(e) {
7016
 
                var KEYS = YAHOO.util.KeyListener.KEY;
7017
 
 
7018
 
                if (YAHOO.util.Event.getCharCode(e) == KEYS.ENTER) {
7019
 
                        YAHOO.util.Event.preventDefault(e);
7020
 
                        this.submit();
7021
 
                }
7022
 
        },
7023
 
 
7024
 
        /**
7025
 
         * Default Keyboard event handler to capture up/down/pgup/pgdown
7026
 
         * on the Navigator's year control (yearEl).
7027
 
         * 
7028
 
         * @method _handleDirectionKeys
7029
 
         * @protected
7030
 
         * @param {Event} e The DOM event being handled
7031
 
         */
7032
 
        _handleDirectionKeys : function(e) {
7033
 
                var E = YAHOO.util.Event,
7034
 
                        KEYS = YAHOO.util.KeyListener.KEY,
7035
 
                        NAV = YAHOO.widget.CalendarNavigator;
7036
 
 
7037
 
                var value = (this.yearEl.value) ? parseInt(this.yearEl.value, 10) : null;
7038
 
                if (isFinite(value)) {
7039
 
                        var dir = false;
7040
 
                        switch(E.getCharCode(e)) {
7041
 
                                case KEYS.UP:
7042
 
                                        this.yearEl.value = value + NAV.YR_MINOR_INC;
7043
 
                                        dir = true;
7044
 
                                        break;
7045
 
                                case KEYS.DOWN:
7046
 
                                        this.yearEl.value = Math.max(value - NAV.YR_MINOR_INC, 0);
7047
 
                                        dir = true;
7048
 
                                        break;
7049
 
                                case KEYS.PAGE_UP:
7050
 
                                        this.yearEl.value = value + NAV.YR_MAJOR_INC;
7051
 
                                        dir = true;
7052
 
                                        break;
7053
 
                                case KEYS.PAGE_DOWN:
7054
 
                                        this.yearEl.value = Math.max(value - NAV.YR_MAJOR_INC, 0);
7055
 
                                        dir = true;
7056
 
                                        break;
7057
 
                                default:
7058
 
                                        break;
7059
 
                        }
7060
 
                        if (dir) {
7061
 
                                E.preventDefault(e);
7062
 
                                try {
7063
 
                                        this.yearEl.select();
7064
 
                                } catch(err) {
7065
 
                                        // Ignore
7066
 
                                }
7067
 
                        }
7068
 
                }
7069
 
        },
7070
 
 
7071
 
        /**
7072
 
         * Default Keyboard event handler to capture Tab 
7073
 
         * on the last control (lastCtrl) in the Navigator.
7074
 
         * 
7075
 
         * @method _handleTabKey
7076
 
         * @protected
7077
 
         * @param {Event} e The DOM event being handled
7078
 
         */
7079
 
        _handleTabKey : function(e) {
7080
 
                var E = YAHOO.util.Event,
7081
 
                        KEYS = YAHOO.util.KeyListener.KEY;
7082
 
 
7083
 
                if (E.getCharCode(e) == KEYS.TAB && !e.shiftKey) {
7084
 
                        try {
7085
 
                                E.preventDefault(e);
7086
 
                                this.firstCtrl.focus();
7087
 
                        } catch (err) {
7088
 
                                // Ignore - mainly for focus edge cases
7089
 
                        }
7090
 
                }
7091
 
        },
7092
 
 
7093
 
        /**
7094
 
         * Default Keyboard event handler to capture Shift-Tab 
7095
 
         * on the first control (firstCtrl) in the Navigator.
7096
 
         * 
7097
 
         * @method _handleShiftTabKey
7098
 
         * @protected
7099
 
         * @param {Event} e The DOM event being handled
7100
 
         */
7101
 
        _handleShiftTabKey : function(e) {
7102
 
                var E = YAHOO.util.Event,
7103
 
                        KEYS = YAHOO.util.KeyListener.KEY;
7104
 
 
7105
 
                if (e.shiftKey && E.getCharCode(e) == KEYS.TAB) {
7106
 
                        try {
7107
 
                                E.preventDefault(e);
7108
 
                                this.lastCtrl.focus();
7109
 
                        } catch (err) {
7110
 
                                // Ignore - mainly for focus edge cases
7111
 
                        }
7112
 
                }
7113
 
        },
7114
 
 
7115
 
        /**
7116
 
         * Retrieve Navigator configuration values from 
7117
 
         * the parent Calendar/CalendarGroup's config value.
7118
 
         * <p>
7119
 
         * If it has not been set in the user provided configuration, the method will 
7120
 
         * return the default value of the configuration property, as set in _DEFAULT_CFG
7121
 
         * </p>
7122
 
         * @private
7123
 
         * @method __getCfg
7124
 
         * @param {String} Case sensitive property name.
7125
 
         * @param {Boolean} true, if the property is a string property, false if not.
7126
 
         * @return The value of the configuration property
7127
 
         */
7128
 
        __getCfg : function(prop, bIsStr) {
7129
 
                var DEF_CFG = YAHOO.widget.CalendarNavigator._DEFAULT_CFG;
7130
 
                var cfg = this.cal.cfg.getProperty("navigator");
7131
 
 
7132
 
                if (bIsStr) {
7133
 
                        return (cfg !== true && cfg.strings && cfg.strings[prop]) ? cfg.strings[prop] : DEF_CFG.strings[prop];
7134
 
                } else {
7135
 
                        return (cfg !== true && cfg[prop]) ? cfg[prop] : DEF_CFG[prop];
7136
 
                }
7137
 
        },
7138
 
 
7139
 
        /**
7140
 
         * Private flag, to identify MacOS
7141
 
         * @private
7142
 
         * @property __isMac
7143
 
         */
7144
 
        __isMac : (navigator.userAgent.toLowerCase().indexOf("macintosh") != -1)
7145
 
 
7146
 
};
7147
 
 
7148
 
YAHOO.register("calendar", YAHOO.widget.Calendar, {version: "2.7.0", build: "1799"});