PageRenderTime 75ms CodeModel.GetById 14ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 2ms

/src/main/resources/org/apache/struts2/static/calendar/calendar-debug.js

http://struts2yuiplugin.googlecode.com/
JavaScript | 7178 lines | 3040 code | 916 blank | 3222 comment | 560 complexity | e465b111e655819506047a645708c328 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2Copyright (c) 2009, Yahoo! Inc. All rights reserved.
   3Code licensed under the BSD License:
   4http://developer.yahoo.net/yui/license.txt
   5version: 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        if (!owner) {  YAHOO.log("No owner specified for Config object", "error", "Config"); }
  27
  28    };
  29
  30
  31    var Lang = YAHOO.lang,
  32        CustomEvent = YAHOO.util.CustomEvent,
  33        Config = YAHOO.util.Config;
  34
  35
  36    /**
  37     * Constant representing the CustomEvent type for the config changed event.
  38     * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
  39     * @private
  40     * @static
  41     * @final
  42     */
  43    Config.CONFIG_CHANGED_EVENT = "configChanged";
  44    
  45    /**
  46     * Constant representing the boolean type string
  47     * @property YAHOO.util.Config.BOOLEAN_TYPE
  48     * @private
  49     * @static
  50     * @final
  51     */
  52    Config.BOOLEAN_TYPE = "boolean";
  53    
  54    Config.prototype = {
  55     
  56        /**
  57        * Object reference to the owner of this Config Object
  58        * @property owner
  59        * @type Object
  60        */
  61        owner: null,
  62        
  63        /**
  64        * Boolean flag that specifies whether a queue is currently 
  65        * being executed
  66        * @property queueInProgress
  67        * @type Boolean
  68        */
  69        queueInProgress: false,
  70        
  71        /**
  72        * Maintains the local collection of configuration property objects and 
  73        * their specified values
  74        * @property config
  75        * @private
  76        * @type Object
  77        */ 
  78        config: null,
  79        
  80        /**
  81        * Maintains the local collection of configuration property objects as 
  82        * they were initially applied.
  83        * This object is used when resetting a property.
  84        * @property initialConfig
  85        * @private
  86        * @type Object
  87        */ 
  88        initialConfig: null,
  89        
  90        /**
  91        * Maintains the local, normalized CustomEvent queue
  92        * @property eventQueue
  93        * @private
  94        * @type Object
  95        */ 
  96        eventQueue: null,
  97        
  98        /**
  99        * Custom Event, notifying subscribers when Config properties are set 
 100        * (setProperty is called without the silent flag
 101        * @event configChangedEvent
 102        */
 103        configChangedEvent: null,
 104    
 105        /**
 106        * Initializes the configuration Object and all of its local members.
 107        * @method init
 108        * @param {Object} owner The owner Object to which this Config 
 109        * Object belongs
 110        */
 111        init: function (owner) {
 112    
 113            this.owner = owner;
 114    
 115            this.configChangedEvent = 
 116                this.createEvent(Config.CONFIG_CHANGED_EVENT);
 117    
 118            this.configChangedEvent.signature = CustomEvent.LIST;
 119            this.queueInProgress = false;
 120            this.config = {};
 121            this.initialConfig = {};
 122            this.eventQueue = [];
 123        
 124        },
 125        
 126        /**
 127        * Validates that the value passed in is a Boolean.
 128        * @method checkBoolean
 129        * @param {Object} val The value to validate
 130        * @return {Boolean} true, if the value is valid
 131        */ 
 132        checkBoolean: function (val) {
 133            return (typeof val == Config.BOOLEAN_TYPE);
 134        },
 135        
 136        /**
 137        * Validates that the value passed in is a number.
 138        * @method checkNumber
 139        * @param {Object} val The value to validate
 140        * @return {Boolean} true, if the value is valid
 141        */
 142        checkNumber: function (val) {
 143            return (!isNaN(val));
 144        },
 145        
 146        /**
 147        * Fires a configuration property event using the specified value. 
 148        * @method fireEvent
 149        * @private
 150        * @param {String} key The configuration property's name
 151        * @param {value} Object The value of the correct type for the property
 152        */ 
 153        fireEvent: function ( key, value ) {
 154            YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
 155            var property = this.config[key];
 156        
 157            if (property && property.event) {
 158                property.event.fire(value);
 159            } 
 160        },
 161        
 162        /**
 163        * Adds a property to the Config Object's private config hash.
 164        * @method addProperty
 165        * @param {String} key The configuration property's name
 166        * @param {Object} propertyObject The Object containing all of this 
 167        * property's arguments
 168        */
 169        addProperty: function ( key, propertyObject ) {
 170            key = key.toLowerCase();
 171            YAHOO.log("Added property: " + key, "info", "Config");
 172        
 173            this.config[key] = propertyObject;
 174        
 175            propertyObject.event = this.createEvent(key, { scope: this.owner });
 176            propertyObject.event.signature = CustomEvent.LIST;
 177            
 178            
 179            propertyObject.key = key;
 180        
 181            if (propertyObject.handler) {
 182                propertyObject.event.subscribe(propertyObject.handler, 
 183                    this.owner);
 184            }
 185        
 186            this.setProperty(key, propertyObject.value, true);
 187            
 188            if (! propertyObject.suppressEvent) {
 189                this.queueProperty(key, propertyObject.value);
 190            }
 191            
 192        },
 193        
 194        /**
 195        * Returns a key-value configuration map of the values currently set in  
 196        * the Config Object.
 197        * @method getConfig
 198        * @return {Object} The current config, represented in a key-value map
 199        */
 200        getConfig: function () {
 201        
 202            var cfg = {},
 203                currCfg = this.config,
 204                prop,
 205                property;
 206                
 207            for (prop in currCfg) {
 208                if (Lang.hasOwnProperty(currCfg, prop)) {
 209                    property = currCfg[prop];
 210                    if (property && property.event) {
 211                        cfg[prop] = property.value;
 212                    }
 213                }
 214            }
 215
 216            return cfg;
 217        },
 218        
 219        /**
 220        * Returns the value of specified property.
 221        * @method getProperty
 222        * @param {String} key The name of the property
 223        * @return {Object}  The value of the specified property
 224        */
 225        getProperty: function (key) {
 226            var property = this.config[key.toLowerCase()];
 227            if (property && property.event) {
 228                return property.value;
 229            } else {
 230                return undefined;
 231            }
 232        },
 233        
 234        /**
 235        * Resets the specified property's value to its initial value.
 236        * @method resetProperty
 237        * @param {String} key The name of the property
 238        * @return {Boolean} True is the property was reset, false if not
 239        */
 240        resetProperty: function (key) {
 241    
 242            key = key.toLowerCase();
 243        
 244            var property = this.config[key];
 245    
 246            if (property && property.event) {
 247    
 248                if (this.initialConfig[key] && 
 249                    !Lang.isUndefined(this.initialConfig[key])) {
 250    
 251                    this.setProperty(key, this.initialConfig[key]);
 252
 253                    return true;
 254    
 255                }
 256    
 257            } else {
 258    
 259                return false;
 260            }
 261    
 262        },
 263        
 264        /**
 265        * Sets the value of a property. If the silent property is passed as 
 266        * true, the property's event will not be fired.
 267        * @method setProperty
 268        * @param {String} key The name of the property
 269        * @param {String} value The value to set the property to
 270        * @param {Boolean} silent Whether the value should be set silently, 
 271        * without firing the property event.
 272        * @return {Boolean} True, if the set was successful, false if it failed.
 273        */
 274        setProperty: function (key, value, silent) {
 275        
 276            var property;
 277        
 278            key = key.toLowerCase();
 279            YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
 280        
 281            if (this.queueInProgress && ! silent) {
 282                // Currently running through a queue... 
 283                this.queueProperty(key,value);
 284                return true;
 285    
 286            } else {
 287                property = this.config[key];
 288                if (property && property.event) {
 289                    if (property.validator && !property.validator(value)) {
 290                        return false;
 291                    } else {
 292                        property.value = value;
 293                        if (! silent) {
 294                            this.fireEvent(key, value);
 295                            this.configChangedEvent.fire([key, value]);
 296                        }
 297                        return true;
 298                    }
 299                } else {
 300                    return false;
 301                }
 302            }
 303        },
 304        
 305        /**
 306        * Sets the value of a property and queues its event to execute. If the 
 307        * event is already scheduled to execute, it is
 308        * moved from its current position to the end of the queue.
 309        * @method queueProperty
 310        * @param {String} key The name of the property
 311        * @param {String} value The value to set the property to
 312        * @return {Boolean}  true, if the set was successful, false if 
 313        * it failed.
 314        */ 
 315        queueProperty: function (key, value) {
 316        
 317            key = key.toLowerCase();
 318            YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
 319        
 320            var property = this.config[key],
 321                foundDuplicate = false,
 322                iLen,
 323                queueItem,
 324                queueItemKey,
 325                queueItemValue,
 326                sLen,
 327                supercedesCheck,
 328                qLen,
 329                queueItemCheck,
 330                queueItemCheckKey,
 331                queueItemCheckValue,
 332                i,
 333                s,
 334                q;
 335                                
 336            if (property && property.event) {
 337    
 338                if (!Lang.isUndefined(value) && property.validator && 
 339                    !property.validator(value)) { // validator
 340                    return false;
 341                } else {
 342        
 343                    if (!Lang.isUndefined(value)) {
 344                        property.value = value;
 345                    } else {
 346                        value = property.value;
 347                    }
 348        
 349                    foundDuplicate = false;
 350                    iLen = this.eventQueue.length;
 351        
 352                    for (i = 0; i < iLen; i++) {
 353                        queueItem = this.eventQueue[i];
 354        
 355                        if (queueItem) {
 356                            queueItemKey = queueItem[0];
 357                            queueItemValue = queueItem[1];
 358
 359                            if (queueItemKey == key) {
 360    
 361                                /*
 362                                    found a dupe... push to end of queue, null 
 363                                    current item, and break
 364                                */
 365    
 366                                this.eventQueue[i] = null;
 367    
 368                                this.eventQueue.push(
 369                                    [key, (!Lang.isUndefined(value) ? 
 370                                    value : queueItemValue)]);
 371    
 372                                foundDuplicate = true;
 373                                break;
 374                            }
 375                        }
 376                    }
 377                    
 378                    // this is a refire, or a new property in the queue
 379    
 380                    if (! foundDuplicate && !Lang.isUndefined(value)) { 
 381                        this.eventQueue.push([key, value]);
 382                    }
 383                }
 384        
 385                if (property.supercedes) {
 386
 387                    sLen = property.supercedes.length;
 388
 389                    for (s = 0; s < sLen; s++) {
 390
 391                        supercedesCheck = property.supercedes[s];
 392                        qLen = this.eventQueue.length;
 393
 394                        for (q = 0; q < qLen; q++) {
 395                            queueItemCheck = this.eventQueue[q];
 396
 397                            if (queueItemCheck) {
 398                                queueItemCheckKey = queueItemCheck[0];
 399                                queueItemCheckValue = queueItemCheck[1];
 400
 401                                if (queueItemCheckKey == 
 402                                    supercedesCheck.toLowerCase() ) {
 403
 404                                    this.eventQueue.push([queueItemCheckKey, 
 405                                        queueItemCheckValue]);
 406
 407                                    this.eventQueue[q] = null;
 408                                    break;
 409
 410                                }
 411                            }
 412                        }
 413                    }
 414                }
 415
 416                YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
 417
 418                return true;
 419            } else {
 420                return false;
 421            }
 422        },
 423        
 424        /**
 425        * Fires the event for a property using the property's current value.
 426        * @method refireEvent
 427        * @param {String} key The name of the property
 428        */
 429        refireEvent: function (key) {
 430    
 431            key = key.toLowerCase();
 432        
 433            var property = this.config[key];
 434    
 435            if (property && property.event && 
 436    
 437                !Lang.isUndefined(property.value)) {
 438    
 439                if (this.queueInProgress) {
 440    
 441                    this.queueProperty(key);
 442    
 443                } else {
 444    
 445                    this.fireEvent(key, property.value);
 446    
 447                }
 448    
 449            }
 450        },
 451        
 452        /**
 453        * Applies a key-value Object literal to the configuration, replacing  
 454        * any existing values, and queueing the property events.
 455        * Although the values will be set, fireQueue() must be called for their 
 456        * associated events to execute.
 457        * @method applyConfig
 458        * @param {Object} userConfig The configuration Object literal
 459        * @param {Boolean} init  When set to true, the initialConfig will 
 460        * be set to the userConfig passed in, so that calling a reset will 
 461        * reset the properties to the passed values.
 462        */
 463        applyConfig: function (userConfig, init) {
 464        
 465            var sKey,
 466                oConfig;
 467
 468            if (init) {
 469                oConfig = {};
 470                for (sKey in userConfig) {
 471                    if (Lang.hasOwnProperty(userConfig, sKey)) {
 472                        oConfig[sKey.toLowerCase()] = userConfig[sKey];
 473                    }
 474                }
 475                this.initialConfig = oConfig;
 476            }
 477
 478            for (sKey in userConfig) {
 479                if (Lang.hasOwnProperty(userConfig, sKey)) {
 480                    this.queueProperty(sKey, userConfig[sKey]);
 481                }
 482            }
 483        },
 484        
 485        /**
 486        * Refires the events for all configuration properties using their 
 487        * current values.
 488        * @method refresh
 489        */
 490        refresh: function () {
 491
 492            var prop;
 493
 494            for (prop in this.config) {
 495                if (Lang.hasOwnProperty(this.config, prop)) {
 496                    this.refireEvent(prop);
 497                }
 498            }
 499        },
 500        
 501        /**
 502        * Fires the normalized list of queued property change events
 503        * @method fireQueue
 504        */
 505        fireQueue: function () {
 506        
 507            var i, 
 508                queueItem,
 509                key,
 510                value,
 511                property;
 512        
 513            this.queueInProgress = true;
 514            for (i = 0;i < this.eventQueue.length; i++) {
 515                queueItem = this.eventQueue[i];
 516                if (queueItem) {
 517        
 518                    key = queueItem[0];
 519                    value = queueItem[1];
 520                    property = this.config[key];
 521
 522                    property.value = value;
 523
 524                    // Clear out queue entry, to avoid it being 
 525                    // re-added to the queue by any queueProperty/supercedes
 526                    // calls which are invoked during fireEvent
 527                    this.eventQueue[i] = null;
 528
 529                    this.fireEvent(key,value);
 530                }
 531            }
 532            
 533            this.queueInProgress = false;
 534            this.eventQueue = [];
 535        },
 536        
 537        /**
 538        * Subscribes an external handler to the change event for any 
 539        * given property. 
 540        * @method subscribeToConfigEvent
 541        * @param {String} key The property name
 542        * @param {Function} handler The handler function to use subscribe to 
 543        * the property's event
 544        * @param {Object} obj The Object to use for scoping the event handler 
 545        * (see CustomEvent documentation)
 546        * @param {Boolean} override Optional. If true, will override "this"  
 547        * within the handler to map to the scope Object passed into the method.
 548        * @return {Boolean} True, if the subscription was successful, 
 549        * otherwise false.
 550        */ 
 551        subscribeToConfigEvent: function (key, handler, obj, override) {
 552    
 553            var property = this.config[key.toLowerCase()];
 554    
 555            if (property && property.event) {
 556                if (!Config.alreadySubscribed(property.event, handler, obj)) {
 557                    property.event.subscribe(handler, obj, override);
 558                }
 559                return true;
 560            } else {
 561                return false;
 562            }
 563    
 564        },
 565        
 566        /**
 567        * Unsubscribes an external handler from the change event for any 
 568        * given property. 
 569        * @method unsubscribeFromConfigEvent
 570        * @param {String} key The property name
 571        * @param {Function} handler The handler function to use subscribe to 
 572        * the property's event
 573        * @param {Object} obj The Object to use for scoping the event 
 574        * handler (see CustomEvent documentation)
 575        * @return {Boolean} True, if the unsubscription was successful, 
 576        * otherwise false.
 577        */
 578        unsubscribeFromConfigEvent: function (key, handler, obj) {
 579            var property = this.config[key.toLowerCase()];
 580            if (property && property.event) {
 581                return property.event.unsubscribe(handler, obj);
 582            } else {
 583                return false;
 584            }
 585        },
 586        
 587        /**
 588        * Returns a string representation of the Config object
 589        * @method toString
 590        * @return {String} The Config object in string format.
 591        */
 592        toString: function () {
 593            var output = "Config";
 594            if (this.owner) {
 595                output += " [" + this.owner.toString() + "]";
 596            }
 597            return output;
 598        },
 599        
 600        /**
 601        * Returns a string representation of the Config object's current 
 602        * CustomEvent queue
 603        * @method outputEventQueue
 604        * @return {String} The string list of CustomEvents currently queued 
 605        * for execution
 606        */
 607        outputEventQueue: function () {
 608
 609            var output = "",
 610                queueItem,
 611                q,
 612                nQueue = this.eventQueue.length;
 613              
 614            for (q = 0; q < nQueue; q++) {
 615                queueItem = this.eventQueue[q];
 616                if (queueItem) {
 617                    output += queueItem[0] + "=" + queueItem[1] + ", ";
 618                }
 619            }
 620            return output;
 621        },
 622
 623        /**
 624        * Sets all properties to null, unsubscribes all listeners from each 
 625        * property's change event and all listeners from the configChangedEvent.
 626        * @method destroy
 627        */
 628        destroy: function () {
 629
 630            var oConfig = this.config,
 631                sProperty,
 632                oProperty;
 633
 634
 635            for (sProperty in oConfig) {
 636            
 637                if (Lang.hasOwnProperty(oConfig, sProperty)) {
 638
 639                    oProperty = oConfig[sProperty];
 640
 641                    oProperty.event.unsubscribeAll();
 642                    oProperty.event = null;
 643
 644                }
 645            
 646            }
 647            
 648            this.configChangedEvent.unsubscribeAll();
 649            
 650            this.configChangedEvent = null;
 651            this.owner = null;
 652            this.config = null;
 653            this.initialConfig = null;
 654            this.eventQueue = null;
 655        
 656        }
 657
 658    };
 659    
 660    
 661    
 662    /**
 663    * Checks to determine if a particular function/Object pair are already 
 664    * subscribed to the specified CustomEvent
 665    * @method YAHOO.util.Config.alreadySubscribed
 666    * @static
 667    * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check 
 668    * the subscriptions
 669    * @param {Function} fn The function to look for in the subscribers list
 670    * @param {Object} obj The execution scope Object for the subscription
 671    * @return {Boolean} true, if the function/Object pair is already subscribed 
 672    * to the CustomEvent passed in
 673    */
 674    Config.alreadySubscribed = function (evt, fn, obj) {
 675    
 676        var nSubscribers = evt.subscribers.length,
 677            subsc,
 678            i;
 679
 680        if (nSubscribers > 0) {
 681            i = nSubscribers - 1;
 682            do {
 683                subsc = evt.subscribers[i];
 684                if (subsc && subsc.obj == obj && subsc.fn == fn) {
 685                    return true;
 686                }
 687            }
 688            while (i--);
 689        }
 690
 691        return false;
 692
 693    };
 694
 695    YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
 696
 697}());
 698/**
 699* YAHOO.widget.DateMath is used for simple date manipulation. The class is a static utility
 700* used for adding, subtracting, and comparing dates.
 701* @namespace YAHOO.widget
 702* @class DateMath
 703*/
 704YAHOO.widget.DateMath = {
 705	/**
 706	* Constant field representing Day
 707	* @property DAY
 708	* @static
 709	* @final
 710	* @type String
 711	*/
 712	DAY : "D",
 713
 714	/**
 715	* Constant field representing Week
 716	* @property WEEK
 717	* @static
 718	* @final
 719	* @type String
 720	*/
 721	WEEK : "W",
 722
 723	/**
 724	* Constant field representing Year
 725	* @property YEAR
 726	* @static
 727	* @final
 728	* @type String
 729	*/
 730	YEAR : "Y",
 731
 732	/**
 733	* Constant field representing Month
 734	* @property MONTH
 735	* @static
 736	* @final
 737	* @type String
 738	*/
 739	MONTH : "M",
 740
 741	/**
 742	* Constant field representing one day, in milliseconds
 743	* @property ONE_DAY_MS
 744	* @static
 745	* @final
 746	* @type Number
 747	*/
 748	ONE_DAY_MS : 1000*60*60*24,
 749	
 750	/**
 751	 * Constant field representing the date in first week of January
 752	 * which identifies the first week of the year.
 753	 * <p>
 754	 * In the U.S, Jan 1st is normally used based on a Sunday start of week.
 755	 * ISO 8601, used widely throughout Europe, uses Jan 4th, based on a Monday start of week.
 756	 * </p>
 757	 * @property WEEK_ONE_JAN_DATE
 758	 * @static
 759	 * @type Number
 760	 */
 761	WEEK_ONE_JAN_DATE : 1,
 762
 763	/**
 764	* Adds the specified amount of time to the this instance.
 765	* @method add
 766	* @param {Date} date	The JavaScript Date object to perform addition on
 767	* @param {String} field	The field constant to be used for performing addition.
 768	* @param {Number} amount	The number of units (measured in the field constant) to add to the date.
 769	* @return {Date} The resulting Date object
 770	*/
 771	add : function(date, field, amount) {
 772		var d = new Date(date.getTime());
 773		switch (field) {
 774			case this.MONTH:
 775				var newMonth = date.getMonth() + amount;
 776				var years = 0;
 777
 778				if (newMonth < 0) {
 779					while (newMonth < 0) {
 780						newMonth += 12;
 781						years -= 1;
 782					}
 783				} else if (newMonth > 11) {
 784					while (newMonth > 11) {
 785						newMonth -= 12;
 786						years += 1;
 787					}
 788				}
 789
 790				d.setMonth(newMonth);
 791				d.setFullYear(date.getFullYear() + years);
 792				break;
 793			case this.DAY:
 794				this._addDays(d, amount);
 795				// d.setDate(date.getDate() + amount);
 796				break;
 797			case this.YEAR:
 798				d.setFullYear(date.getFullYear() + amount);
 799				break;
 800			case this.WEEK:
 801				this._addDays(d, (amount * 7));
 802				// d.setDate(date.getDate() + (amount * 7));
 803				break;
 804		}
 805		return d;
 806	},
 807
 808	/**
 809	 * Private helper method to account for bug in Safari 2 (webkit < 420)
 810	 * when Date.setDate(n) is called with n less than -128 or greater than 127.
 811	 * <p>
 812	 * Fix approach and original findings are available here:
 813	 * http://brianary.blogspot.com/2006/03/safari-date-bug.html
 814	 * </p>
 815	 * @method _addDays
 816	 * @param {Date} d JavaScript date object
 817	 * @param {Number} nDays The number of days to add to the date object (can be negative)
 818	 * @private
 819	 */
 820	_addDays : function(d, nDays) {
 821		if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420) {
 822			if (nDays < 0) {
 823				// Ensure we don't go below -128 (getDate() is always 1 to 31, so we won't go above 127)
 824				for(var min = -128; nDays < min; nDays -= min) {
 825					d.setDate(d.getDate() + min);
 826				}
 827			} else {
 828				// Ensure we don't go above 96 + 31 = 127
 829				for(var max = 96; nDays > max; nDays -= max) {
 830					d.setDate(d.getDate() + max);
 831				}
 832			}
 833			// nDays should be remainder between -128 and 96
 834		}
 835		d.setDate(d.getDate() + nDays);
 836	},
 837
 838	/**
 839	* Subtracts the specified amount of time from the this instance.
 840	* @method subtract
 841	* @param {Date} date	The JavaScript Date object to perform subtraction on
 842	* @param {Number} field	The this field constant to be used for performing subtraction.
 843	* @param {Number} amount	The number of units (measured in the field constant) to subtract from the date.
 844	* @return {Date} The resulting Date object
 845	*/
 846	subtract : function(date, field, amount) {
 847		return this.add(date, field, (amount*-1));
 848	},
 849
 850	/**
 851	* Determines whether a given date is before another date on the calendar.
 852	* @method before
 853	* @param {Date} date		The Date object to compare with the compare argument
 854	* @param {Date} compareTo	The Date object to use for the comparison
 855	* @return {Boolean} true if the date occurs before the compared date; false if not.
 856	*/
 857	before : function(date, compareTo) {
 858		var ms = compareTo.getTime();
 859		if (date.getTime() < ms) {
 860			return true;
 861		} else {
 862			return false;
 863		}
 864	},
 865
 866	/**
 867	* Determines whether a given date is after another date on the calendar.
 868	* @method after
 869	* @param {Date} date		The Date object to compare with the compare argument
 870	* @param {Date} compareTo	The Date object to use for the comparison
 871	* @return {Boolean} true if the date occurs after the compared date; false if not.
 872	*/
 873	after : function(date, compareTo) {
 874		var ms = compareTo.getTime();
 875		if (date.getTime() > ms) {
 876			return true;
 877		} else {
 878			return false;
 879		}
 880	},
 881
 882	/**
 883	* Determines whether a given date is between two other dates on the calendar.
 884	* @method between
 885	* @param {Date} date		The date to check for
 886	* @param {Date} dateBegin	The start of the range
 887	* @param {Date} dateEnd		The end of the range
 888	* @return {Boolean} true if the date occurs between the compared dates; false if not.
 889	*/
 890	between : function(date, dateBegin, dateEnd) {
 891		if (this.after(date, dateBegin) && this.before(date, dateEnd)) {
 892			return true;
 893		} else {
 894			return false;
 895		}
 896	},
 897	
 898	/**
 899	* Retrieves a JavaScript Date object representing January 1 of any given year.
 900	* @method getJan1
 901	* @param {Number} calendarYear		The calendar year for which to retrieve January 1
 902	* @return {Date}	January 1 of the calendar year specified.
 903	*/
 904	getJan1 : function(calendarYear) {
 905		return this.getDate(calendarYear,0,1);
 906	},
 907
 908	/**
 909	* Calculates the number of days the specified date is from January 1 of the specified calendar year.
 910	* Passing January 1 to this function would return an offset value of zero.
 911	* @method getDayOffset
 912	* @param {Date}	date	The JavaScript date for which to find the offset
 913	* @param {Number} calendarYear	The calendar year to use for determining the offset
 914	* @return {Number}	The number of days since January 1 of the given year
 915	*/
 916	getDayOffset : function(date, calendarYear) {
 917		var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
 918		
 919		// Find the number of days the passed in date is away from the calendar year start
 920		var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
 921		return dayOffset;
 922	},
 923
 924	/**
 925	* Calculates the week number for the given date. Can currently support standard
 926	* U.S. week numbers, based on Jan 1st defining the 1st week of the year, and 
 927	* ISO8601 week numbers, based on Jan 4th defining the 1st week of the year.
 928	* 
 929	* @method getWeekNumber
 930	* @param {Date}	date The JavaScript date for which to find the week number
 931	* @param {Number} firstDayOfWeek The index of the first day of the week (0 = Sun, 1 = Mon ... 6 = Sat).
 932	* Defaults to 0
 933	* @param {Number} janDate The date in the first week of January which defines week one for the year
 934	* Defaults to the value of YAHOO.widget.DateMath.WEEK_ONE_JAN_DATE, which is 1 (Jan 1st). 
 935	* For the U.S, this is normally Jan 1st. ISO8601 uses Jan 4th to define the first week of the year.
 936	* 
 937	* @return {Number} The number of the week containing the given date.
 938	*/
 939	getWeekNumber : function(date, firstDayOfWeek, janDate) {
 940
 941		// Setup Defaults
 942		firstDayOfWeek = firstDayOfWeek || 0;
 943		janDate = janDate || this.WEEK_ONE_JAN_DATE;
 944
 945		var targetDate = this.clearTime(date),
 946			startOfWeek,
 947			endOfWeek;
 948
 949		if (targetDate.getDay() === firstDayOfWeek) { 
 950			startOfWeek = targetDate;
 951		} else {
 952			startOfWeek = this.getFirstDayOfWeek(targetDate, firstDayOfWeek);
 953		}
 954
 955		var startYear = startOfWeek.getFullYear(),
 956			startTime = startOfWeek.getTime();
 957
 958		// DST shouldn't be a problem here, math is quicker than setDate();
 959		endOfWeek = new Date(startOfWeek.getTime() + 6*this.ONE_DAY_MS);
 960
 961		var weekNum;
 962		if (startYear !== endOfWeek.getFullYear() && endOfWeek.getDate() >= janDate) {
 963			// If years don't match, endOfWeek is in Jan. and if the 
 964			// week has WEEK_ONE_JAN_DATE in it, it's week one by definition.
 965			weekNum = 1;
 966		} else {
 967			// Get the 1st day of the 1st week, and 
 968			// find how many days away we are from it.
 969			var weekOne = this.clearTime(this.getDate(startYear, 0, janDate)),
 970				weekOneDayOne = this.getFirstDayOfWeek(weekOne, firstDayOfWeek);
 971
 972			// Round days to smoothen out 1 hr DST diff
 973			var daysDiff  = Math.round((targetDate.getTime() - weekOneDayOne.getTime())/this.ONE_DAY_MS);
 974
 975			// Calc. Full Weeks
 976			var rem = daysDiff % 7;
 977			var weeksDiff = (daysDiff - rem)/7;
 978			weekNum = weeksDiff + 1;
 979		}
 980		return weekNum;
 981	},
 982
 983	/**
 984	 * Get the first day of the week, for the give date. 
 985	 * @param {Date} dt The date in the week for which the first day is required.
 986	 * @param {Number} startOfWeek The index for the first day of the week, 0 = Sun, 1 = Mon ... 6 = Sat (defaults to 0)
 987	 * @return {Date} The first day of the week
 988	 */
 989	getFirstDayOfWeek : function (dt, startOfWeek) {
 990		startOfWeek = startOfWeek || 0;
 991		var dayOfWeekIndex = dt.getDay(),
 992			dayOfWeek = (dayOfWeekIndex - startOfWeek + 7) % 7;
 993
 994		return this.subtract(dt, this.DAY, dayOfWeek);
 995	},
 996
 997	/**
 998	* Determines if a given week overlaps two different years.
 999	* @method isYearOverlapWeek
1000	* @param {Date}	weekBeginDate	The JavaScript Date representing the first day of the week.
1001	* @return {Boolean}	true if the date overlaps two different years.
1002	*/
1003	isYearOverlapWeek : function(weekBeginDate) {
1004		var overlaps = false;
1005		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
1006		if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
1007			overlaps = true;
1008		}
1009		return overlaps;
1010	},
1011
1012	/**
1013	* Determines if a given week overlaps two different months.
1014	* @method isMonthOverlapWeek
1015	* @param {Date}	weekBeginDate	The JavaScript Date representing the first day of the week.
1016	* @return {Boolean}	true if the date overlaps two different months.
1017	*/
1018	isMonthOverlapWeek : function(weekBeginDate) {
1019		var overlaps = false;
1020		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
1021		if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
1022			overlaps = true;
1023		}
1024		return overlaps;
1025	},
1026
1027	/**
1028	* Gets the first day of a month containing a given date.
1029	* @method findMonthStart
1030	* @param {Date}	date	The JavaScript Date used to calculate the month start
1031	* @return {Date}		The JavaScript Date representing the first day of the month
1032	*/
1033	findMonthStart : function(date) {
1034		var start = this.getDate(date.getFullYear(), date.getMonth(), 1);
1035		return start;
1036	},
1037
1038	/**
1039	* Gets the last day of a month containing a given date.
1040	* @method findMonthEnd
1041	* @param {Date}	date	The JavaScript Date used to calculate the month end
1042	* @return {Date}		The JavaScript Date representing the last day of the month
1043	*/
1044	findMonthEnd : function(date) {
1045		var start = this.findMonthStart(date);
1046		var nextMonth = this.add(start, this.MONTH, 1);
1047		var end = this.subtract(nextMonth, this.DAY, 1);
1048		return end;
1049	},
1050
1051	/**
1052	* Clears the time fields from a given date, effectively setting the time to 12 noon.
1053	* @method clearTime
1054	* @param {Date}	date	The JavaScript Date for which the time fields will be cleared
1055	* @return {Date}		The JavaScript Date cleared of all time fields
1056	*/
1057	clearTime : function(date) {
1058		date.setHours(12,0,0,0);
1059		return date;
1060	},
1061
1062	/**
1063	 * Returns a new JavaScript Date object, representing the given year, month and date. Time fields (hr, min, sec, ms) on the new Date object
1064	 * 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 
1065	 * set the year to 19xx if a year (xx) which is less than 100 is provided.
1066	 * <p>
1067	 * <em>NOTE:</em>Validation on argument values is not performed. It is the caller's responsibility to ensure
1068	 * arguments are valid as per the ECMAScript-262 Date object specification for the new Date(year, month[, date]) constructor.
1069	 * </p>
1070	 * @method getDate
1071	 * @param {Number} y Year.
1072	 * @param {Number} m Month index from 0 (Jan) to 11 (Dec).
1073	 * @param {Number} d (optional) Date from 1 to 31. If not provided, defaults to 1.
1074	 * @return {Date} The JavaScript date object with year, month, date set as provided.
1075	 */
1076	getDate : function(y, m, d) {
1077		var dt = null;
1078		if (YAHOO.lang.isUndefined(d)) {
1079			d = 1;
1080		}
1081		if (y >= 100) {
1082			dt = new Date(y, m, d);
1083		} else {
1084			dt = new Date();
1085			dt.setFullYear(y);
1086			dt.setMonth(m);
1087			dt.setDate(d);
1088			dt.setHours(0,0,0,0);
1089		}
1090		return dt;
1091	}
1092};
1093
1094/**
1095* 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
1096* multi-month interface. Calendars are generated entirely via script and can be navigated without any page refreshes.
1097* @module    calendar
1098* @title    Calendar
1099* @namespace  YAHOO.widget
1100* @requires  yahoo,dom,event
1101*/
1102(function(){
1103
1104	var Dom = YAHOO.util.Dom,
1105		Event = YAHOO.util.Event,
1106		Lang = YAHOO.lang,
1107		DateMath = YAHOO.widget.DateMath;
1108
1109/**
1110* Calendar is the base class for the Calendar widget. In its most basic
1111* implementation, it has the ability to render a calendar widget on the page
1112* that can be manipulated to select a single date, move back and forth between
1113* months and years.
1114* <p>To construct the placeholder for the calendar widget, the code is as
1115* follows:
1116*	<xmp>
1117*		<div id="calContainer"></div>
1118*	</xmp>
1119* </p>
1120* <p>
1121* <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
1122* The Calendar can be constructed by simply providing a container ID string, 
1123* or a reference to a container DIV HTMLElement (the element needs to exist 
1124* in the document).
1125* 
1126* E.g.:
1127*	<xmp>
1128*		var c = new YAHOO.widget.Calendar("calContainer", configOptions);
1129*	</xmp>
1130* or:
1131*   <xmp>
1132*       var containerDiv = YAHOO.util.Dom.get("calContainer");
1133*		var c = new YAHOO.widget.Calendar(containerDiv, configOptions);
1134*	</xmp>
1135* </p>
1136* <p>
1137* If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
1138* 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".
1139* </p>
1140* 
1141* @namespace YAHOO.widget
1142* @class Calendar
1143* @constructor
1144* @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.
1145* @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.
1146* @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
1147*/
1148function Calendar(id, containerId, config) {
1149	this.init.apply(this, arguments);
1150}
1151
1152/**
1153* The path to be used for images loaded for the Calendar
1154* @property YAHOO.widget.Calendar.IMG_ROOT
1155* @static
1156* @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
1157* @type String
1158*/
1159Calendar.IMG_ROOT = null;
1160
1161/**
1162* Type constant used for renderers to represent an individual date (M/D/Y)
1163* @property YAHOO.widget.Calendar.DATE
1164* @static
1165* @final
1166* @type String
1167*/
1168Calendar.DATE = "D";
1169
1170/**
1171* Type constant used for renderers to represent an individual date across any year (M/D)
1172* @property YAHOO.widget.Calendar.MONTH_DAY
1173* @static
1174* @final
1175* @type String
1176*/
1177Calendar.MONTH_DAY = "MD";
1178
1179/**
1180* Type constant used for renderers to represent a weekday
1181* @property YAHOO.widget.Calendar.WEEKDAY
1182* @static
1183* @final
1184* @type String
1185*/
1186Calendar.WEEKDAY = "WD";
1187
1188/**
1189* Type constant used for renderers to represent a range of individual dates (M/D/Y-M/D/Y)
1190* @property YAHOO.widget.Calendar.RANGE
1191* @static
1192* @final
1193* @type String
1194*/
1195Calendar.RANGE = "R";
1196
1197/**
1198* Type constant used for renderers to represent a month across any year
1199* @property YAHOO.widget.Calendar.MONTH
1200* @static
1201* @final
1202* @type String
1203*/
1204Calendar.MONTH = "M";
1205
1206/**
1207* Constant that represents the total number of date cells that are displayed in a given month
1208* @property YAHOO.widget.Calendar.DISPLAY_DAYS
1209* @static
1210* @final
1211* @type Number
1212*/
1213Calendar.DISPLAY_DAYS = 42;
1214
1215/**
1216* Constant used for halting the execution of the remainder of the render stack
1217* @property YAHOO.widget.Calendar.STOP_RENDER
1218* @static
1219* @final
1220* @type String
1221*/
1222Calendar.STOP_RENDER = "S";
1223
1224/**
1225* Constant used to represent short date field string formats (e.g. Tu or Feb)
1226* @property YAHOO.widget.Calendar.SHORT
1227* @static
1228* @final
1229* @type String
1230*/
1231Calendar.SHORT = "short";
1232
1233/**
1234* Constant used to represent long date field string formats (e.g. Monday or February)
1235* @property YAHOO.widget.Calendar.LONG
1236* @static
1237* @final
1238* @type String
1239*/
1240Calendar.LONG = "long";
1241
1242/**
1243* Constant used to represent medium date field string formats (e.g. Mon)
1244* @property YAHOO.widget.Calendar.MEDIUM
1245* @static
1246* @final
1247* @type String
1248*/
1249Calendar.MEDIUM = "medium";
1250
1251/**
1252* Constant used to represent single character date field string formats (e.g. M, T, W)
1253* @property YAHOO.widget.Calendar.ONE_CHAR
1254* @static
1255* @final
1256* @type String
1257*/
1258Calendar.ONE_CHAR = "1char";
1259
1260/**
1261* The set of default Config property keys and values for the Calendar
1262* @property YAHOO.widget.Calendar._DEFAULT_CONFIG
1263* @final
1264* @static
1265* @private
1266* @type Object
1267*/
1268Calendar._DEFAULT_CONFIG = {
1269	// Default values for pagedate and selected are not class level constants - they are set during instance creation 
1270	PAGEDATE : {key:"pagedate", value:null},
1271	SELECTED : {key:"selected", value:null},
1272	TITLE : {key:"title", value:""},
1273	CLOSE : {key:"close", value:false},
1274	IFRAME : {key:"iframe", value:(YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) ? true : false},
1275	MINDATE : {key:"mindate", value:null},
1276	MAXDATE : {key:"maxdate", value:null},
1277	MULTI_SELECT : {key:"multi_select", value:false},
1278	START_WEEKDAY : {key:"start_weekday", value:0},
1279	SHOW_WEEKDAYS : {key:"show_weekdays", value:true},
1280	SHOW_WEEK_HEADER : {key:"show_week_header", value:false},
1281	SHOW_WEEK_FOOTER : {key:"show_week_footer", value:false},
1282	HIDE_BLANK_WEEKS : {key:"hide_blank_weeks", value:false},
1283	NAV_ARROW_LEFT: {key:"nav_arrow_left", value:null} ,
1284	NAV_ARROW_RIGHT : {key:"nav_arrow_right", value:null} ,
1285	MONTHS_SHORT : {key:"months_short", value:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]},
1286	MONTHS_LONG: {key:"months_long", value:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]},
1287	WEEKDAYS_1CHAR: {key:"weekdays_1char", value:["S", "M", "T", "W", "T", "F", "S"]},
1288	WEEKDAYS_SHORT: {key:"weekdays_short", value:["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]},
1289	WEEKDAYS_MEDIUM: {key:"weekdays_medium", value:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]},
1290	WEEKDAYS_LONG: {key:"weekdays_long", value:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]},
1291	LOCALE_MONTHS:{key:"locale_months", value:"long"},
1292	LOCALE_WEEKDAYS:{key:"locale_weekdays", value:"short"},
1293	DATE_DELIMITER:{key:"date_delimiter", value:","},
1294	DATE_FIELD_DELIMITER:{key:"date_field_delimiter", value:"/"},
1295	DATE_RANGE_DELIMITER:{key:"date_range_delimiter", value:"-"},
1296	MY_MONTH_POSITION:{key:"my_month_position", value:1},
1297	MY_YEAR_POSITION:{key:"my_year_position", value:2},
1298	MD_MONTH_POSITION:{key:"md_month_position", value:1},
1299	MD_DAY_POSITION:{key:"md_day_position", value:2},
1300	MDY_MONTH_POSITION:{key:"mdy_month_position", value:1},
1301	MDY_DAY_POSITION:{key:"mdy_day_position", value:2},
1302	MDY_YEAR_POSITION:{key:"mdy_year_position", value:3},
1303	MY_LABEL_MONTH_POSITION:{key:"my_label_month_position", value:1},
1304	MY_LABEL_YEAR_POSITION:{key:"my_label_year_position", value:2},
1305	MY_LABEL_MONTH_SUFFIX:{key:"my_label_month_suffix", value:" "},
1306	MY_LABEL_YEAR_SUFFIX:{key:"my_label_year_suffix", value:""},
1307	NAV: {key:"navigator", value: null},
1308	STRINGS : { 
1309		key:"strings",
1310		value: {
1311			previousMonth : "Previous Month",
1312			nextMonth : "Next Month",
1313			close: "Close"
1314		},
1315		supercedes : ["close", "title"]
1316	}
1317};
1318
1319var DEF_CFG = Calendar._DEFAULT_CONFIG;
1320
1321/**
1322* The set of Custom Event types supported by the Calendar
1323* @property YAHOO.widget.Calendar._EVENT_TYPES
1324* @final
1325* @static
1326* @private
1327* @type Object
1328*/
1329Calendar._EVENT_TYPES = {
1330	BEFORE_SELECT : "beforeSelect", 
1331	SELECT : "select",
1332	BEFORE_DESELECT : "beforeDeselect",
1333	DESELECT : "deselect",
1334	CHANGE_PAGE : "changePage",
1335	BEFORE_RENDER : "beforeRender",
1336	RENDER : "render",
1337	BEFORE_DESTROY : "beforeDestroy",
1338	DESTROY : "destroy",
1339	RESET : "reset",
1340	CLEAR : "clear",
1341	BEFORE_HIDE : "beforeHide",
1342	HIDE : "hide",
1343	BEFORE_SHOW : "beforeShow",
1344	SHOW : "show",
1345	BEFORE_HIDE_NAV : "beforeHideNav",
1346	HIDE_NAV : "hideNav",
1347	BEFORE_SHOW_NAV : "beforeShowNav",
1348	SHOW_NAV : "showNav",
1349	BEFORE_RENDER_NAV : "beforeRenderNav",
1350	RENDER_NAV : "renderNav"
1351};
1352
1353/**
1354* The set of default style constants for the Calendar
1355* @property YAHOO.widget.Calendar._STYLES
1356* @final
1357* @static
1358* @private
1359* @type Object
1360*/
1361Calendar._STYLES = {
1362	CSS_ROW_HEADER: "calrowhead",
1363	CSS_ROW_FOOTER: "calrowfoot",
1364	CSS_CELL : "calcell",
1365	CSS_CELL_SELECTOR : "selector",
1366	CSS_CELL_SELECTED : "selected",
1367	CSS_CELL_SELECTABLE : "selectable",
1368	CSS_CELL_RESTRICTED : "restricted",
1369	CSS_CELL_TODAY : "today",
1370	CSS_CELL_OOM : "oom",
1371	CSS_CELL_OOB : "previous",
1372	CSS_HEADER : "calheader",
1373	CSS_HEADER_TEXT : "calhead",
1374	CSS_BODY : "calbody",
1375	CSS_WEEKDAY_CELL : "calweekdaycell",
1376	CSS_WEEKDAY_ROW : "calweekdayrow",
1377	CSS_FOOTER : "calfoot",
1378	CSS_CALENDAR : "yui-calendar",
1379	CSS_SINGLE : "single",
1380	CSS_CONTAINER : "yui-calcontainer",
1381	CSS_NAV_LEFT : "calnavleft",
1382	CSS_NAV_RIGHT : "calnavright",
1383	CSS_NAV : "calnav",
1384	CSS_CLOSE : "calclose",
1385	CSS_CELL_TOP : "calcelltop",
1386	CSS_CELL_LEFT : "calcellleft",
1387	CSS_CELL_RIGHT : "calcellright",
1388	CSS_CELL_BOTTOM : "calcellbottom",
1389	CSS_CELL_HOVER : "calcellhover",
1390	CSS_CELL_HIGHLIGHT1 : "highlight1",
1391	CSS_CELL_HIGHLIGHT2 : "highlight2",
1392	CSS_CELL_HIGHLIGHT3 : "highlight3",
1393	CSS_CELL_HIGHLIGHT4 : "highlight4"
1394};
1395
1396Calendar.prototype = {
1397
1398	/**
1399	* The configuration object used to set up the calendars various locale and style options.
1400	* @property Config
1401	* @private
1402	* @deprecated Configuration properties should be set by calling Calendar.cfg.setProperty.
1403	* @type Object
1404	*/
1405	Config : null,
1406
1407	/**
1408	* The parent CalendarGroup, only to be set explicitly by the parent group
1409	* @property parent
1410	* @type CalendarGroup
1411	*/	
1412	parent : null,
1413
1414	/**
1415	* The index of this item in the parent group
1416	* @property index
1417	* @type Number
1418	*/
1419	index : -1,
1420
1421	/**
1422	* The collection of calendar table cells
1423	* @property cells
1424	* @type HTMLTableCellElement[]
1425	*/
1426	cells : null,
1427
1428	/**
1429	* 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].
1430	* @property cellDates
1431	* @type Array[](Number[])
1432	*/
1433	cellDates : null,
1434
1435	/**
1436	* The id that uniquely identifies this Calendar.
1437	* @property id
1438	* @type String
1439	*/
1440	id : null,
1441
1442	/**
1443	* The unique id associated with the Calendar's container
1444	* @property containerId
1445	* @type String
1446	*/
1447	containerId: null,
1448
1449	/**
1450	* 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.
1451	* @property oDomContainer
1452	* @type HTMLElement
1453	*/
1454	oDomContainer : null,
1455
1456	/**
1457	* A Date object representing today's date.
1458	* @property today
1459	* @type Date
1460	*/
1461	today : null,
1462
1463	/**
1464	* The list of render functions, along with required parameters, used to render cells. 
1465	* @property renderStack
1466	* @type Array[]
1467	*/
1468	renderStack : null,
1469
1470	/**
1471	* A copy of the initial render functions created before rendering.
1472	* @property _renderStack
1473	* @private
1474	* @type Array
1475	*/
1476	_renderStack : null,
1477
1478	/**
1479	* A reference to the CalendarNavigator instance created for this Calendar.
1480	* Will be null if the "navigator" configuration property has not been set
1481	* @property oNavigator
1482	* @type CalendarNavigator
1483	*/
1484	oNavigator : null,
1485
1486	/**
1487	* The private list of initially selected dates.
1488	* @property _selectedDates
1489	* @private
1490	* @type Array
1491	*/
1492	_selectedDates : null,
1493
1494	/**
1495	* A map of DOM event handlers to attach to cells associated with specific CSS class names
1496	* @property domEventMap
1497	* @type Object
1498	*/
1499	domEventMap : null,
1500
1501	/**
1502	 * Protected helper used to parse Calendar constructor/init arguments.
1503	 *
1504	 * As of 2.4.0, Calendar supports a simpler constructor 
1505	 * signature. This method reconciles arguments
1506	 * received in the pre 2.4.0 and 2.4.0 formats.
1507	 * 
1508	 * @protected
1509	 * @method _parseArgs
1510	 * @param {Array} Function "arguments" array
1511	 * @return {Object} Object with id, container, config properties containing
1512	 * the reconciled argument values.
1513	 **/
1514	_parseArgs : function(args) {
1515		/*
1516		   2.4.0 Constructors signatures
1517
1518		   new Calendar(String)
1519		   new Calendar(HTMLElement)
1520		   new Calendar(String, ConfigObject)
1521		   new Calendar(HTMLElement, ConfigObject)
1522
1523		   Pre 2.4.0 Constructor signatures
1524
1525		   new Calendar(String, String)
1526		   new Calendar(String, HTMLElement)
1527		   new Calendar(String, String, ConfigObject)
1528		   new Calendar(String, HTMLElement, ConfigObject)
1529		 */
1530		var nArgs = {id:null, container:null, config:null};
1531
1532		if (args && args.length && args.length > 0) {
1533			switch (args.length) {
1534				case 1:
1535					nArgs.id = null;
1536					nArgs.container = args[0];
1537					nArgs.config = null;
1538					break;
1539				case 2:
1540					if (Lang.isObject(args[1]) && !args[1].tagName && !(args[1] instanceof String)) {
1541						nArgs.id = null;
1542						nArgs.container = args[0];
1543						nArgs.config = args[1];
1544					} else {
1545						nArgs.id = args[0];
1546						nArgs.container = args[1];
1547						nArgs.config = null;
1548					}
1549					break;
1550				default: // 3+
1551					nArgs.id = args[0];
1552					nArgs.container = args[1];
1553					nArgs.config = args[2];
1554					break;
1555			}
1556		} else {
1557			this.logger.log("Invalid constructor/init arguments", "error");
1558		}
1559		return nArgs;
1560	},
1561
1562	/**
1563	* Initializes the Calendar widget.
1564	* @method init
1565	*
1566	* @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.
1567	* @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.
1568	* @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
1569	*/
1570	init : function(id, container, config) {
1571		// Normalize 2.4.0, pre 2.4.0 args
1572		var nArgs = this._parseArgs(arguments);
1573
1574		id = nArgs.id;
1575		container = nArgs.container;
1576		config = nArgs.config;
1577
1578		this.oDomContainer = Dom.get(container);
1579		if (!this.oDomContainer) { this.logger.log("Container not found in document.", "error"); }
1580
1581		if (!this.oDomContainer.id) {
1582			this.oDomContainer.id = Dom.generateId();
1583		}
1584		if (!id) {
1585			id = this.oDomContainer.id + "_t";
1586		}
1587
1588		this.id = id;
1589		this.containerId = this.oDomContainer.id;
1590
1591		this.logger = new YAHOO.widget.LogWriter("Calendar " + this.id);
1592		this.initEvents();
1593
1594		this.today = new Date();
1595		DateMath.clearTime(this.today);
1596
1597		/**
1598		* The Config object used to hold the configuration variables for the Calendar
1599		* @property cfg
1600		* @type YAHOO.util.Config
1601		*/
1602		this.cfg = new YAHOO.util.Config(this);
1603
1604		/**
1605		* The local object which contains the Calendar's options
1606		* @property Options
1607		* @type Object
1608		*/
1609		this.Options = {};
1610
1611		/**
1612		* The local object which contains the Calendar's 

Large files files are truncated, but you can click here to view the full file