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