2 Copyright (c) 2011, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.com/yui/license.html
10 * Config is a utility used within an Object to allow the implementer to
11 * maintain a list of local configuration properties and listen for changes
12 * to those properties dynamically using CustomEvent. The initial values are
13 * also maintained so that the configuration can be reset at any given point
14 * to its initial state.
15 * @namespace YAHOO.util
18 * @param {Object} owner The owner Object to which this Config Object belongs
20 YAHOO.util.Config = function (owner) {
30 var Lang = YAHOO.lang,
31 CustomEvent = YAHOO.util.CustomEvent,
32 Config = YAHOO.util.Config;
36 * Constant representing the CustomEvent type for the config changed event.
37 * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
42 Config.CONFIG_CHANGED_EVENT = "configChanged";
45 * Constant representing the boolean type string
46 * @property YAHOO.util.Config.BOOLEAN_TYPE
51 Config.BOOLEAN_TYPE = "boolean";
56 * Object reference to the owner of this Config Object
63 * Boolean flag that specifies whether a queue is currently
65 * @property queueInProgress
68 queueInProgress: false,
71 * Maintains the local collection of configuration property objects and
72 * their specified values
80 * Maintains the local collection of configuration property objects as
81 * they were initially applied.
82 * This object is used when resetting a property.
83 * @property initialConfig
90 * Maintains the local, normalized CustomEvent queue
91 * @property eventQueue
98 * Custom Event, notifying subscribers when Config properties are set
99 * (setProperty is called without the silent flag
100 * @event configChangedEvent
102 configChangedEvent: null,
105 * Initializes the configuration Object and all of its local members.
107 * @param {Object} owner The owner Object to which this Config
110 init: function (owner) {
114 this.configChangedEvent =
115 this.createEvent(Config.CONFIG_CHANGED_EVENT);
117 this.configChangedEvent.signature = CustomEvent.LIST;
118 this.queueInProgress = false;
120 this.initialConfig = {};
121 this.eventQueue = [];
126 * Validates that the value passed in is a Boolean.
127 * @method checkBoolean
128 * @param {Object} val The value to validate
129 * @return {Boolean} true, if the value is valid
131 checkBoolean: function (val) {
132 return (typeof val == Config.BOOLEAN_TYPE);
136 * Validates that the value passed in is a number.
137 * @method checkNumber
138 * @param {Object} val The value to validate
139 * @return {Boolean} true, if the value is valid
141 checkNumber: function (val) {
142 return (!isNaN(val));
146 * Fires a configuration property event using the specified value.
149 * @param {String} key The configuration property's name
150 * @param {value} Object The value of the correct type for the property
152 fireEvent: function ( key, value ) {
153 var property = this.config[key];
155 if (property && property.event) {
156 property.event.fire(value);
161 * Adds a property to the Config Object's private config hash.
162 * @method addProperty
163 * @param {String} key The configuration property's name
164 * @param {Object} propertyObject The Object containing all of this
165 * property's arguments
167 addProperty: function ( key, propertyObject ) {
168 key = key.toLowerCase();
170 this.config[key] = propertyObject;
172 propertyObject.event = this.createEvent(key, { scope: this.owner });
173 propertyObject.event.signature = CustomEvent.LIST;
176 propertyObject.key = key;
178 if (propertyObject.handler) {
179 propertyObject.event.subscribe(propertyObject.handler,
183 this.setProperty(key, propertyObject.value, true);
185 if (! propertyObject.suppressEvent) {
186 this.queueProperty(key, propertyObject.value);
192 * Returns a key-value configuration map of the values currently set in
195 * @return {Object} The current config, represented in a key-value map
197 getConfig: function () {
200 currCfg = this.config,
204 for (prop in currCfg) {
205 if (Lang.hasOwnProperty(currCfg, prop)) {
206 property = currCfg[prop];
207 if (property && property.event) {
208 cfg[prop] = property.value;
217 * Returns the value of specified property.
218 * @method getProperty
219 * @param {String} key The name of the property
220 * @return {Object} The value of the specified property
222 getProperty: function (key) {
223 var property = this.config[key.toLowerCase()];
224 if (property && property.event) {
225 return property.value;
232 * Resets the specified property's value to its initial value.
233 * @method resetProperty
234 * @param {String} key The name of the property
235 * @return {Boolean} True is the property was reset, false if not
237 resetProperty: function (key) {
238 key = key.toLowerCase();
240 var property = this.config[key];
242 if (property && property.event) {
243 if (key in this.initialConfig) {
244 this.setProperty(key, this.initialConfig[key]);
253 * Sets the value of a property. If the silent property is passed as
254 * true, the property's event will not be fired.
255 * @method setProperty
256 * @param {String} key The name of the property
257 * @param {String} value The value to set the property to
258 * @param {Boolean} silent Whether the value should be set silently,
259 * without firing the property event.
260 * @return {Boolean} True, if the set was successful, false if it failed.
262 setProperty: function (key, value, silent) {
266 key = key.toLowerCase();
268 if (this.queueInProgress && ! silent) {
269 // Currently running through a queue...
270 this.queueProperty(key,value);
274 property = this.config[key];
275 if (property && property.event) {
276 if (property.validator && !property.validator(value)) {
279 property.value = value;
281 this.fireEvent(key, value);
282 this.configChangedEvent.fire([key, value]);
293 * Sets the value of a property and queues its event to execute. If the
294 * event is already scheduled to execute, it is
295 * moved from its current position to the end of the queue.
296 * @method queueProperty
297 * @param {String} key The name of the property
298 * @param {String} value The value to set the property to
299 * @return {Boolean} true, if the set was successful, false if
302 queueProperty: function (key, value) {
304 key = key.toLowerCase();
306 var property = this.config[key],
307 foundDuplicate = false,
322 if (property && property.event) {
324 if (!Lang.isUndefined(value) && property.validator &&
325 !property.validator(value)) { // validator
329 if (!Lang.isUndefined(value)) {
330 property.value = value;
332 value = property.value;
335 foundDuplicate = false;
336 iLen = this.eventQueue.length;
338 for (i = 0; i < iLen; i++) {
339 queueItem = this.eventQueue[i];
342 queueItemKey = queueItem[0];
343 queueItemValue = queueItem[1];
345 if (queueItemKey == key) {
348 found a dupe... push to end of queue, null
349 current item, and break
352 this.eventQueue[i] = null;
354 this.eventQueue.push(
355 [key, (!Lang.isUndefined(value) ?
356 value : queueItemValue)]);
358 foundDuplicate = true;
364 // this is a refire, or a new property in the queue
366 if (! foundDuplicate && !Lang.isUndefined(value)) {
367 this.eventQueue.push([key, value]);
371 if (property.supercedes) {
373 sLen = property.supercedes.length;
375 for (s = 0; s < sLen; s++) {
377 supercedesCheck = property.supercedes[s];
378 qLen = this.eventQueue.length;
380 for (q = 0; q < qLen; q++) {
381 queueItemCheck = this.eventQueue[q];
383 if (queueItemCheck) {
384 queueItemCheckKey = queueItemCheck[0];
385 queueItemCheckValue = queueItemCheck[1];
387 if (queueItemCheckKey ==
388 supercedesCheck.toLowerCase() ) {
390 this.eventQueue.push([queueItemCheckKey,
391 queueItemCheckValue]);
393 this.eventQueue[q] = null;
410 * Fires the event for a property using the property's current value.
411 * @method refireEvent
412 * @param {String} key The name of the property
414 refireEvent: function (key) {
416 key = key.toLowerCase();
418 var property = this.config[key];
420 if (property && property.event &&
422 !Lang.isUndefined(property.value)) {
424 if (this.queueInProgress) {
426 this.queueProperty(key);
430 this.fireEvent(key, property.value);
438 * Applies a key-value Object literal to the configuration, replacing
439 * any existing values, and queueing the property events.
440 * Although the values will be set, fireQueue() must be called for their
441 * associated events to execute.
442 * @method applyConfig
443 * @param {Object} userConfig The configuration Object literal
444 * @param {Boolean} init When set to true, the initialConfig will
445 * be set to the userConfig passed in, so that calling a reset will
446 * reset the properties to the passed values.
448 applyConfig: function (userConfig, init) {
455 for (sKey in userConfig) {
456 if (Lang.hasOwnProperty(userConfig, sKey)) {
457 oConfig[sKey.toLowerCase()] = userConfig[sKey];
460 this.initialConfig = oConfig;
463 for (sKey in userConfig) {
464 if (Lang.hasOwnProperty(userConfig, sKey)) {
465 this.queueProperty(sKey, userConfig[sKey]);
471 * Refires the events for all configuration properties using their
475 refresh: function () {
479 for (prop in this.config) {
480 if (Lang.hasOwnProperty(this.config, prop)) {
481 this.refireEvent(prop);
487 * Fires the normalized list of queued property change events
490 fireQueue: function () {
498 this.queueInProgress = true;
499 for (i = 0;i < this.eventQueue.length; i++) {
500 queueItem = this.eventQueue[i];
504 value = queueItem[1];
505 property = this.config[key];
507 property.value = value;
509 // Clear out queue entry, to avoid it being
510 // re-added to the queue by any queueProperty/supercedes
511 // calls which are invoked during fireEvent
512 this.eventQueue[i] = null;
514 this.fireEvent(key,value);
518 this.queueInProgress = false;
519 this.eventQueue = [];
523 * Subscribes an external handler to the change event for any
525 * @method subscribeToConfigEvent
526 * @param {String} key The property name
527 * @param {Function} handler The handler function to use subscribe to
528 * the property's event
529 * @param {Object} obj The Object to use for scoping the event handler
530 * (see CustomEvent documentation)
531 * @param {Boolean} overrideContext Optional. If true, will override
532 * "this" within the handler to map to the scope Object passed into the
534 * @return {Boolean} True, if the subscription was successful,
537 subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
539 var property = this.config[key.toLowerCase()];
541 if (property && property.event) {
542 if (!Config.alreadySubscribed(property.event, handler, obj)) {
543 property.event.subscribe(handler, obj, overrideContext);
553 * Unsubscribes an external handler from the change event for any
555 * @method unsubscribeFromConfigEvent
556 * @param {String} key The property name
557 * @param {Function} handler The handler function to use subscribe to
558 * the property's event
559 * @param {Object} obj The Object to use for scoping the event
560 * handler (see CustomEvent documentation)
561 * @return {Boolean} True, if the unsubscription was successful,
564 unsubscribeFromConfigEvent: function (key, handler, obj) {
565 var property = this.config[key.toLowerCase()];
566 if (property && property.event) {
567 return property.event.unsubscribe(handler, obj);
574 * Returns a string representation of the Config object
576 * @return {String} The Config object in string format.
578 toString: function () {
579 var output = "Config";
581 output += " [" + this.owner.toString() + "]";
587 * Returns a string representation of the Config object's current
589 * @method outputEventQueue
590 * @return {String} The string list of CustomEvents currently queued
593 outputEventQueue: function () {
598 nQueue = this.eventQueue.length;
600 for (q = 0; q < nQueue; q++) {
601 queueItem = this.eventQueue[q];
603 output += queueItem[0] + "=" + queueItem[1] + ", ";
610 * Sets all properties to null, unsubscribes all listeners from each
611 * property's change event and all listeners from the configChangedEvent.
614 destroy: function () {
616 var oConfig = this.config,
621 for (sProperty in oConfig) {
623 if (Lang.hasOwnProperty(oConfig, sProperty)) {
625 oProperty = oConfig[sProperty];
627 oProperty.event.unsubscribeAll();
628 oProperty.event = null;
634 this.configChangedEvent.unsubscribeAll();
636 this.configChangedEvent = null;
639 this.initialConfig = null;
640 this.eventQueue = null;
649 * Checks to determine if a particular function/Object pair are already
650 * subscribed to the specified CustomEvent
651 * @method YAHOO.util.Config.alreadySubscribed
653 * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
655 * @param {Function} fn The function to look for in the subscribers list
656 * @param {Object} obj The execution scope Object for the subscription
657 * @return {Boolean} true, if the function/Object pair is already subscribed
658 * to the CustomEvent passed in
660 Config.alreadySubscribed = function (evt, fn, obj) {
662 var nSubscribers = evt.subscribers.length,
666 if (nSubscribers > 0) {
667 i = nSubscribers - 1;
669 subsc = evt.subscribers[i];
670 if (subsc && subsc.obj == obj && subsc.fn == fn) {
681 YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
685 * The datemath module provides utility methods for basic JavaScript Date object manipulation and
692 * YAHOO.widget.DateMath is used for simple date manipulation. The class is a static utility
693 * used for adding, subtracting, and comparing dates.
694 * @namespace YAHOO.widget
697 YAHOO.widget.DateMath = {
699 * Constant field representing Day
708 * Constant field representing Week
717 * Constant field representing Year
726 * Constant field representing Month
735 * Constant field representing one day, in milliseconds
736 * @property ONE_DAY_MS
741 ONE_DAY_MS : 1000*60*60*24,
744 * Constant field representing the date in first week of January
745 * which identifies the first week of the year.
747 * In the U.S, Jan 1st is normally used based on a Sunday start of week.
748 * ISO 8601, used widely throughout Europe, uses Jan 4th, based on a Monday start of week.
750 * @property WEEK_ONE_JAN_DATE
754 WEEK_ONE_JAN_DATE : 1,
757 * Adds the specified amount of time to the this instance.
759 * @param {Date} date The JavaScript Date object to perform addition on
760 * @param {String} field The field constant to be used for performing addition.
761 * @param {Number} amount The number of units (measured in the field constant) to add to the date.
762 * @return {Date} The resulting Date object
764 add : function(date, field, amount) {
765 var d = new Date(date.getTime());
768 var newMonth = date.getMonth() + amount;
772 while (newMonth < 0) {
776 } else if (newMonth > 11) {
777 while (newMonth > 11) {
783 d.setMonth(newMonth);
784 d.setFullYear(date.getFullYear() + years);
787 this._addDays(d, amount);
788 // d.setDate(date.getDate() + amount);
791 d.setFullYear(date.getFullYear() + amount);
794 this._addDays(d, (amount * 7));
795 // d.setDate(date.getDate() + (amount * 7));
802 * Private helper method to account for bug in Safari 2 (webkit < 420)
803 * when Date.setDate(n) is called with n less than -128 or greater than 127.
805 * Fix approach and original findings are available here:
806 * http://brianary.blogspot.com/2006/03/safari-date-bug.html
809 * @param {Date} d JavaScript date object
810 * @param {Number} nDays The number of days to add to the date object (can be negative)
813 _addDays : function(d, nDays) {
814 if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420) {
816 // Ensure we don't go below -128 (getDate() is always 1 to 31, so we won't go above 127)
817 for(var min = -128; nDays < min; nDays -= min) {
818 d.setDate(d.getDate() + min);
821 // Ensure we don't go above 96 + 31 = 127
822 for(var max = 96; nDays > max; nDays -= max) {
823 d.setDate(d.getDate() + max);
826 // nDays should be remainder between -128 and 96
828 d.setDate(d.getDate() + nDays);
832 * Subtracts the specified amount of time from the this instance.
834 * @param {Date} date The JavaScript Date object to perform subtraction on
835 * @param {Number} field The this field constant to be used for performing subtraction.
836 * @param {Number} amount The number of units (measured in the field constant) to subtract from the date.
837 * @return {Date} The resulting Date object
839 subtract : function(date, field, amount) {
840 return this.add(date, field, (amount*-1));
844 * Determines whether a given date is before another date on the calendar.
846 * @param {Date} date The Date object to compare with the compare argument
847 * @param {Date} compareTo The Date object to use for the comparison
848 * @return {Boolean} true if the date occurs before the compared date; false if not.
850 before : function(date, compareTo) {
851 var ms = compareTo.getTime();
852 if (date.getTime() < ms) {
860 * Determines whether a given date is after another date on the calendar.
862 * @param {Date} date The Date object to compare with the compare argument
863 * @param {Date} compareTo The Date object to use for the comparison
864 * @return {Boolean} true if the date occurs after the compared date; false if not.
866 after : function(date, compareTo) {
867 var ms = compareTo.getTime();
868 if (date.getTime() > ms) {
876 * Determines whether a given date is between two other dates on the calendar.
878 * @param {Date} date The date to check for
879 * @param {Date} dateBegin The start of the range
880 * @param {Date} dateEnd The end of the range
881 * @return {Boolean} true if the date occurs between the compared dates; false if not.
883 between : function(date, dateBegin, dateEnd) {
884 if (this.after(date, dateBegin) && this.before(date, dateEnd)) {
892 * Retrieves a JavaScript Date object representing January 1 of any given year.
894 * @param {Number} calendarYear The calendar year for which to retrieve January 1
895 * @return {Date} January 1 of the calendar year specified.
897 getJan1 : function(calendarYear) {
898 return this.getDate(calendarYear,0,1);
902 * Calculates the number of days the specified date is from January 1 of the specified calendar year.
903 * Passing January 1 to this function would return an offset value of zero.
904 * @method getDayOffset
905 * @param {Date} date The JavaScript date for which to find the offset
906 * @param {Number} calendarYear The calendar year to use for determining the offset
907 * @return {Number} The number of days since January 1 of the given year
909 getDayOffset : function(date, calendarYear) {
910 var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
912 // Find the number of days the passed in date is away from the calendar year start
913 var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
918 * Calculates the week number for the given date. Can currently support standard
919 * U.S. week numbers, based on Jan 1st defining the 1st week of the year, and
920 * ISO8601 week numbers, based on Jan 4th defining the 1st week of the year.
922 * @method getWeekNumber
923 * @param {Date} date The JavaScript date for which to find the week number
924 * @param {Number} firstDayOfWeek The index of the first day of the week (0 = Sun, 1 = Mon ... 6 = Sat).
926 * @param {Number} janDate The date in the first week of January which defines week one for the year
927 * Defaults to the value of YAHOO.widget.DateMath.WEEK_ONE_JAN_DATE, which is 1 (Jan 1st).
928 * For the U.S, this is normally Jan 1st. ISO8601 uses Jan 4th to define the first week of the year.
930 * @return {Number} The number of the week containing the given date.
932 getWeekNumber : function(date, firstDayOfWeek, janDate) {
935 firstDayOfWeek = firstDayOfWeek || 0;
936 janDate = janDate || this.WEEK_ONE_JAN_DATE;
938 var targetDate = this.clearTime(date),
942 if (targetDate.getDay() === firstDayOfWeek) {
943 startOfWeek = targetDate;
945 startOfWeek = this.getFirstDayOfWeek(targetDate, firstDayOfWeek);
948 var startYear = startOfWeek.getFullYear();
950 // DST shouldn't be a problem here, math is quicker than setDate();
951 endOfWeek = new Date(startOfWeek.getTime() + 6*this.ONE_DAY_MS);
954 if (startYear !== endOfWeek.getFullYear() && endOfWeek.getDate() >= janDate) {
955 // If years don't match, endOfWeek is in Jan. and if the
956 // week has WEEK_ONE_JAN_DATE in it, it's week one by definition.
959 // Get the 1st day of the 1st week, and
960 // find how many days away we are from it.
961 var weekOne = this.clearTime(this.getDate(startYear, 0, janDate)),
962 weekOneDayOne = this.getFirstDayOfWeek(weekOne, firstDayOfWeek);
964 // Round days to smoothen out 1 hr DST diff
965 var daysDiff = Math.round((targetDate.getTime() - weekOneDayOne.getTime())/this.ONE_DAY_MS);
968 var rem = daysDiff % 7;
969 var weeksDiff = (daysDiff - rem)/7;
970 weekNum = weeksDiff + 1;
976 * Get the first day of the week, for the give date.
977 * @param {Date} dt The date in the week for which the first day is required.
978 * @param {Number} startOfWeek The index for the first day of the week, 0 = Sun, 1 = Mon ... 6 = Sat (defaults to 0)
979 * @return {Date} The first day of the week
981 getFirstDayOfWeek : function (dt, startOfWeek) {
982 startOfWeek = startOfWeek || 0;
983 var dayOfWeekIndex = dt.getDay(),
984 dayOfWeek = (dayOfWeekIndex - startOfWeek + 7) % 7;
986 return this.subtract(dt, this.DAY, dayOfWeek);
990 * Determines if a given week overlaps two different years.
991 * @method isYearOverlapWeek
992 * @param {Date} weekBeginDate The JavaScript Date representing the first day of the week.
993 * @return {Boolean} true if the date overlaps two different years.
995 isYearOverlapWeek : function(weekBeginDate) {
996 var overlaps = false;
997 var nextWeek = this.add(weekBeginDate, this.DAY, 6);
998 if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
1005 * Determines if a given week overlaps two different months.
1006 * @method isMonthOverlapWeek
1007 * @param {Date} weekBeginDate The JavaScript Date representing the first day of the week.
1008 * @return {Boolean} true if the date overlaps two different months.
1010 isMonthOverlapWeek : function(weekBeginDate) {
1011 var overlaps = false;
1012 var nextWeek = this.add(weekBeginDate, this.DAY, 6);
1013 if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
1020 * Gets the first day of a month containing a given date.
1021 * @method findMonthStart
1022 * @param {Date} date The JavaScript Date used to calculate the month start
1023 * @return {Date} The JavaScript Date representing the first day of the month
1025 findMonthStart : function(date) {
1026 var start = this.getDate(date.getFullYear(), date.getMonth(), 1);
1031 * Gets the last day of a month containing a given date.
1032 * @method findMonthEnd
1033 * @param {Date} date The JavaScript Date used to calculate the month end
1034 * @return {Date} The JavaScript Date representing the last day of the month
1036 findMonthEnd : function(date) {
1037 var start = this.findMonthStart(date);
1038 var nextMonth = this.add(start, this.MONTH, 1);
1039 var end = this.subtract(nextMonth, this.DAY, 1);
1044 * Clears the time fields from a given date, effectively setting the time to 12 noon.
1046 * @param {Date} date The JavaScript Date for which the time fields will be cleared
1047 * @return {Date} The JavaScript Date cleared of all time fields
1049 clearTime : function(date) {
1050 date.setHours(12,0,0,0);
1055 * Returns a new JavaScript Date object, representing the given year, month and date. Time fields (hr, min, sec, ms) on the new Date object
1056 * are set to 0. The method allows Date instances to be created with the a year less than 100. "new Date(year, month, date)" implementations
1057 * set the year to 19xx if a year (xx) which is less than 100 is provided.
1059 * <em>NOTE:</em>Validation on argument values is not performed. It is the caller's responsibility to ensure
1060 * arguments are valid as per the ECMAScript-262 Date object specification for the new Date(year, month[, date]) constructor.
1063 * @param {Number} y Year.
1064 * @param {Number} m Month index from 0 (Jan) to 11 (Dec).
1065 * @param {Number} d (optional) Date from 1 to 31. If not provided, defaults to 1.
1066 * @return {Date} The JavaScript date object with year, month, date set as provided.
1068 getDate : function(y, m, d) {
1070 if (YAHOO.lang.isUndefined(d)) {
1074 dt = new Date(y, m, d);
1080 dt.setHours(0,0,0,0);
1086 * 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
1087 * multi-month interface. Calendars are generated entirely via script and can be navigated without any page refreshes.
1090 * @namespace YAHOO.widget
1091 * @requires yahoo,dom,event
1095 var Dom = YAHOO.util.Dom,
1096 Event = YAHOO.util.Event,
1098 DateMath = YAHOO.widget.DateMath;
1101 * Calendar is the base class for the Calendar widget. In its most basic
1102 * implementation, it has the ability to render a calendar widget on the page
1103 * that can be manipulated to select a single date, move back and forth between
1105 * <p>To construct the placeholder for the calendar widget, the code is as
1108 * <div id="calContainer"></div>
1112 * <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
1113 * The Calendar can be constructed by simply providing a container ID string,
1114 * or a reference to a container DIV HTMLElement (the element needs to exist
1119 * var c = new YAHOO.widget.Calendar("calContainer", configOptions);
1123 * var containerDiv = YAHOO.util.Dom.get("calContainer");
1124 * var c = new YAHOO.widget.Calendar(containerDiv, configOptions);
1128 * If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
1129 * 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".
1132 * @namespace YAHOO.widget
1135 * @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.
1136 * @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.
1137 * @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
1139 function Calendar(id, containerId, config) {
1140 this.init.apply(this, arguments);
1144 * The path to be used for images loaded for the Calendar
1145 * @property YAHOO.widget.Calendar.IMG_ROOT
1147 * @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
1150 Calendar.IMG_ROOT = null;
1153 * Type constant used for renderers to represent an individual date (M/D/Y)
1154 * @property YAHOO.widget.Calendar.DATE
1159 Calendar.DATE = "D";
1162 * Type constant used for renderers to represent an individual date across any year (M/D)
1163 * @property YAHOO.widget.Calendar.MONTH_DAY
1168 Calendar.MONTH_DAY = "MD";
1171 * Type constant used for renderers to represent a weekday
1172 * @property YAHOO.widget.Calendar.WEEKDAY
1177 Calendar.WEEKDAY = "WD";
1180 * Type constant used for renderers to represent a range of individual dates (M/D/Y-M/D/Y)
1181 * @property YAHOO.widget.Calendar.RANGE
1186 Calendar.RANGE = "R";
1189 * Type constant used for renderers to represent a month across any year
1190 * @property YAHOO.widget.Calendar.MONTH
1195 Calendar.MONTH = "M";
1198 * Constant that represents the total number of date cells that are displayed in a given month
1199 * @property YAHOO.widget.Calendar.DISPLAY_DAYS
1204 Calendar.DISPLAY_DAYS = 42;
1207 * Constant used for halting the execution of the remainder of the render stack
1208 * @property YAHOO.widget.Calendar.STOP_RENDER
1213 Calendar.STOP_RENDER = "S";
1216 * Constant used to represent short date field string formats (e.g. Tu or Feb)
1217 * @property YAHOO.widget.Calendar.SHORT
1222 Calendar.SHORT = "short";
1225 * Constant used to represent long date field string formats (e.g. Monday or February)
1226 * @property YAHOO.widget.Calendar.LONG
1231 Calendar.LONG = "long";
1234 * Constant used to represent medium date field string formats (e.g. Mon)
1235 * @property YAHOO.widget.Calendar.MEDIUM
1240 Calendar.MEDIUM = "medium";
1243 * Constant used to represent single character date field string formats (e.g. M, T, W)
1244 * @property YAHOO.widget.Calendar.ONE_CHAR
1249 Calendar.ONE_CHAR = "1char";
1252 * The set of default Config property keys and values for the Calendar.
1255 * NOTE: This property is made public in order to allow users to change
1256 * the default values of configuration properties. Users should not
1257 * modify the key string, unless they are overriding the Calendar implementation
1261 * The property is an object with key/value pairs, the key being the
1262 * uppercase configuration property name and the value being an object
1263 * literal with a key string property, and a value property, specifying the
1264 * default value of the property. To override a default value, you can set
1265 * the value property, for example, <code>YAHOO.widget.Calendar.DEFAULT_CONFIG.MULTI_SELECT.value = true;</code>
1267 * @property YAHOO.widget.Calendar.DEFAULT_CONFIG
1272 Calendar.DEFAULT_CONFIG = {
1273 YEAR_OFFSET : {key:"year_offset", value:0, supercedes:["pagedate", "selected", "mindate","maxdate"]},
1274 TODAY : {key:"today", value:new Date(), supercedes:["pagedate"]},
1275 PAGEDATE : {key:"pagedate", value:null},
1276 SELECTED : {key:"selected", value:[]},
1277 TITLE : {key:"title", value:""},
1278 CLOSE : {key:"close", value:false},
1279 IFRAME : {key:"iframe", value:(YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) ? true : false},
1280 MINDATE : {key:"mindate", value:null},
1281 MAXDATE : {key:"maxdate", value:null},
1282 MULTI_SELECT : {key:"multi_select", value:false},
1283 OOM_SELECT : {key:"oom_select", value:false},
1284 START_WEEKDAY : {key:"start_weekday", value:0},
1285 SHOW_WEEKDAYS : {key:"show_weekdays", value:true},
1286 SHOW_WEEK_HEADER : {key:"show_week_header", value:false},
1287 SHOW_WEEK_FOOTER : {key:"show_week_footer", value:false},
1288 HIDE_BLANK_WEEKS : {key:"hide_blank_weeks", value:false},
1289 NAV_ARROW_LEFT: {key:"nav_arrow_left", value:null} ,
1290 NAV_ARROW_RIGHT : {key:"nav_arrow_right", value:null} ,
1291 MONTHS_SHORT : {key:"months_short", value:["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]},
1292 MONTHS_LONG: {key:"months_long", value:["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]},
1293 WEEKDAYS_1CHAR: {key:"weekdays_1char", value:["S", "M", "T", "W", "T", "F", "S"]},
1294 WEEKDAYS_SHORT: {key:"weekdays_short", value:["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]},
1295 WEEKDAYS_MEDIUM: {key:"weekdays_medium", value:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]},
1296 WEEKDAYS_LONG: {key:"weekdays_long", value:["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]},
1297 LOCALE_MONTHS:{key:"locale_months", value:"long"},
1298 LOCALE_WEEKDAYS:{key:"locale_weekdays", value:"short"},
1299 DATE_DELIMITER:{key:"date_delimiter", value:","},
1300 DATE_FIELD_DELIMITER:{key:"date_field_delimiter", value:"/"},
1301 DATE_RANGE_DELIMITER:{key:"date_range_delimiter", value:"-"},
1302 MY_MONTH_POSITION:{key:"my_month_position", value:1},
1303 MY_YEAR_POSITION:{key:"my_year_position", value:2},
1304 MD_MONTH_POSITION:{key:"md_month_position", value:1},
1305 MD_DAY_POSITION:{key:"md_day_position", value:2},
1306 MDY_MONTH_POSITION:{key:"mdy_month_position", value:1},
1307 MDY_DAY_POSITION:{key:"mdy_day_position", value:2},
1308 MDY_YEAR_POSITION:{key:"mdy_year_position", value:3},
1309 MY_LABEL_MONTH_POSITION:{key:"my_label_month_position", value:1},
1310 MY_LABEL_YEAR_POSITION:{key:"my_label_year_position", value:2},
1311 MY_LABEL_MONTH_SUFFIX:{key:"my_label_month_suffix", value:" "},
1312 MY_LABEL_YEAR_SUFFIX:{key:"my_label_year_suffix", value:""},
1313 NAV: {key:"navigator", value: null},
1317 previousMonth : "Previous Month",
1318 nextMonth : "Next Month",
1321 supercedes : ["close", "title"]
1326 * The set of default Config property keys and values for the Calendar
1327 * @property YAHOO.widget.Calendar._DEFAULT_CONFIG
1328 * @deprecated Made public. See the public DEFAULT_CONFIG property for details
1334 Calendar._DEFAULT_CONFIG = Calendar.DEFAULT_CONFIG;
1336 var DEF_CFG = Calendar.DEFAULT_CONFIG;
1339 * The set of Custom Event types supported by the Calendar
1340 * @property YAHOO.widget.Calendar._EVENT_TYPES
1346 Calendar._EVENT_TYPES = {
1347 BEFORE_SELECT : "beforeSelect",
1349 BEFORE_DESELECT : "beforeDeselect",
1350 DESELECT : "deselect",
1351 CHANGE_PAGE : "changePage",
1352 BEFORE_RENDER : "beforeRender",
1354 BEFORE_DESTROY : "beforeDestroy",
1355 DESTROY : "destroy",
1358 BEFORE_HIDE : "beforeHide",
1360 BEFORE_SHOW : "beforeShow",
1362 BEFORE_HIDE_NAV : "beforeHideNav",
1363 HIDE_NAV : "hideNav",
1364 BEFORE_SHOW_NAV : "beforeShowNav",
1365 SHOW_NAV : "showNav",
1366 BEFORE_RENDER_NAV : "beforeRenderNav",
1367 RENDER_NAV : "renderNav"
1371 * The set of default style constants for the Calendar
1372 * @property YAHOO.widget.Calendar.STYLES
1374 * @type Object An object with name/value pairs for the class name identifier/value.
1377 CSS_ROW_HEADER: "calrowhead",
1378 CSS_ROW_FOOTER: "calrowfoot",
1379 CSS_CELL : "calcell",
1380 CSS_CELL_SELECTOR : "selector",
1381 CSS_CELL_SELECTED : "selected",
1382 CSS_CELL_SELECTABLE : "selectable",
1383 CSS_CELL_RESTRICTED : "restricted",
1384 CSS_CELL_TODAY : "today",
1385 CSS_CELL_OOM : "oom",
1386 CSS_CELL_OOB : "previous",
1387 CSS_HEADER : "calheader",
1388 CSS_HEADER_TEXT : "calhead",
1389 CSS_BODY : "calbody",
1390 CSS_WEEKDAY_CELL : "calweekdaycell",
1391 CSS_WEEKDAY_ROW : "calweekdayrow",
1392 CSS_FOOTER : "calfoot",
1393 CSS_CALENDAR : "yui-calendar",
1394 CSS_SINGLE : "single",
1395 CSS_CONTAINER : "yui-calcontainer",
1396 CSS_NAV_LEFT : "calnavleft",
1397 CSS_NAV_RIGHT : "calnavright",
1399 CSS_CLOSE : "calclose",
1400 CSS_CELL_TOP : "calcelltop",
1401 CSS_CELL_LEFT : "calcellleft",
1402 CSS_CELL_RIGHT : "calcellright",
1403 CSS_CELL_BOTTOM : "calcellbottom",
1404 CSS_CELL_HOVER : "calcellhover",
1405 CSS_CELL_HIGHLIGHT1 : "highlight1",
1406 CSS_CELL_HIGHLIGHT2 : "highlight2",
1407 CSS_CELL_HIGHLIGHT3 : "highlight3",
1408 CSS_CELL_HIGHLIGHT4 : "highlight4",
1409 CSS_WITH_TITLE: "withtitle",
1410 CSS_FIXED_SIZE: "fixedsize",
1411 CSS_LINK_CLOSE: "link-close"
1415 * The set of default style constants for the Calendar
1416 * @property YAHOO.widget.Calendar._STYLES
1417 * @deprecated Made public. See the public STYLES property for details
1423 Calendar._STYLES = Calendar.STYLES;
1425 Calendar.prototype = {
1428 * The configuration object used to set up the calendars various locale and style options.
1431 * @deprecated Configuration properties should be set by calling Calendar.cfg.setProperty.
1437 * The parent CalendarGroup, only to be set explicitly by the parent group
1439 * @type CalendarGroup
1444 * The index of this item in the parent group
1451 * The collection of calendar table cells
1453 * @type HTMLTableCellElement[]
1458 * 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].
1459 * @property cellDates
1460 * @type Array[](Number[])
1465 * The id that uniquely identifies this Calendar.
1472 * The unique id associated with the Calendar's container
1473 * @property containerId
1479 * 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.
1480 * @property oDomContainer
1483 oDomContainer : null,
1486 * A Date object representing today's date.
1487 * @deprecated Use the "today" configuration property
1494 * The list of render functions, along with required parameters, used to render cells.
1495 * @property renderStack
1501 * A copy of the initial render functions created before rendering.
1502 * @property _renderStack
1506 _renderStack : null,
1509 * A reference to the CalendarNavigator instance created for this Calendar.
1510 * Will be null if the "navigator" configuration property has not been set
1511 * @property oNavigator
1512 * @type CalendarNavigator
1517 * The private list of initially selected dates.
1518 * @property _selectedDates
1522 _selectedDates : null,
1525 * A map of DOM event handlers to attach to cells associated with specific CSS class names
1526 * @property domEventMap
1532 * Protected helper used to parse Calendar constructor/init arguments.
1534 * As of 2.4.0, Calendar supports a simpler constructor
1535 * signature. This method reconciles arguments
1536 * received in the pre 2.4.0 and 2.4.0 formats.
1539 * @method _parseArgs
1540 * @param {Array} Function "arguments" array
1541 * @return {Object} Object with id, container, config properties containing
1542 * the reconciled argument values.
1544 _parseArgs : function(args) {
1546 2.4.0 Constructors signatures
1548 new Calendar(String)
1549 new Calendar(HTMLElement)
1550 new Calendar(String, ConfigObject)
1551 new Calendar(HTMLElement, ConfigObject)
1553 Pre 2.4.0 Constructor signatures
1555 new Calendar(String, String)
1556 new Calendar(String, HTMLElement)
1557 new Calendar(String, String, ConfigObject)
1558 new Calendar(String, HTMLElement, ConfigObject)
1560 var nArgs = {id:null, container:null, config:null};
1562 if (args && args.length && args.length > 0) {
1563 switch (args.length) {
1566 nArgs.container = args[0];
1567 nArgs.config = null;
1570 if (Lang.isObject(args[1]) && !args[1].tagName && !(args[1] instanceof String)) {
1572 nArgs.container = args[0];
1573 nArgs.config = args[1];
1576 nArgs.container = args[1];
1577 nArgs.config = null;
1582 nArgs.container = args[1];
1583 nArgs.config = args[2];
1592 * Initializes the Calendar widget.
1595 * @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.
1596 * @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.
1597 * @param {Object} config optional The configuration object containing the initial configuration values for the Calendar.
1599 init : function(id, container, config) {
1600 // Normalize 2.4.0, pre 2.4.0 args
1601 var nArgs = this._parseArgs(arguments);
1604 container = nArgs.container;
1605 config = nArgs.config;
1607 this.oDomContainer = Dom.get(container);
1609 this._oDoc = this.oDomContainer.ownerDocument;
1611 if (!this.oDomContainer.id) {
1612 this.oDomContainer.id = Dom.generateId();
1616 id = this.oDomContainer.id + "_t";
1620 this.containerId = this.oDomContainer.id;
1625 * The Config object used to hold the configuration variables for the Calendar
1627 * @type YAHOO.util.Config
1629 this.cfg = new YAHOO.util.Config(this);
1632 * The local object which contains the Calendar's options
1639 * The local object which contains the Calendar's locale settings
1647 Dom.addClass(this.oDomContainer, this.Style.CSS_CONTAINER);
1648 Dom.addClass(this.oDomContainer, this.Style.CSS_SINGLE);
1650 this.cellDates = [];
1652 this.renderStack = [];
1653 this._renderStack = [];
1658 this.cfg.applyConfig(config, true);
1661 this.cfg.fireQueue();
1663 this.today = this.cfg.getProperty("today");
1667 * Default Config listener for the iframe property. If the iframe config property is set to true,
1668 * renders the built-in IFRAME shim if the container is relatively or absolutely positioned.
1670 * @method configIframe
1672 configIframe : function(type, args, obj) {
1673 var useIframe = args[0];
1676 if (Dom.inDocument(this.oDomContainer)) {
1678 var pos = Dom.getStyle(this.oDomContainer, "position");
1680 if (pos == "absolute" || pos == "relative") {
1682 if (!Dom.inDocument(this.iframe)) {
1683 this.iframe = document.createElement("iframe");
1684 this.iframe.src = "javascript:false;";
1686 Dom.setStyle(this.iframe, "opacity", "0");
1688 if (YAHOO.env.ua.ie && YAHOO.env.ua.ie <= 6) {
1689 Dom.addClass(this.iframe, this.Style.CSS_FIXED_SIZE);
1692 this.oDomContainer.insertBefore(this.iframe, this.oDomContainer.firstChild);
1697 if (this.iframe.parentNode) {
1698 this.iframe.parentNode.removeChild(this.iframe);
1708 * Default handler for the "title" property
1709 * @method configTitle
1711 configTitle : function(type, args, obj) {
1712 var title = args[0];
1714 // "" disables title bar
1716 this.createTitleBar(title);
1718 var close = this.cfg.getProperty(DEF_CFG.CLOSE.key);
1720 this.removeTitleBar();
1722 this.createTitleBar(" ");
1728 * Default handler for the "close" property
1729 * @method configClose
1731 configClose : function(type, args, obj) {
1732 var close = args[0],
1733 title = this.cfg.getProperty(DEF_CFG.TITLE.key);
1737 this.createTitleBar(" ");
1739 this.createCloseButton();
1741 this.removeCloseButton();
1743 this.removeTitleBar();
1749 * Initializes Calendar's built-in CustomEvents
1750 * @method initEvents
1752 initEvents : function() {
1754 var defEvents = Calendar._EVENT_TYPES,
1755 CE = YAHOO.util.CustomEvent,
1756 cal = this; // To help with minification
1759 * Fired before a date selection is made
1760 * @event beforeSelectEvent
1762 cal.beforeSelectEvent = new CE(defEvents.BEFORE_SELECT);
1765 * Fired when a date selection is made
1766 * @event selectEvent
1767 * @param {Array} Array of Date field arrays in the format [YYYY, MM, DD].
1769 cal.selectEvent = new CE(defEvents.SELECT);
1772 * Fired before a date or set of dates is deselected
1773 * @event beforeDeselectEvent
1775 cal.beforeDeselectEvent = new CE(defEvents.BEFORE_DESELECT);
1778 * Fired when a date or set of dates is deselected
1779 * @event deselectEvent
1780 * @param {Array} Array of Date field arrays in the format [YYYY, MM, DD].
1782 cal.deselectEvent = new CE(defEvents.DESELECT);
1785 * Fired when the Calendar page is changed
1786 * @event changePageEvent
1787 * @param {Date} prevDate The date before the page was changed
1788 * @param {Date} newDate The date after the page was changed
1790 cal.changePageEvent = new CE(defEvents.CHANGE_PAGE);
1793 * Fired before the Calendar is rendered
1794 * @event beforeRenderEvent
1796 cal.beforeRenderEvent = new CE(defEvents.BEFORE_RENDER);
1799 * Fired when the Calendar is rendered
1800 * @event renderEvent
1802 cal.renderEvent = new CE(defEvents.RENDER);
1805 * Fired just before the Calendar is to be destroyed
1806 * @event beforeDestroyEvent
1808 cal.beforeDestroyEvent = new CE(defEvents.BEFORE_DESTROY);
1811 * Fired after the Calendar is destroyed. This event should be used
1812 * for notification only. When this event is fired, important Calendar instance
1813 * properties, dom references and event listeners have already been
1814 * removed/dereferenced, and hence the Calendar instance is not in a usable
1817 * @event destroyEvent
1819 cal.destroyEvent = new CE(defEvents.DESTROY);
1822 * Fired when the Calendar is reset
1825 cal.resetEvent = new CE(defEvents.RESET);
1828 * Fired when the Calendar is cleared
1831 cal.clearEvent = new CE(defEvents.CLEAR);
1834 * Fired just before the Calendar is to be shown
1835 * @event beforeShowEvent
1837 cal.beforeShowEvent = new CE(defEvents.BEFORE_SHOW);
1840 * Fired after the Calendar is shown
1843 cal.showEvent = new CE(defEvents.SHOW);
1846 * Fired just before the Calendar is to be hidden
1847 * @event beforeHideEvent
1849 cal.beforeHideEvent = new CE(defEvents.BEFORE_HIDE);
1852 * Fired after the Calendar is hidden
1855 cal.hideEvent = new CE(defEvents.HIDE);
1858 * Fired just before the CalendarNavigator is to be shown
1859 * @event beforeShowNavEvent
1861 cal.beforeShowNavEvent = new CE(defEvents.BEFORE_SHOW_NAV);
1864 * Fired after the CalendarNavigator is shown
1865 * @event showNavEvent
1867 cal.showNavEvent = new CE(defEvents.SHOW_NAV);
1870 * Fired just before the CalendarNavigator is to be hidden
1871 * @event beforeHideNavEvent
1873 cal.beforeHideNavEvent = new CE(defEvents.BEFORE_HIDE_NAV);
1876 * Fired after the CalendarNavigator is hidden
1877 * @event hideNavEvent
1879 cal.hideNavEvent = new CE(defEvents.HIDE_NAV);
1882 * Fired just before the CalendarNavigator is to be rendered
1883 * @event beforeRenderNavEvent
1885 cal.beforeRenderNavEvent = new CE(defEvents.BEFORE_RENDER_NAV);
1888 * Fired after the CalendarNavigator is rendered
1889 * @event renderNavEvent
1891 cal.renderNavEvent = new CE(defEvents.RENDER_NAV);
1893 cal.beforeSelectEvent.subscribe(cal.onBeforeSelect, this, true);
1894 cal.selectEvent.subscribe(cal.onSelect, this, true);
1895 cal.beforeDeselectEvent.subscribe(cal.onBeforeDeselect, this, true);
1896 cal.deselectEvent.subscribe(cal.onDeselect, this, true);
1897 cal.changePageEvent.subscribe(cal.onChangePage, this, true);
1898 cal.renderEvent.subscribe(cal.onRender, this, true);
1899 cal.resetEvent.subscribe(cal.onReset, this, true);
1900 cal.clearEvent.subscribe(cal.onClear, this, true);
1904 * The default event handler for clicks on the "Previous Month" navigation UI
1906 * @method doPreviousMonthNav
1907 * @param {DOMEvent} e The DOM event
1908 * @param {Calendar} cal A reference to the calendar
1910 doPreviousMonthNav : function(e, cal) {
1911 Event.preventDefault(e);
1912 // previousMonth invoked in a timeout, to allow
1913 // event to bubble up, with correct target. Calling
1914 // previousMonth, will call render which will remove
1915 // HTML which generated the event, resulting in an
1916 // invalid event target in certain browsers.
1917 setTimeout(function() {
1918 cal.previousMonth();
1919 var navs = Dom.getElementsByClassName(cal.Style.CSS_NAV_LEFT, "a", cal.oDomContainer);
1920 if (navs && navs[0]) {
1931 * The default event handler for clicks on the "Next Month" navigation UI
1933 * @method doNextMonthNav
1934 * @param {DOMEvent} e The DOM event
1935 * @param {Calendar} cal A reference to the calendar
1937 doNextMonthNav : function(e, cal) {
1938 Event.preventDefault(e);
1939 setTimeout(function() {
1941 var navs = Dom.getElementsByClassName(cal.Style.CSS_NAV_RIGHT, "a", cal.oDomContainer);
1942 if (navs && navs[0]) {
1953 * The default event handler for date cell selection. Currently attached to
1954 * the Calendar's bounding box, referenced by it's <a href="#property_oDomContainer">oDomContainer</a> property.
1956 * @method doSelectCell
1957 * @param {DOMEvent} e The DOM event
1958 * @param {Calendar} cal A reference to the calendar
1960 doSelectCell : function(e, cal) {
1961 var cell, d, date, index;
1963 var target = Event.getTarget(e),
1964 tagName = target.tagName.toLowerCase(),
1965 defSelector = false;
1967 while (tagName != "td" && !Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
1969 if (!defSelector && tagName == "a" && Dom.hasClass(target, cal.Style.CSS_CELL_SELECTOR)) {
1973 target = target.parentNode;
1974 tagName = target.tagName.toLowerCase();
1976 if (target == this.oDomContainer || tagName == "html") {
1982 // Stop link href navigation for default renderer
1983 Event.preventDefault(e);
1988 if (Dom.hasClass(cell, cal.Style.CSS_CELL_SELECTABLE)) {
1989 index = cal.getIndexFromId(cell.id);
1991 d = cal.cellDates[index];
1993 date = DateMath.getDate(d[0],d[1]-1,d[2]);
1997 if (cal.Options.MULTI_SELECT) {
1998 link = cell.getElementsByTagName("a")[0];
2003 var cellDate = cal.cellDates[index];
2004 var cellDateIndex = cal._indexOfSelectedFieldArray(cellDate);
2006 if (cellDateIndex > -1) {
2007 cal.deselectCell(index);
2009 cal.selectCell(index);
2013 link = cell.getElementsByTagName("a")[0];
2017 cal.selectCell(index);
2025 * The event that is executed when the user hovers over a cell
2026 * @method doCellMouseOver
2027 * @param {DOMEvent} e The event
2028 * @param {Calendar} cal A reference to the calendar passed by the Event utility
2030 doCellMouseOver : function(e, cal) {
2033 target = Event.getTarget(e);
2038 while (target.tagName && target.tagName.toLowerCase() != "td") {
2039 target = target.parentNode;
2040 if (!target.tagName || target.tagName.toLowerCase() == "html") {
2045 if (Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
2046 Dom.addClass(target, cal.Style.CSS_CELL_HOVER);
2051 * The event that is executed when the user moves the mouse out of a cell
2052 * @method doCellMouseOut
2053 * @param {DOMEvent} e The event
2054 * @param {Calendar} cal A reference to the calendar passed by the Event utility
2056 doCellMouseOut : function(e, cal) {
2059 target = Event.getTarget(e);
2064 while (target.tagName && target.tagName.toLowerCase() != "td") {
2065 target = target.parentNode;
2066 if (!target.tagName || target.tagName.toLowerCase() == "html") {
2071 if (Dom.hasClass(target, cal.Style.CSS_CELL_SELECTABLE)) {
2072 Dom.removeClass(target, cal.Style.CSS_CELL_HOVER);
2076 setupConfig : function() {
2081 * The date to use to represent "Today".
2085 * @default The client side date (new Date()) when the Calendar is instantiated.
2087 cfg.addProperty(DEF_CFG.TODAY.key, { value: new Date(DEF_CFG.TODAY.value.getTime()), supercedes:DEF_CFG.TODAY.supercedes, handler:this.configToday, suppressEvent:true } );
2090 * The month/year representing the current visible Calendar date (mm/yyyy)
2092 * @type String | Date
2093 * @default Today's date
2095 cfg.addProperty(DEF_CFG.PAGEDATE.key, { value: DEF_CFG.PAGEDATE.value || new Date(DEF_CFG.TODAY.value.getTime()), handler:this.configPageDate } );
2098 * The date or range of dates representing the current Calendar selection
2103 cfg.addProperty(DEF_CFG.SELECTED.key, { value:DEF_CFG.SELECTED.value.concat(), handler:this.configSelected } );
2106 * 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 cfg.addProperty(DEF_CFG.TITLE.key, { value:DEF_CFG.TITLE.value, handler:this.configTitle } );
2114 * Whether or not a close button should be displayed for this Calendar
2119 cfg.addProperty(DEF_CFG.CLOSE.key, { value:DEF_CFG.CLOSE.value, handler:this.configClose } );
2122 * 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.
2123 * This property is enabled by default for IE6 and below. It is disabled by default for other browsers for performance reasons, but can be
2124 * enabled if required.
2128 * @default true for IE6 and below, false for all other browsers
2130 cfg.addProperty(DEF_CFG.IFRAME.key, { value:DEF_CFG.IFRAME.value, handler:this.configIframe, validator:cfg.checkBoolean } );
2133 * The minimum selectable date in the current Calendar (mm/dd/yyyy)
2135 * @type String | Date
2138 cfg.addProperty(DEF_CFG.MINDATE.key, { value:DEF_CFG.MINDATE.value, handler:this.configMinDate } );
2141 * The maximum selectable date in the current Calendar (mm/dd/yyyy)
2143 * @type String | Date
2146 cfg.addProperty(DEF_CFG.MAXDATE.key, { value:DEF_CFG.MAXDATE.value, handler:this.configMaxDate } );
2148 // Options properties
2151 * True if the Calendar should allow multiple selections. False by default.
2152 * @config MULTI_SELECT
2156 cfg.addProperty(DEF_CFG.MULTI_SELECT.key, { value:DEF_CFG.MULTI_SELECT.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2159 * True if the Calendar should allow selection of out-of-month dates. False by default.
2160 * @config OOM_SELECT
2164 cfg.addProperty(DEF_CFG.OOM_SELECT.key, { value:DEF_CFG.OOM_SELECT.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2167 * The weekday the week begins on. Default is 0 (Sunday = 0, Monday = 1 ... Saturday = 6).
2168 * @config START_WEEKDAY
2172 cfg.addProperty(DEF_CFG.START_WEEKDAY.key, { value:DEF_CFG.START_WEEKDAY.value, handler:this.configOptions, validator:cfg.checkNumber } );
2175 * True if the Calendar should show weekday labels. True by default.
2176 * @config SHOW_WEEKDAYS
2180 cfg.addProperty(DEF_CFG.SHOW_WEEKDAYS.key, { value:DEF_CFG.SHOW_WEEKDAYS.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2183 * True if the Calendar should show week row headers. False by default.
2184 * @config SHOW_WEEK_HEADER
2188 cfg.addProperty(DEF_CFG.SHOW_WEEK_HEADER.key, { value:DEF_CFG.SHOW_WEEK_HEADER.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2191 * True if the Calendar should show week row footers. False by default.
2192 * @config SHOW_WEEK_FOOTER
2196 cfg.addProperty(DEF_CFG.SHOW_WEEK_FOOTER.key,{ value:DEF_CFG.SHOW_WEEK_FOOTER.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2199 * True if the Calendar should suppress weeks that are not a part of the current month. False by default.
2200 * @config HIDE_BLANK_WEEKS
2204 cfg.addProperty(DEF_CFG.HIDE_BLANK_WEEKS.key, { value:DEF_CFG.HIDE_BLANK_WEEKS.value, handler:this.configOptions, validator:cfg.checkBoolean } );
2207 * 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.
2208 * @config NAV_ARROW_LEFT
2210 * @deprecated You can customize the image by overriding the default CSS class for the left arrow - "calnavleft"
2213 cfg.addProperty(DEF_CFG.NAV_ARROW_LEFT.key, { value:DEF_CFG.NAV_ARROW_LEFT.value, handler:this.configOptions } );
2216 * 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.
2217 * @config NAV_ARROW_RIGHT
2219 * @deprecated You can customize the image by overriding the default CSS class for the right arrow - "calnavright"
2222 cfg.addProperty(DEF_CFG.NAV_ARROW_RIGHT.key, { value:DEF_CFG.NAV_ARROW_RIGHT.value, handler:this.configOptions } );
2224 // Locale properties
2227 * 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.
2228 * @config MONTHS_SHORT
2230 * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
2232 cfg.addProperty(DEF_CFG.MONTHS_SHORT.key, { value:DEF_CFG.MONTHS_SHORT.value, handler:this.configLocale } );
2235 * 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.
2236 * @config MONTHS_LONG
2238 * @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
2240 cfg.addProperty(DEF_CFG.MONTHS_LONG.key, { value:DEF_CFG.MONTHS_LONG.value, handler:this.configLocale } );
2243 * 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.
2244 * @config WEEKDAYS_1CHAR
2246 * @default ["S", "M", "T", "W", "T", "F", "S"]
2248 cfg.addProperty(DEF_CFG.WEEKDAYS_1CHAR.key, { value:DEF_CFG.WEEKDAYS_1CHAR.value, handler:this.configLocale } );
2251 * 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.
2252 * @config WEEKDAYS_SHORT
2254 * @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
2256 cfg.addProperty(DEF_CFG.WEEKDAYS_SHORT.key, { value:DEF_CFG.WEEKDAYS_SHORT.value, handler:this.configLocale } );
2259 * 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.
2260 * @config WEEKDAYS_MEDIUM
2262 * @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
2264 cfg.addProperty(DEF_CFG.WEEKDAYS_MEDIUM.key, { value:DEF_CFG.WEEKDAYS_MEDIUM.value, handler:this.configLocale } );
2267 * 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.
2268 * @config WEEKDAYS_LONG
2270 * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
2272 cfg.addProperty(DEF_CFG.WEEKDAYS_LONG.key, { value:DEF_CFG.WEEKDAYS_LONG.value, handler:this.configLocale } );
2275 * Refreshes the locale values used to build the Calendar.
2276 * @method refreshLocale
2279 var refreshLocale = function() {
2280 cfg.refireEvent(DEF_CFG.LOCALE_MONTHS.key);
2281 cfg.refireEvent(DEF_CFG.LOCALE_WEEKDAYS.key);
2284 cfg.subscribeToConfigEvent(DEF_CFG.START_WEEKDAY.key, refreshLocale, this, true);
2285 cfg.subscribeToConfigEvent(DEF_CFG.MONTHS_SHORT.key, refreshLocale, this, true);
2286 cfg.subscribeToConfigEvent(DEF_CFG.MONTHS_LONG.key, refreshLocale, this, true);
2287 cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_1CHAR.key, refreshLocale, this, true);
2288 cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_SHORT.key, refreshLocale, this, true);
2289 cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_MEDIUM.key, refreshLocale, this, true);
2290 cfg.subscribeToConfigEvent(DEF_CFG.WEEKDAYS_LONG.key, refreshLocale, this, true);
2293 * The setting that determines which length of month labels should be used. Possible values are "short" and "long".
2294 * @config LOCALE_MONTHS
2298 cfg.addProperty(DEF_CFG.LOCALE_MONTHS.key, { value:DEF_CFG.LOCALE_MONTHS.value, handler:this.configLocaleValues } );
2301 * The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
2302 * @config LOCALE_WEEKDAYS
2306 cfg.addProperty(DEF_CFG.LOCALE_WEEKDAYS.key, { value:DEF_CFG.LOCALE_WEEKDAYS.value, handler:this.configLocaleValues } );
2309 * The positive or negative year offset from the Gregorian calendar year (assuming a January 1st rollover) to
2310 * be used when displaying and parsing dates. NOTE: All JS Date objects returned by methods, or expected as input by
2311 * methods will always represent the Gregorian year, in order to maintain date/month/week values.
2313 * @config YEAR_OFFSET
2317 cfg.addProperty(DEF_CFG.YEAR_OFFSET.key, { value:DEF_CFG.YEAR_OFFSET.value, supercedes:DEF_CFG.YEAR_OFFSET.supercedes, handler:this.configLocale } );
2320 * The value used to delimit individual dates in a date string passed to various Calendar functions.
2321 * @config DATE_DELIMITER
2325 cfg.addProperty(DEF_CFG.DATE_DELIMITER.key, { value:DEF_CFG.DATE_DELIMITER.value, handler:this.configLocale } );
2328 * The value used to delimit date fields in a date string passed to various Calendar functions.
2329 * @config DATE_FIELD_DELIMITER
2333 cfg.addProperty(DEF_CFG.DATE_FIELD_DELIMITER.key, { value:DEF_CFG.DATE_FIELD_DELIMITER.value, handler:this.configLocale } );
2336 * The value used to delimit date ranges in a date string passed to various Calendar functions.
2337 * @config DATE_RANGE_DELIMITER
2341 cfg.addProperty(DEF_CFG.DATE_RANGE_DELIMITER.key, { value:DEF_CFG.DATE_RANGE_DELIMITER.value, handler:this.configLocale } );
2344 * The position of the month in a month/year date string
2345 * @config MY_MONTH_POSITION
2349 cfg.addProperty(DEF_CFG.MY_MONTH_POSITION.key, { value:DEF_CFG.MY_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2352 * The position of the year in a month/year date string
2353 * @config MY_YEAR_POSITION
2357 cfg.addProperty(DEF_CFG.MY_YEAR_POSITION.key, { value:DEF_CFG.MY_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2360 * The position of the month in a month/day date string
2361 * @config MD_MONTH_POSITION
2365 cfg.addProperty(DEF_CFG.MD_MONTH_POSITION.key, { value:DEF_CFG.MD_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2368 * The position of the day in a month/year date string
2369 * @config MD_DAY_POSITION
2373 cfg.addProperty(DEF_CFG.MD_DAY_POSITION.key, { value:DEF_CFG.MD_DAY_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2376 * The position of the month in a month/day/year date string
2377 * @config MDY_MONTH_POSITION
2381 cfg.addProperty(DEF_CFG.MDY_MONTH_POSITION.key, { value:DEF_CFG.MDY_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2384 * The position of the day in a month/day/year date string
2385 * @config MDY_DAY_POSITION
2389 cfg.addProperty(DEF_CFG.MDY_DAY_POSITION.key, { value:DEF_CFG.MDY_DAY_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2392 * The position of the year in a month/day/year date string
2393 * @config MDY_YEAR_POSITION
2397 cfg.addProperty(DEF_CFG.MDY_YEAR_POSITION.key, { value:DEF_CFG.MDY_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2400 * The position of the month in the month year label string used as the Calendar header
2401 * @config MY_LABEL_MONTH_POSITION
2405 cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_POSITION.key, { value:DEF_CFG.MY_LABEL_MONTH_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2408 * The position of the year in the month year label string used as the Calendar header
2409 * @config MY_LABEL_YEAR_POSITION
2413 cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_POSITION.key, { value:DEF_CFG.MY_LABEL_YEAR_POSITION.value, handler:this.configLocale, validator:cfg.checkNumber } );
2416 * 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.
2417 * @config MY_LABEL_MONTH_SUFFIX
2421 cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_SUFFIX.key, { value:DEF_CFG.MY_LABEL_MONTH_SUFFIX.value, handler:this.configLocale } );
2424 * 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.
2425 * @config MY_LABEL_YEAR_SUFFIX
2429 cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_SUFFIX.key, { value:DEF_CFG.MY_LABEL_YEAR_SUFFIX.value, handler:this.configLocale } );
2432 * Configuration for the Month/Year CalendarNavigator UI which allows the user to jump directly to a
2433 * specific Month/Year without having to scroll sequentially through months.
2435 * Setting this property to null (default value) or false, will disable the CalendarNavigator UI.
2438 * Setting this property to true will enable the CalendarNavigatior UI with the default CalendarNavigator configuration values.
2441 * This property can also be set to an object literal containing configuration properties for the CalendarNavigator UI.
2442 * The configuration object expects the the following case-sensitive properties, with the "strings" property being a nested object.
2443 * Any properties which are not provided will use the default values (defined in the CalendarNavigator class).
2447 * <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.
2449 * <dt>month</dt><dd><em>HTML</em> : The markup to use for the month label. Defaults to "Month".</dd>
2450 * <dt>year</dt><dd><em>HTML</em> : The markup to use for the year label. Defaults to "Year".</dd>
2451 * <dt>submit</dt><dd><em>HTML</em> : The markup to use for the submit button label. Defaults to "Okay".</dd>
2452 * <dt>cancel</dt><dd><em>HTML</em> : The markup to use for the cancel button label. Defaults to "Cancel".</dd>
2453 * <dt>invalidYear</dt><dd><em>HTML</em> : The markup to use for invalid year values. Defaults to "Year needs to be a number".</dd>
2456 * <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>
2457 * <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
2463 * month:"Calendar Month",
2464 * year:"Calendar Year",
2467 * invalidYear: "Please enter a valid year"
2469 * monthFormat: YAHOO.widget.Calendar.SHORT,
2470 * initialFocus: "month"
2474 * @type {Object|Boolean}
2477 cfg.addProperty(DEF_CFG.NAV.key, { value:DEF_CFG.NAV.value, handler:this.configNavigator } );
2480 * The map of UI strings which the Calendar UI uses.
2484 * @default An object with the properties shown below:
2486 * <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>
2487 * <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>
2488 * <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>
2491 cfg.addProperty(DEF_CFG.STRINGS.key, {
2492 value:DEF_CFG.STRINGS.value,
2493 handler:this.configStrings,
2494 validator: function(val) {
2495 return Lang.isObject(val);
2497 supercedes:DEF_CFG.STRINGS.supercedes
2502 * The default handler for the "strings" property
2503 * @method configStrings
2505 configStrings : function(type, args, obj) {
2506 var val = Lang.merge(DEF_CFG.STRINGS.value, args[0]);
2507 this.cfg.setProperty(DEF_CFG.STRINGS.key, val, true);
2511 * The default handler for the "pagedate" property
2512 * @method configPageDate
2514 configPageDate : function(type, args, obj) {
2515 this.cfg.setProperty(DEF_CFG.PAGEDATE.key, this._parsePageDate(args[0]), true);
2519 * The default handler for the "mindate" property
2520 * @method configMinDate
2522 configMinDate : function(type, args, obj) {
2524 if (Lang.isString(val)) {
2525 val = this._parseDate(val);
2526 this.cfg.setProperty(DEF_CFG.MINDATE.key, DateMath.getDate(val[0],(val[1]-1),val[2]));
2531 * The default handler for the "maxdate" property
2532 * @method configMaxDate
2534 configMaxDate : function(type, args, obj) {
2536 if (Lang.isString(val)) {
2537 val = this._parseDate(val);
2538 this.cfg.setProperty(DEF_CFG.MAXDATE.key, DateMath.getDate(val[0],(val[1]-1),val[2]));
2543 * The default handler for the "today" property
2544 * @method configToday
2546 configToday : function(type, args, obj) {
2547 // Only do this for initial set. Changing the today property after the initial
2548 // set, doesn't affect pagedate
2550 if (Lang.isString(val)) {
2551 val = this._parseDate(val);
2553 var today = DateMath.clearTime(val);
2554 if (!this.cfg.initialConfig[DEF_CFG.PAGEDATE.key]) {
2555 this.cfg.setProperty(DEF_CFG.PAGEDATE.key, today);
2558 this.cfg.setProperty(DEF_CFG.TODAY.key, today, true);
2562 * The default handler for the "selected" property
2563 * @method configSelected
2565 configSelected : function(type, args, obj) {
2566 var selected = args[0],
2567 cfgSelected = DEF_CFG.SELECTED.key;
2570 if (Lang.isString(selected)) {
2571 this.cfg.setProperty(cfgSelected, this._parseDates(selected), true);
2574 if (! this._selectedDates) {
2575 this._selectedDates = this.cfg.getProperty(cfgSelected);
2580 * The default handler for all configuration options properties
2581 * @method configOptions
2583 configOptions : function(type, args, obj) {
2584 this.Options[type.toUpperCase()] = args[0];
2588 * The default handler for all configuration locale properties
2589 * @method configLocale
2591 configLocale : function(type, args, obj) {
2592 this.Locale[type.toUpperCase()] = args[0];
2594 this.cfg.refireEvent(DEF_CFG.LOCALE_MONTHS.key);
2595 this.cfg.refireEvent(DEF_CFG.LOCALE_WEEKDAYS.key);
2599 * The default handler for all configuration locale field length properties
2600 * @method configLocaleValues
2602 configLocaleValues : function(type, args, obj) {
2604 type = type.toLowerCase();
2608 Locale = this.Locale;
2611 case DEF_CFG.LOCALE_MONTHS.key:
2613 case Calendar.SHORT:
2614 Locale.LOCALE_MONTHS = cfg.getProperty(DEF_CFG.MONTHS_SHORT.key).concat();
2617 Locale.LOCALE_MONTHS = cfg.getProperty(DEF_CFG.MONTHS_LONG.key).concat();
2621 case DEF_CFG.LOCALE_WEEKDAYS.key:
2623 case Calendar.ONE_CHAR:
2624 Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_1CHAR.key).concat();
2626 case Calendar.SHORT:
2627 Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_SHORT.key).concat();
2629 case Calendar.MEDIUM:
2630 Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_MEDIUM.key).concat();
2633 Locale.LOCALE_WEEKDAYS = cfg.getProperty(DEF_CFG.WEEKDAYS_LONG.key).concat();
2637 var START_WEEKDAY = cfg.getProperty(DEF_CFG.START_WEEKDAY.key);
2639 if (START_WEEKDAY > 0) {
2640 for (var w=0; w < START_WEEKDAY; ++w) {
2641 Locale.LOCALE_WEEKDAYS.push(Locale.LOCALE_WEEKDAYS.shift());
2649 * The default handler for the "navigator" property
2650 * @method configNavigator
2652 configNavigator : function(type, args, obj) {
2654 if (YAHOO.widget.CalendarNavigator && (val === true || Lang.isObject(val))) {
2655 if (!this.oNavigator) {
2656 this.oNavigator = new YAHOO.widget.CalendarNavigator(this);
2657 // Cleanup DOM Refs/Events before innerHTML is removed.
2658 this.beforeRenderEvent.subscribe(function () {
2660 this.oNavigator.erase();
2665 if (this.oNavigator) {
2666 this.oNavigator.destroy();
2667 this.oNavigator = null;
2673 * 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.
2674 * @method initStyles
2676 initStyles : function() {
2678 var defStyle = Calendar.STYLES;
2682 * @property Style.CSS_ROW_HEADER
2684 CSS_ROW_HEADER: defStyle.CSS_ROW_HEADER,
2686 * @property Style.CSS_ROW_FOOTER
2688 CSS_ROW_FOOTER: defStyle.CSS_ROW_FOOTER,
2690 * @property Style.CSS_CELL
2692 CSS_CELL : defStyle.CSS_CELL,
2694 * @property Style.CSS_CELL_SELECTOR
2696 CSS_CELL_SELECTOR : defStyle.CSS_CELL_SELECTOR,
2698 * @property Style.CSS_CELL_SELECTED
2700 CSS_CELL_SELECTED : defStyle.CSS_CELL_SELECTED,
2702 * @property Style.CSS_CELL_SELECTABLE
2704 CSS_CELL_SELECTABLE : defStyle.CSS_CELL_SELECTABLE,
2706 * @property Style.CSS_CELL_RESTRICTED
2708 CSS_CELL_RESTRICTED : defStyle.CSS_CELL_RESTRICTED,
2710 * @property Style.CSS_CELL_TODAY
2712 CSS_CELL_TODAY : defStyle.CSS_CELL_TODAY,
2714 * @property Style.CSS_CELL_OOM
2716 CSS_CELL_OOM : defStyle.CSS_CELL_OOM,
2718 * @property Style.CSS_CELL_OOB
2720 CSS_CELL_OOB : defStyle.CSS_CELL_OOB,
2722 * @property Style.CSS_HEADER
2724 CSS_HEADER : defStyle.CSS_HEADER,
2726 * @property Style.CSS_HEADER_TEXT
2728 CSS_HEADER_TEXT : defStyle.CSS_HEADER_TEXT,
2730 * @property Style.CSS_BODY
2732 CSS_BODY : defStyle.CSS_BODY,
2734 * @property Style.CSS_WEEKDAY_CELL
2736 CSS_WEEKDAY_CELL : defStyle.CSS_WEEKDAY_CELL,
2738 * @property Style.CSS_WEEKDAY_ROW
2740 CSS_WEEKDAY_ROW : defStyle.CSS_WEEKDAY_ROW,
2742 * @property Style.CSS_FOOTER
2744 CSS_FOOTER : defStyle.CSS_FOOTER,
2746 * @property Style.CSS_CALENDAR
2748 CSS_CALENDAR : defStyle.CSS_CALENDAR,
2750 * @property Style.CSS_SINGLE
2752 CSS_SINGLE : defStyle.CSS_SINGLE,
2754 * @property Style.CSS_CONTAINER
2756 CSS_CONTAINER : defStyle.CSS_CONTAINER,
2758 * @property Style.CSS_NAV_LEFT
2760 CSS_NAV_LEFT : defStyle.CSS_NAV_LEFT,
2762 * @property Style.CSS_NAV_RIGHT
2764 CSS_NAV_RIGHT : defStyle.CSS_NAV_RIGHT,
2766 * @property Style.CSS_NAV
2768 CSS_NAV : defStyle.CSS_NAV,
2770 * @property Style.CSS_CLOSE
2772 CSS_CLOSE : defStyle.CSS_CLOSE,
2774 * @property Style.CSS_CELL_TOP
2776 CSS_CELL_TOP : defStyle.CSS_CELL_TOP,
2778 * @property Style.CSS_CELL_LEFT
2780 CSS_CELL_LEFT : defStyle.CSS_CELL_LEFT,
2782 * @property Style.CSS_CELL_RIGHT
2784 CSS_CELL_RIGHT : defStyle.CSS_CELL_RIGHT,
2786 * @property Style.CSS_CELL_BOTTOM
2788 CSS_CELL_BOTTOM : defStyle.CSS_CELL_BOTTOM,
2790 * @property Style.CSS_CELL_HOVER
2792 CSS_CELL_HOVER : defStyle.CSS_CELL_HOVER,
2794 * @property Style.CSS_CELL_HIGHLIGHT1
2796 CSS_CELL_HIGHLIGHT1 : defStyle.CSS_CELL_HIGHLIGHT1,
2798 * @property Style.CSS_CELL_HIGHLIGHT2
2800 CSS_CELL_HIGHLIGHT2 : defStyle.CSS_CELL_HIGHLIGHT2,
2802 * @property Style.CSS_CELL_HIGHLIGHT3
2804 CSS_CELL_HIGHLIGHT3 : defStyle.CSS_CELL_HIGHLIGHT3,
2806 * @property Style.CSS_CELL_HIGHLIGHT4
2808 CSS_CELL_HIGHLIGHT4 : defStyle.CSS_CELL_HIGHLIGHT4,
2810 * @property Style.CSS_WITH_TITLE
2812 CSS_WITH_TITLE : defStyle.CSS_WITH_TITLE,
2814 * @property Style.CSS_FIXED_SIZE
2816 CSS_FIXED_SIZE : defStyle.CSS_FIXED_SIZE,
2818 * @property Style.CSS_LINK_CLOSE
2820 CSS_LINK_CLOSE : defStyle.CSS_LINK_CLOSE
2825 * Builds the date label that will be displayed in the calendar header or
2826 * footer, depending on configuration.
2827 * @method buildMonthLabel
2828 * @return {HTML} The formatted calendar month label
2830 buildMonthLabel : function() {
2831 return this._buildMonthLabel(this.cfg.getProperty(DEF_CFG.PAGEDATE.key));
2835 * Helper method, to format a Month Year string, given a JavaScript Date, based on the
2836 * Calendar localization settings
2838 * @method _buildMonthLabel
2840 * @param {Date} date
2841 * @return {HTML} Formated month, year string
2843 _buildMonthLabel : function(date) {
2844 var monthLabel = this.Locale.LOCALE_MONTHS[date.getMonth()] + this.Locale.MY_LABEL_MONTH_SUFFIX,
2845 yearLabel = (date.getFullYear() + this.Locale.YEAR_OFFSET) + this.Locale.MY_LABEL_YEAR_SUFFIX;
2847 if (this.Locale.MY_LABEL_MONTH_POSITION == 2 || this.Locale.MY_LABEL_YEAR_POSITION == 1) {
2848 return yearLabel + monthLabel;
2850 return monthLabel + yearLabel;
2855 * Builds the date digit that will be displayed in calendar cells
2856 * @method buildDayLabel
2857 * @param {Date} workingDate The current working date
2858 * @return {Number} The day
2860 buildDayLabel : function(workingDate) {
2861 return workingDate.getDate();
2865 * 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.
2867 * @method createTitleBar
2868 * @param {HTML} strTitle The title to display in the title bar
2869 * @return The title bar element
2871 createTitleBar : function(strTitle) {
2872 var tDiv = Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || document.createElement("div");
2873 tDiv.className = YAHOO.widget.CalendarGroup.CSS_2UPTITLE;
2874 tDiv.innerHTML = strTitle;
2875 this.oDomContainer.insertBefore(tDiv, this.oDomContainer.firstChild);
2877 Dom.addClass(this.oDomContainer, this.Style.CSS_WITH_TITLE);
2883 * Removes the title bar element from the DOM
2885 * @method removeTitleBar
2887 removeTitleBar : function() {
2888 var tDiv = Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE, "div", this.oDomContainer)[0] || null;
2890 Event.purgeElement(tDiv);
2891 this.oDomContainer.removeChild(tDiv);
2893 Dom.removeClass(this.oDomContainer, this.Style.CSS_WITH_TITLE);
2897 * Creates the close button HTML element and adds it to Calendar container DIV
2899 * @method createCloseButton
2900 * @return {HTMLElement} The close HTML element created
2902 createCloseButton : function() {
2903 var cssClose = YAHOO.widget.CalendarGroup.CSS_2UPCLOSE,
2904 cssLinkClose = this.Style.CSS_LINK_CLOSE,
2905 DEPR_CLOSE_PATH = "us/my/bn/x_d.gif",
2907 lnk = Dom.getElementsByClassName(cssLinkClose, "a", this.oDomContainer)[0],
2908 strings = this.cfg.getProperty(DEF_CFG.STRINGS.key),
2909 closeStr = (strings && strings.close) ? strings.close : "";
2912 lnk = document.createElement("a");
2913 Event.addListener(lnk, "click", function(e, cal) {
2915 Event.preventDefault(e);
2920 lnk.className = cssLinkClose;
2922 if (Calendar.IMG_ROOT !== null) {
2923 var img = Dom.getElementsByClassName(cssClose, "img", lnk)[0] || document.createElement("img");
2924 img.src = Calendar.IMG_ROOT + DEPR_CLOSE_PATH;
2925 img.className = cssClose;
2926 lnk.appendChild(img);
2928 lnk.innerHTML = '<span class="' + cssClose + ' ' + this.Style.CSS_CLOSE + '">' + closeStr + '</span>';
2930 this.oDomContainer.appendChild(lnk);
2936 * Removes the close button HTML element from the DOM
2938 * @method removeCloseButton
2940 removeCloseButton : function() {
2941 var btn = Dom.getElementsByClassName(this.Style.CSS_LINK_CLOSE, "a", this.oDomContainer)[0] || null;
2943 Event.purgeElement(btn);
2944 this.oDomContainer.removeChild(btn);
2949 * 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.
2950 * @method renderHeader
2951 * @param {HTML[]} html The current working HTML array
2952 * @return {HTML[]} The current working HTML array
2954 renderHeader : function(html) {
2958 DEPR_NAV_LEFT = "us/tr/callt.gif",
2959 DEPR_NAV_RIGHT = "us/tr/calrt.gif",
2961 pageDate = cfg.getProperty(DEF_CFG.PAGEDATE.key),
2962 strings= cfg.getProperty(DEF_CFG.STRINGS.key),
2963 prevStr = (strings && strings.previousMonth) ? strings.previousMonth : "",
2964 nextStr = (strings && strings.nextMonth) ? strings.nextMonth : "",
2967 if (cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key)) {
2971 if (cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key)) {
2975 html[html.length] = "<thead>";
2976 html[html.length] = "<tr>";
2977 html[html.length] = '<th colspan="' + colSpan + '" class="' + this.Style.CSS_HEADER_TEXT + '">';
2978 html[html.length] = '<div class="' + this.Style.CSS_HEADER + '">';
2980 var renderLeft, renderRight = false;
2983 if (this.index === 0) {
2986 if (this.index == (this.parent.cfg.getProperty("pages") -1)) {
2995 monthLabel = this._buildMonthLabel(DateMath.subtract(pageDate, DateMath.MONTH, 1));
2997 var leftArrow = cfg.getProperty(DEF_CFG.NAV_ARROW_LEFT.key);
2998 // 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
2999 if (leftArrow === null && Calendar.IMG_ROOT !== null) {
3000 leftArrow = Calendar.IMG_ROOT + DEPR_NAV_LEFT;
3002 var leftStyle = (leftArrow === null) ? "" : ' style="background-image:url(' + leftArrow + ')"';
3003 html[html.length] = '<a class="' + this.Style.CSS_NAV_LEFT + '"' + leftStyle + ' href="#">' + prevStr + ' (' + monthLabel + ')' + '</a>';
3006 var lbl = this.buildMonthLabel();
3007 var cal = this.parent || this;
3008 if (cal.cfg.getProperty("navigator")) {
3009 lbl = "<a class=\"" + this.Style.CSS_NAV + "\" href=\"#\">" + lbl + "</a>";
3011 html[html.length] = lbl;
3014 monthLabel = this._buildMonthLabel(DateMath.add(pageDate, DateMath.MONTH, 1));
3016 var rightArrow = cfg.getProperty(DEF_CFG.NAV_ARROW_RIGHT.key);
3017 if (rightArrow === null && Calendar.IMG_ROOT !== null) {
3018 rightArrow = Calendar.IMG_ROOT + DEPR_NAV_RIGHT;
3020 var rightStyle = (rightArrow === null) ? "" : ' style="background-image:url(' + rightArrow + ')"';
3021 html[html.length] = '<a class="' + this.Style.CSS_NAV_RIGHT + '"' + rightStyle + ' href="#">' + nextStr + ' (' + monthLabel + ')' + '</a>';
3024 html[html.length] = '</div>\n</th>\n</tr>';
3026 if (cfg.getProperty(DEF_CFG.SHOW_WEEKDAYS.key)) {
3027 html = this.buildWeekdays(html);
3030 html[html.length] = '</thead>';
3036 * 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.
3037 * @method buildWeekdays
3038 * @param {HTML[]} html The current working HTML array
3039 * @return {HTML[]} The current working HTML array
3041 buildWeekdays : function(html) {
3043 html[html.length] = '<tr class="' + this.Style.CSS_WEEKDAY_ROW + '">';
3045 if (this.cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key)) {
3046 html[html.length] = '<th> </th>';
3049 for(var i=0;i < this.Locale.LOCALE_WEEKDAYS.length; ++i) {
3050 html[html.length] = '<th class="' + this.Style.CSS_WEEKDAY_CELL + '">' + this.Locale.LOCALE_WEEKDAYS[i] + '</th>';
3053 if (this.cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key)) {
3054 html[html.length] = '<th> </th>';
3057 html[html.length] = '</tr>';
3063 * 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.
3064 * @method renderBody
3065 * @param {Date} workingDate The current working Date being used for the render process
3066 * @param {HTML[]} html The current working HTML array
3067 * @return {HTML[]} The current working HTML array
3069 renderBody : function(workingDate, html) {
3071 var startDay = this.cfg.getProperty(DEF_CFG.START_WEEKDAY.key);
3073 this.preMonthDays = workingDate.getDay();
3075 this.preMonthDays -= startDay;
3077 if (this.preMonthDays < 0) {
3078 this.preMonthDays += 7;
3081 this.monthDays = DateMath.findMonthEnd(workingDate).getDate();
3082 this.postMonthDays = Calendar.DISPLAY_DAYS-this.preMonthDays-this.monthDays;
3085 workingDate = DateMath.subtract(workingDate, DateMath.DAY, this.preMonthDays);
3090 cellPrefix = "_cell",
3091 workingDayPrefix = "wd",
3098 todayYear = t.getFullYear(),
3099 todayMonth = t.getMonth(),
3100 todayDate = t.getDate(),
3101 useDate = cfg.getProperty(DEF_CFG.PAGEDATE.key),
3102 hideBlankWeeks = cfg.getProperty(DEF_CFG.HIDE_BLANK_WEEKS.key),
3103 showWeekFooter = cfg.getProperty(DEF_CFG.SHOW_WEEK_FOOTER.key),
3104 showWeekHeader = cfg.getProperty(DEF_CFG.SHOW_WEEK_HEADER.key),
3105 oomSelect = cfg.getProperty(DEF_CFG.OOM_SELECT.key),
3106 mindate = cfg.getProperty(DEF_CFG.MINDATE.key),
3107 maxdate = cfg.getProperty(DEF_CFG.MAXDATE.key),
3108 yearOffset = this.Locale.YEAR_OFFSET;
3111 mindate = DateMath.clearTime(mindate);
3114 maxdate = DateMath.clearTime(maxdate);
3117 html[html.length] = '<tbody class="m' + (useDate.getMonth()+1) + ' ' + this.Style.CSS_BODY + '">';
3120 tempDiv = document.createElement("div"),
3121 cell = document.createElement("td");
3123 tempDiv.appendChild(cell);
3125 var cal = this.parent || this;
3127 for (var r = 0; r < 6; r++) {
3128 weekNum = DateMath.getWeekNumber(workingDate, startDay);
3129 weekClass = weekPrefix + weekNum;
3131 // Local OOM check for performance, since we already have pagedate
3132 if (r !== 0 && hideBlankWeeks === true && workingDate.getMonth() != useDate.getMonth()) {
3135 html[html.length] = '<tr class="' + weekClass + '">';
3137 if (showWeekHeader) { html = this.renderRowHeader(weekNum, html); }
3139 for (var d=0; d < 7; d++){ // Render actual days
3143 this.clearElement(cell);
3144 cell.className = this.Style.CSS_CELL;
3145 cell.id = this.id + cellPrefix + i;
3147 if (workingDate.getDate() == todayDate &&
3148 workingDate.getMonth() == todayMonth &&
3149 workingDate.getFullYear() == todayYear) {
3150 cellRenderers[cellRenderers.length]=cal.renderCellStyleToday;
3153 var workingArray = [workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()];
3154 this.cellDates[this.cellDates.length] = workingArray; // Add this date to cellDates
3156 // Local OOM check for performance, since we already have pagedate
3157 oom = workingDate.getMonth() != useDate.getMonth();
3158 if (oom && !oomSelect) {
3159 cellRenderers[cellRenderers.length]=cal.renderCellNotThisMonth;
3161 Dom.addClass(cell, workingDayPrefix + workingDate.getDay());
3162 Dom.addClass(cell, dayPrefix + workingDate.getDate());
3164 // Concat, so that we're not splicing from an array
3165 // which we're also iterating
3166 var rs = this.renderStack.concat();
3168 for (var s=0, l = rs.length; s < l; ++s) {
3180 month = rArray[1][1];
3182 year = rArray[1][0];
3184 if (workingDate.getMonth()+1 == month && workingDate.getDate() == day && workingDate.getFullYear() == year) {
3185 renderer = rArray[2];
3186 this.renderStack.splice(s,1);
3190 case Calendar.MONTH_DAY:
3191 month = rArray[1][0];
3194 if (workingDate.getMonth()+1 == month && workingDate.getDate() == day) {
3195 renderer = rArray[2];
3196 this.renderStack.splice(s,1);
3199 case Calendar.RANGE:
3200 var date1 = rArray[1][0],
3201 date2 = rArray[1][1],
3205 d1 = DateMath.getDate(d1year, d1month-1, d1day),
3209 d2 = DateMath.getDate(d2year, d2month-1, d2day);
3211 if (workingDate.getTime() >= d1.getTime() && workingDate.getTime() <= d2.getTime()) {
3212 renderer = rArray[2];
3214 if (workingDate.getTime()==d2.getTime()) {
3215 this.renderStack.splice(s,1);
3219 case Calendar.WEEKDAY:
3220 var weekday = rArray[1][0];
3221 if (workingDate.getDay()+1 == weekday) {
3222 renderer = rArray[2];
3225 case Calendar.MONTH:
3226 month = rArray[1][0];
3227 if (workingDate.getMonth()+1 == month) {
3228 renderer = rArray[2];
3234 cellRenderers[cellRenderers.length]=renderer;
3240 if (this._indexOfSelectedFieldArray(workingArray) > -1) {
3241 cellRenderers[cellRenderers.length]=cal.renderCellStyleSelected;
3245 cellRenderers[cellRenderers.length] = cal.styleCellNotThisMonth;
3248 if ((mindate && (workingDate.getTime() < mindate.getTime())) || (maxdate && (workingDate.getTime() > maxdate.getTime()))) {
3249 cellRenderers[cellRenderers.length] = cal.renderOutOfBoundsDate;
3251 cellRenderers[cellRenderers.length] = cal.styleCellDefault;
3252 cellRenderers[cellRenderers.length] = cal.renderCellDefault;
3255 for (var x=0; x < cellRenderers.length; ++x) {
3256 if (cellRenderers[x].call(cal, workingDate, cell) == Calendar.STOP_RENDER) {
3261 workingDate.setTime(workingDate.getTime() + DateMath.ONE_DAY_MS);
3262 // Just in case we crossed DST/Summertime boundaries
3263 workingDate = DateMath.clearTime(workingDate);
3265 if (i >= 0 && i <= 6) {
3266 Dom.addClass(cell, this.Style.CSS_CELL_TOP);
3268 if ((i % 7) === 0) {
3269 Dom.addClass(cell, this.Style.CSS_CELL_LEFT);
3271 if (((i+1) % 7) === 0) {
3272 Dom.addClass(cell, this.Style.CSS_CELL_RIGHT);
3275 var postDays = this.postMonthDays;
3276 if (hideBlankWeeks && postDays >= 7) {
3277 var blankWeeks = Math.floor(postDays/7);
3278 for (var p=0;p<blankWeeks;++p) {
3283 if (i >= ((this.preMonthDays+postDays+this.monthDays)-7)) {
3284 Dom.addClass(cell, this.Style.CSS_CELL_BOTTOM);
3287 html[html.length] = tempDiv.innerHTML;
3291 if (showWeekFooter) { html = this.renderRowFooter(weekNum, html); }
3293 html[html.length] = '</tr>';
3297 html[html.length] = '</tbody>';
3303 * 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.
3304 * @method renderFooter
3305 * @param {HTML[]} html The current working HTML array
3306 * @return {HTML[]} The current working HTML array
3308 renderFooter : function(html) { return html; },
3311 * Renders the calendar after it has been configured. The render() method has a specific call chain that will execute
3312 * when the method is called: renderHeader, renderBody, renderFooter.
3313 * Refer to the documentation for those methods for information on individual render tasks.
3316 render : function() {
3317 this.beforeRenderEvent.fire();
3319 // Find starting day of the current month
3320 var workingDate = DateMath.findMonthStart(this.cfg.getProperty(DEF_CFG.PAGEDATE.key));
3322 this.resetRenderers();
3323 this.cellDates.length = 0;
3325 Event.purgeElement(this.oDomContainer, true);
3330 html[html.length] = '<table cellSpacing="0" class="' + this.Style.CSS_CALENDAR + ' y' + (workingDate.getFullYear() + this.Locale.YEAR_OFFSET) +'" id="' + this.id + '">';
3331 html = this.renderHeader(html);
3332 html = this.renderBody(workingDate, html);
3333 html = this.renderFooter(html);
3334 html[html.length] = '</table>';
3336 this.oDomContainer.innerHTML = html.join("\n");
3338 this.applyListeners();
3340 // Using oDomContainer.ownerDocument, to allow for cross-frame rendering
3341 table = ((this._oDoc) && this._oDoc.getElementById(this.id)) || (this.id);
3343 this.cells = Dom.getElementsByClassName(this.Style.CSS_CELL, "td", table);
3345 this.cfg.refireEvent(DEF_CFG.TITLE.key);
3346 this.cfg.refireEvent(DEF_CFG.CLOSE.key);
3347 this.cfg.refireEvent(DEF_CFG.IFRAME.key);
3349 this.renderEvent.fire();
3353 * Applies the Calendar's DOM listeners to applicable elements.
3354 * @method applyListeners
3356 applyListeners : function() {
3357 var root = this.oDomContainer,
3358 cal = this.parent || this,
3362 var linkLeft = Dom.getElementsByClassName(this.Style.CSS_NAV_LEFT, anchor, root),
3363 linkRight = Dom.getElementsByClassName(this.Style.CSS_NAV_RIGHT, anchor, root);
3365 if (linkLeft && linkLeft.length > 0) {
3366 this.linkLeft = linkLeft[0];
3367 Event.addListener(this.linkLeft, click, this.doPreviousMonthNav, cal, true);
3370 if (linkRight && linkRight.length > 0) {
3371 this.linkRight = linkRight[0];
3372 Event.addListener(this.linkRight, click, this.doNextMonthNav, cal, true);
3375 if (cal.cfg.getProperty("navigator") !== null) {
3376 this.applyNavListeners();
3379 if (this.domEventMap) {
3381 for (var cls in this.domEventMap) {
3382 if (Lang.hasOwnProperty(this.domEventMap, cls)) {
3383 var items = this.domEventMap[cls];
3385 if (! (items instanceof Array)) {
3389 for (var i=0;i<items.length;i++) {
3390 var item = items[i];
3391 elements = Dom.getElementsByClassName(cls, item.tag, this.oDomContainer);
3393 for (var c=0;c<elements.length;c++) {
3395 Event.addListener(el, item.event, item.handler, item.scope, item.correct );
3402 Event.addListener(this.oDomContainer, "click", this.doSelectCell, this);
3403 Event.addListener(this.oDomContainer, "mouseover", this.doCellMouseOver, this);
3404 Event.addListener(this.oDomContainer, "mouseout", this.doCellMouseOut, this);
3408 * Applies the DOM listeners to activate the Calendar Navigator.
3409 * @method applyNavListeners
3411 applyNavListeners : function() {
3412 var calParent = this.parent || this,
3414 navBtns = Dom.getElementsByClassName(this.Style.CSS_NAV, "a", this.oDomContainer);
3416 if (navBtns.length > 0) {
3418 Event.addListener(navBtns, "click", function (e, obj) {
3419 var target = Event.getTarget(e);
3421 if (this === target || Dom.isAncestor(this, target)) {
3422 Event.preventDefault(e);
3424 var navigator = calParent.oNavigator;
3426 var pgdate = cal.cfg.getProperty("pagedate");
3427 navigator.setYear(pgdate.getFullYear() + cal.Locale.YEAR_OFFSET);
3428 navigator.setMonth(pgdate.getMonth());
3436 * Retrieves the Date object for the specified Calendar cell
3437 * @method getDateByCellId
3438 * @param {String} id The id of the cell
3439 * @return {Date} The Date object for the specified Calendar cell
3441 getDateByCellId : function(id) {
3442 var date = this.getDateFieldsByCellId(id);
3443 return (date) ? DateMath.getDate(date[0],date[1]-1,date[2]) : null;
3447 * Retrieves the Date object for the specified Calendar cell
3448 * @method getDateFieldsByCellId
3449 * @param {String} id The id of the cell
3450 * @return {Array} The array of Date fields for the specified Calendar cell
3452 getDateFieldsByCellId : function(id) {
3453 id = this.getIndexFromId(id);
3454 return (id > -1) ? this.cellDates[id] : null;
3458 * Find the Calendar's cell index for a given date.
3459 * If the date is not found, the method returns -1.
3461 * The returned index can be used to lookup the cell HTMLElement
3462 * using the Calendar's cells array or passed to selectCell to select
3466 * See <a href="#cells">cells</a>, <a href="#selectCell">selectCell</a>.
3468 * @method getCellIndex
3469 * @param {Date} date JavaScript Date object, for which to find a cell index.
3470 * @return {Number} The index of the date in Calendars cellDates/cells arrays, or -1 if the date
3471 * is not on the curently rendered Calendar page.
3473 getCellIndex : function(date) {
3476 var m = date.getMonth(),
3477 y = date.getFullYear(),
3479 dates = this.cellDates;
3481 for (var i = 0; i < dates.length; ++i) {
3482 var cellDate = dates[i];
3483 if (cellDate[0] === y && cellDate[1] === m+1 && cellDate[2] === d) {
3493 * Given the id used to mark each Calendar cell, this method
3494 * extracts the index number from the id.
3496 * @param {String} strId The cell id
3497 * @return {Number} The index of the cell, or -1 if id does not contain an index number
3499 getIndexFromId : function(strId) {
3501 li = strId.lastIndexOf("_cell");
3504 idx = parseInt(strId.substring(li + 5), 10);
3510 // BEGIN BUILT-IN TABLE CELL RENDERERS
3513 * Renders a cell that falls before the minimum date or after the maximum date.
3514 * @method renderOutOfBoundsDate
3515 * @param {Date} workingDate The current working Date object being used to generate the calendar
3516 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3517 * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
3518 * should not be terminated
3520 renderOutOfBoundsDate : function(workingDate, cell) {
3521 Dom.addClass(cell, this.Style.CSS_CELL_OOB);
3522 cell.innerHTML = workingDate.getDate();
3523 return Calendar.STOP_RENDER;
3527 * Renders the row header HTML for a week.
3529 * @method renderRowHeader
3530 * @param {Number} weekNum The week number of the current row
3531 * @param {HTML[]} cell The current working HTML array
3533 renderRowHeader : function(weekNum, html) {
3534 html[html.length] = '<th class="' + this.Style.CSS_ROW_HEADER + '">' + weekNum + '</th>';
3539 * Renders the row footer HTML for a week.
3541 * @method renderRowFooter
3542 * @param {Number} weekNum The week number of the current row
3543 * @param {HTML[]} cell The current working HTML array
3545 renderRowFooter : function(weekNum, html) {
3546 html[html.length] = '<th class="' + this.Style.CSS_ROW_FOOTER + '">' + weekNum + '</th>';
3551 * Renders a single standard calendar cell in the calendar widget table.
3553 * All logic for determining how a standard default cell will be rendered is
3554 * encapsulated in this method, and must be accounted for when extending the
3557 * @method renderCellDefault
3558 * @param {Date} workingDate The current working Date object being used to generate the calendar
3559 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3561 renderCellDefault : function(workingDate, cell) {
3562 cell.innerHTML = '<a href="#" class="' + this.Style.CSS_CELL_SELECTOR + '">' + this.buildDayLabel(workingDate) + "</a>";
3566 * Styles a selectable cell.
3567 * @method styleCellDefault
3568 * @param {Date} workingDate The current working Date object being used to generate the calendar
3569 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3571 styleCellDefault : function(workingDate, cell) {
3572 Dom.addClass(cell, this.Style.CSS_CELL_SELECTABLE);
3577 * Renders a single standard calendar cell using the CSS hightlight1 style
3578 * @method renderCellStyleHighlight1
3579 * @param {Date} workingDate The current working Date object being used to generate the calendar
3580 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3582 renderCellStyleHighlight1 : function(workingDate, cell) {
3583 Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT1);
3587 * Renders a single standard calendar cell using the CSS hightlight2 style
3588 * @method renderCellStyleHighlight2
3589 * @param {Date} workingDate The current working Date object being used to generate the calendar
3590 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3592 renderCellStyleHighlight2 : function(workingDate, cell) {
3593 Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT2);
3597 * Renders a single standard calendar cell using the CSS hightlight3 style
3598 * @method renderCellStyleHighlight3
3599 * @param {Date} workingDate The current working Date object being used to generate the calendar
3600 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3602 renderCellStyleHighlight3 : function(workingDate, cell) {
3603 Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT3);
3607 * Renders a single standard calendar cell using the CSS hightlight4 style
3608 * @method renderCellStyleHighlight4
3609 * @param {Date} workingDate The current working Date object being used to generate the calendar
3610 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3612 renderCellStyleHighlight4 : function(workingDate, cell) {
3613 Dom.addClass(cell, this.Style.CSS_CELL_HIGHLIGHT4);
3617 * Applies the default style used for rendering today's date to the current calendar cell
3618 * @method renderCellStyleToday
3619 * @param {Date} workingDate The current working Date object being used to generate the calendar
3620 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3622 renderCellStyleToday : function(workingDate, cell) {
3623 Dom.addClass(cell, this.Style.CSS_CELL_TODAY);
3627 * Applies the default style used for rendering selected dates to the current calendar cell
3628 * @method renderCellStyleSelected
3629 * @param {Date} workingDate The current working Date object being used to generate the calendar
3630 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3631 * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
3632 * should not be terminated
3634 renderCellStyleSelected : function(workingDate, cell) {
3635 Dom.addClass(cell, this.Style.CSS_CELL_SELECTED);
3639 * Applies the default style used for rendering dates that are not a part of the current
3640 * month (preceding or trailing the cells for the current month)
3642 * @method renderCellNotThisMonth
3643 * @param {Date} workingDate The current working Date object being used to generate the calendar
3644 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3645 * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
3646 * should not be terminated
3648 renderCellNotThisMonth : function(workingDate, cell) {
3649 this.styleCellNotThisMonth(workingDate, cell);
3650 cell.innerHTML=workingDate.getDate();
3651 return Calendar.STOP_RENDER;
3654 /** Applies the style used for rendering out-of-month dates to the current calendar cell
3655 * @method styleCellNotThisMonth
3656 * @param {Date} workingDate The current working Date object being used to generate the calendar
3657 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3659 styleCellNotThisMonth : function(workingDate, cell) {
3660 YAHOO.util.Dom.addClass(cell, this.Style.CSS_CELL_OOM);
3664 * Renders the current calendar cell as a non-selectable "black-out" date using the default
3666 * @method renderBodyCellRestricted
3667 * @param {Date} workingDate The current working Date object being used to generate the calendar
3668 * @param {HTMLTableCellElement} cell The current working cell in the calendar
3669 * @return {String} YAHOO.widget.Calendar.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
3670 * should not be terminated
3672 renderBodyCellRestricted : function(workingDate, cell) {
3673 Dom.addClass(cell, this.Style.CSS_CELL);
3674 Dom.addClass(cell, this.Style.CSS_CELL_RESTRICTED);
3675 cell.innerHTML=workingDate.getDate();
3676 return Calendar.STOP_RENDER;
3679 // END BUILT-IN TABLE CELL RENDERERS
3681 // BEGIN MONTH NAVIGATION METHODS
3684 * Adds the designated number of months to the current calendar month, and sets the current
3685 * calendar page date to the new month.
3687 * @param {Number} count The number of months to add to the current calendar
3689 addMonths : function(count) {
3690 var cfgPageDate = DEF_CFG.PAGEDATE.key,
3692 prevDate = this.cfg.getProperty(cfgPageDate),
3693 newDate = DateMath.add(prevDate, DateMath.MONTH, count);
3695 this.cfg.setProperty(cfgPageDate, newDate);
3696 this.resetRenderers();
3697 this.changePageEvent.fire(prevDate, newDate);
3701 * Subtracts the designated number of months from the current calendar month, and sets the current
3702 * calendar page date to the new month.
3703 * @method subtractMonths
3704 * @param {Number} count The number of months to subtract from the current calendar
3706 subtractMonths : function(count) {
3707 this.addMonths(-1*count);
3711 * Adds the designated number of years to the current calendar, and sets the current
3712 * calendar page date to the new month.
3714 * @param {Number} count The number of years to add to the current calendar
3716 addYears : function(count) {
3717 var cfgPageDate = DEF_CFG.PAGEDATE.key,
3719 prevDate = this.cfg.getProperty(cfgPageDate),
3720 newDate = DateMath.add(prevDate, DateMath.YEAR, count);
3722 this.cfg.setProperty(cfgPageDate, newDate);
3723 this.resetRenderers();
3724 this.changePageEvent.fire(prevDate, newDate);
3728 * Subtcats the designated number of years from the current calendar, and sets the current
3729 * calendar page date to the new month.
3730 * @method subtractYears
3731 * @param {Number} count The number of years to subtract from the current calendar
3733 subtractYears : function(count) {
3734 this.addYears(-1*count);
3738 * Navigates to the next month page in the calendar widget.
3741 nextMonth : function() {
3746 * Navigates to the previous month page in the calendar widget.
3747 * @method previousMonth
3749 previousMonth : function() {
3754 * Navigates to the next year in the currently selected month in the calendar widget.
3757 nextYear : function() {
3762 * Navigates to the previous year in the currently selected month in the calendar widget.
3763 * @method previousYear
3765 previousYear : function() {
3769 // END MONTH NAVIGATION METHODS
3771 // BEGIN SELECTION METHODS
3774 * Resets the calendar widget to the originally selected month and year, and
3775 * sets the calendar to the initial selection(s).
3778 reset : function() {
3779 this.cfg.resetProperty(DEF_CFG.SELECTED.key);
3780 this.cfg.resetProperty(DEF_CFG.PAGEDATE.key);
3781 this.resetEvent.fire();
3785 * Clears the selected dates in the current calendar widget and sets the calendar
3786 * to the current month and year.
3789 clear : function() {
3790 this.cfg.setProperty(DEF_CFG.SELECTED.key, []);
3791 this.cfg.setProperty(DEF_CFG.PAGEDATE.key, new Date(this.today.getTime()));
3792 this.clearEvent.fire();
3796 * Selects a date or a collection of dates on the current calendar. This method, by default,
3797 * does not call the render method explicitly. Once selection has completed, render must be
3798 * called for the changes to be reflected visually.
3800 * Any dates which are OOB (out of bounds, not selectable) will not be selected and the array of
3801 * selected dates passed to the selectEvent will not contain OOB dates.
3803 * If all dates are OOB, the no state change will occur; beforeSelect and select events will not be fired.
3806 * @param {String/Date/Date[]} date The date string of dates to select in the current calendar. Valid formats are
3807 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
3808 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
3809 * This method can also take a JavaScript Date object or an array of Date objects.
3810 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
3812 select : function(date) {
3814 var aToBeSelected = this._toFieldArray(date),
3817 cfgSelected = DEF_CFG.SELECTED.key;
3820 for (var a=0; a < aToBeSelected.length; ++a) {
3821 var toSelect = aToBeSelected[a];
3823 if (!this.isDateOOB(this._toDate(toSelect))) {
3825 if (validDates.length === 0) {
3826 this.beforeSelectEvent.fire();
3827 selected = this.cfg.getProperty(cfgSelected);
3829 validDates.push(toSelect);
3831 if (this._indexOfSelectedFieldArray(toSelect) == -1) {
3832 selected[selected.length] = toSelect;
3838 if (validDates.length > 0) {
3840 this.parent.cfg.setProperty(cfgSelected, selected);
3842 this.cfg.setProperty(cfgSelected, selected);
3844 this.selectEvent.fire(validDates);
3847 return this.getSelectedDates();
3851 * Selects a date on the current calendar by referencing the index of the cell that should be selected.
3852 * This method is used to easily select a single cell (usually with a mouse click) without having to do
3853 * a full render. The selected style is applied to the cell directly.
3855 * If the cell is not marked with the CSS_CELL_SELECTABLE class (as is the case by default for out of month
3856 * or out of bounds cells), it will not be selected and in such a case beforeSelect and select events will not be fired.
3858 * @method selectCell
3859 * @param {Number} cellIndex The index of the cell to select in the current calendar.
3860 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
3862 selectCell : function(cellIndex) {
3864 var cell = this.cells[cellIndex],
3865 cellDate = this.cellDates[cellIndex],
3866 dCellDate = this._toDate(cellDate),
3867 selectable = Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
3872 this.beforeSelectEvent.fire();
3874 var cfgSelected = DEF_CFG.SELECTED.key;
3875 var selected = this.cfg.getProperty(cfgSelected);
3877 var selectDate = cellDate.concat();
3879 if (this._indexOfSelectedFieldArray(selectDate) == -1) {
3880 selected[selected.length] = selectDate;
3883 this.parent.cfg.setProperty(cfgSelected, selected);
3885 this.cfg.setProperty(cfgSelected, selected);
3887 this.renderCellStyleSelected(dCellDate,cell);
3888 this.selectEvent.fire([selectDate]);
3890 this.doCellMouseOut.call(cell, null, this);
3893 return this.getSelectedDates();
3897 * Deselects a date or a collection of dates on the current calendar. This method, by default,
3898 * does not call the render method explicitly. Once deselection has completed, render must be
3899 * called for the changes to be reflected visually.
3901 * The method will not attempt to deselect any dates which are OOB (out of bounds, and hence not selectable)
3902 * and the array of deselected dates passed to the deselectEvent will not contain any OOB dates.
3904 * If all dates are OOB, beforeDeselect and deselect events will not be fired.
3907 * @param {String/Date/Date[]} date The date string of dates to deselect in the current calendar. Valid formats are
3908 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
3909 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
3910 * This method can also take a JavaScript Date object or an array of Date objects.
3911 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
3913 deselect : function(date) {
3915 var aToBeDeselected = this._toFieldArray(date),
3918 cfgSelected = DEF_CFG.SELECTED.key;
3921 for (var a=0; a < aToBeDeselected.length; ++a) {
3922 var toDeselect = aToBeDeselected[a];
3924 if (!this.isDateOOB(this._toDate(toDeselect))) {
3926 if (validDates.length === 0) {
3927 this.beforeDeselectEvent.fire();
3928 selected = this.cfg.getProperty(cfgSelected);
3931 validDates.push(toDeselect);
3933 var index = this._indexOfSelectedFieldArray(toDeselect);
3935 selected.splice(index,1);
3941 if (validDates.length > 0) {
3943 this.parent.cfg.setProperty(cfgSelected, selected);
3945 this.cfg.setProperty(cfgSelected, selected);
3947 this.deselectEvent.fire(validDates);
3950 return this.getSelectedDates();
3954 * Deselects a date on the current calendar by referencing the index of the cell that should be deselected.
3955 * This method is used to easily deselect a single cell (usually with a mouse click) without having to do
3956 * a full render. The selected style is removed from the cell directly.
3958 * If the cell is not marked with the CSS_CELL_SELECTABLE class (as is the case by default for out of month
3959 * or out of bounds cells), the method will not attempt to deselect it and in such a case, beforeDeselect and
3960 * deselect events will not be fired.
3962 * @method deselectCell
3963 * @param {Number} cellIndex The index of the cell to deselect in the current calendar.
3964 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
3966 deselectCell : function(cellIndex) {
3967 var cell = this.cells[cellIndex],
3968 cellDate = this.cellDates[cellIndex],
3969 cellDateIndex = this._indexOfSelectedFieldArray(cellDate);
3971 var selectable = Dom.hasClass(cell, this.Style.CSS_CELL_SELECTABLE);
3975 this.beforeDeselectEvent.fire();
3977 var selected = this.cfg.getProperty(DEF_CFG.SELECTED.key),
3978 dCellDate = this._toDate(cellDate),
3979 selectDate = cellDate.concat();
3981 if (cellDateIndex > -1) {
3982 if ((this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getMonth() == dCellDate.getMonth() &&
3983 this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getFullYear() == dCellDate.getFullYear()) || this.cfg.getProperty(DEF_CFG.OOM_SELECT.key)) {
3984 Dom.removeClass(cell, this.Style.CSS_CELL_SELECTED);
3986 selected.splice(cellDateIndex, 1);
3990 this.parent.cfg.setProperty(DEF_CFG.SELECTED.key, selected);
3992 this.cfg.setProperty(DEF_CFG.SELECTED.key, selected);
3995 this.deselectEvent.fire([selectDate]);
3998 return this.getSelectedDates();
4002 * Deselects all dates on the current calendar.
4003 * @method deselectAll
4004 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
4005 * Assuming that this function executes properly, the return value should be an empty array.
4006 * However, the empty array is returned for the sake of being able to check the selection status
4009 deselectAll : function() {
4010 this.beforeDeselectEvent.fire();
4012 var cfgSelected = DEF_CFG.SELECTED.key,
4013 selected = this.cfg.getProperty(cfgSelected),
4014 count = selected.length,
4015 sel = selected.concat();
4018 this.parent.cfg.setProperty(cfgSelected, []);
4020 this.cfg.setProperty(cfgSelected, []);
4024 this.deselectEvent.fire(sel);
4027 return this.getSelectedDates();
4030 // END SELECTION METHODS
4032 // BEGIN TYPE CONVERSION METHODS
4035 * Converts a date (either a JavaScript Date object, or a date string) to the internal data structure
4036 * used to represent dates: [[yyyy,mm,dd],[yyyy,mm,dd]].
4037 * @method _toFieldArray
4039 * @param {String/Date/Date[]} date The date string of dates to deselect in the current calendar. Valid formats are
4040 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
4041 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
4042 * This method can also take a JavaScript Date object or an array of Date objects.
4043 * @return {Array[](Number[])} Array of date field arrays
4045 _toFieldArray : function(date) {
4046 var returnDate = [];
4048 if (date instanceof Date) {
4049 returnDate = [[date.getFullYear(), date.getMonth()+1, date.getDate()]];
4050 } else if (Lang.isString(date)) {
4051 returnDate = this._parseDates(date);
4052 } else if (Lang.isArray(date)) {
4053 for (var i=0;i<date.length;++i) {
4055 returnDate[returnDate.length] = [d.getFullYear(),d.getMonth()+1,d.getDate()];
4063 * Converts a date field array [yyyy,mm,dd] to a JavaScript Date object. The date field array
4064 * is the format in which dates are as provided as arguments to selectEvent and deselectEvent listeners.
4067 * @param {Number[]} dateFieldArray The date field array to convert to a JavaScript Date.
4068 * @return {Date} JavaScript Date object representing the date field array.
4070 toDate : function(dateFieldArray) {
4071 return this._toDate(dateFieldArray);
4075 * Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
4078 * @deprecated Made public, toDate
4079 * @param {Number[]} dateFieldArray The date field array to convert to a JavaScript Date.
4080 * @return {Date} JavaScript Date object representing the date field array
4082 _toDate : function(dateFieldArray) {
4083 if (dateFieldArray instanceof Date) {
4084 return dateFieldArray;
4086 return DateMath.getDate(dateFieldArray[0],dateFieldArray[1]-1,dateFieldArray[2]);
4090 // END TYPE CONVERSION METHODS
4092 // BEGIN UTILITY METHODS
4095 * Determines if 2 field arrays are equal.
4096 * @method _fieldArraysAreEqual
4098 * @param {Number[]} array1 The first date field array to compare
4099 * @param {Number[]} array2 The first date field array to compare
4100 * @return {Boolean} The boolean that represents the equality of the two arrays
4102 _fieldArraysAreEqual : function(array1, array2) {
4105 if (array1[0]==array2[0]&&array1[1]==array2[1]&&array1[2]==array2[2]) {
4113 * Gets the index of a date field array [yyyy,mm,dd] in the current list of selected dates.
4114 * @method _indexOfSelectedFieldArray
4116 * @param {Number[]} find The date field array to search for
4117 * @return {Number} The index of the date field array within the collection of selected dates.
4118 * -1 will be returned if the date is not found.
4120 _indexOfSelectedFieldArray : function(find) {
4122 seldates = this.cfg.getProperty(DEF_CFG.SELECTED.key);
4124 for (var s=0;s<seldates.length;++s) {
4125 var sArray = seldates[s];
4126 if (find[0]==sArray[0]&&find[1]==sArray[1]&&find[2]==sArray[2]) {
4136 * Determines whether a given date is OOM (out of month).
4138 * @param {Date} date The JavaScript Date object for which to check the OOM status
4139 * @return {Boolean} true if the date is OOM
4141 isDateOOM : function(date) {
4142 return (date.getMonth() != this.cfg.getProperty(DEF_CFG.PAGEDATE.key).getMonth());
4146 * Determines whether a given date is OOB (out of bounds - less than the mindate or more than the maxdate).
4149 * @param {Date} date The JavaScript Date object for which to check the OOB status
4150 * @return {Boolean} true if the date is OOB
4152 isDateOOB : function(date) {
4153 var minDate = this.cfg.getProperty(DEF_CFG.MINDATE.key),
4154 maxDate = this.cfg.getProperty(DEF_CFG.MAXDATE.key),
4158 minDate = dm.clearTime(minDate);
4161 maxDate = dm.clearTime(maxDate);
4164 var clearedDate = new Date(date.getTime());
4165 clearedDate = dm.clearTime(clearedDate);
4167 return ((minDate && clearedDate.getTime() < minDate.getTime()) || (maxDate && clearedDate.getTime() > maxDate.getTime()));
4171 * Parses a pagedate configuration property value. The value can either be specified as a string of form "mm/yyyy" or a Date object
4172 * 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
4173 * @method _parsePageDate
4175 * @param {Date|String} date Pagedate value which needs to be parsed
4176 * @return {Date} The Date object representing the pagedate
4178 _parsePageDate : function(date) {
4182 if (date instanceof Date) {
4183 parsedDate = DateMath.findMonthStart(date);
4185 var month, year, aMonthYear;
4186 aMonthYear = date.split(this.cfg.getProperty(DEF_CFG.DATE_FIELD_DELIMITER.key));
4187 month = parseInt(aMonthYear[this.cfg.getProperty(DEF_CFG.MY_MONTH_POSITION.key)-1], 10)-1;
4188 year = parseInt(aMonthYear[this.cfg.getProperty(DEF_CFG.MY_YEAR_POSITION.key)-1], 10) - this.Locale.YEAR_OFFSET;
4190 parsedDate = DateMath.getDate(year, month, 1);
4193 parsedDate = DateMath.getDate(this.today.getFullYear(), this.today.getMonth(), 1);
4198 // END UTILITY METHODS
4200 // BEGIN EVENT HANDLERS
4203 * Event executed before a date is selected in the calendar widget.
4204 * @deprecated Event handlers for this event should be susbcribed to beforeSelectEvent.
4206 onBeforeSelect : function() {
4207 if (this.cfg.getProperty(DEF_CFG.MULTI_SELECT.key) === false) {
4209 this.parent.callChildFunction("clearAllBodyCellStyles", this.Style.CSS_CELL_SELECTED);
4210 this.parent.deselectAll();
4212 this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);
4219 * Event executed when a date is selected in the calendar widget.
4220 * @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] ]
4221 * @deprecated Event handlers for this event should be susbcribed to selectEvent.
4223 onSelect : function(selected) { },
4226 * Event executed before a date is deselected in the calendar widget.
4227 * @deprecated Event handlers for this event should be susbcribed to beforeDeselectEvent.
4229 onBeforeDeselect : function() { },
4232 * Event executed when a date is deselected in the calendar widget.
4233 * @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] ]
4234 * @deprecated Event handlers for this event should be susbcribed to deselectEvent.
4236 onDeselect : function(deselected) { },
4239 * Event executed when the user navigates to a different calendar page.
4240 * @deprecated Event handlers for this event should be susbcribed to changePageEvent.
4242 onChangePage : function() {
4247 * Event executed when the calendar widget is rendered.
4248 * @deprecated Event handlers for this event should be susbcribed to renderEvent.
4250 onRender : function() { },
4253 * Event executed when the calendar widget is reset to its original state.
4254 * @deprecated Event handlers for this event should be susbcribed to resetEvemt.
4256 onReset : function() { this.render(); },
4259 * Event executed when the calendar widget is completely cleared to the current month with no selections.
4260 * @deprecated Event handlers for this event should be susbcribed to clearEvent.
4262 onClear : function() { this.render(); },
4265 * Validates the calendar widget. This method has no default implementation
4266 * and must be extended by subclassing the widget.
4267 * @return Should return true if the widget validates, and false if
4271 validate : function() { return true; },
4273 // END EVENT HANDLERS
4275 // BEGIN DATE PARSE METHODS
4278 * Converts a date string to a date field array
4280 * @param {String} sDate Date string. Valid formats are mm/dd and mm/dd/yyyy.
4281 * @return A date field array representing the string passed to the method
4282 * @type Array[](Number[])
4284 _parseDate : function(sDate) {
4285 var aDate = sDate.split(this.Locale.DATE_FIELD_DELIMITER),
4288 if (aDate.length == 2) {
4289 rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
4290 rArray.type = Calendar.MONTH_DAY;
4292 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]];
4293 rArray.type = Calendar.DATE;
4296 for (var i=0;i<rArray.length;i++) {
4297 rArray[i] = parseInt(rArray[i], 10);
4304 * Converts a multi or single-date string to an array of date field arrays
4306 * @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
4307 * @return An array of date field arrays
4308 * @type Array[](Number[])
4310 _parseDates : function(sDates) {
4312 aDates = sDates.split(this.Locale.DATE_DELIMITER);
4314 for (var d=0;d<aDates.length;++d) {
4315 var sDate = aDates[d];
4317 if (sDate.indexOf(this.Locale.DATE_RANGE_DELIMITER) != -1) {
4319 var aRange = sDate.split(this.Locale.DATE_RANGE_DELIMITER),
4320 dateStart = this._parseDate(aRange[0]),
4321 dateEnd = this._parseDate(aRange[1]),
4322 fullRange = this._parseRange(dateStart, dateEnd);
4324 aReturn = aReturn.concat(fullRange);
4326 // This is not a range
4327 var aDate = this._parseDate(sDate);
4328 aReturn.push(aDate);
4335 * Converts a date range to the full list of included dates
4337 * @param {Number[]} startDate Date field array representing the first date in the range
4338 * @param {Number[]} endDate Date field array representing the last date in the range
4339 * @return An array of date field arrays
4340 * @type Array[](Number[])
4342 _parseRange : function(startDate, endDate) {
4343 var dCurrent = DateMath.add(DateMath.getDate(startDate[0],startDate[1]-1,startDate[2]),DateMath.DAY,1),
4344 dEnd = DateMath.getDate(endDate[0], endDate[1]-1, endDate[2]),
4347 results.push(startDate);
4348 while (dCurrent.getTime() <= dEnd.getTime()) {
4349 results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
4350 dCurrent = DateMath.add(dCurrent,DateMath.DAY,1);
4355 // END DATE PARSE METHODS
4357 // BEGIN RENDERER METHODS
4360 * Resets the render stack of the current calendar to its original pre-render value.
4362 resetRenderers : function() {
4363 this.renderStack = this._renderStack.concat();
4367 * Removes all custom renderers added to the Calendar through the addRenderer, addMonthRenderer and
4368 * addWeekdayRenderer methods. Calendar's render method needs to be called after removing renderers
4369 * to re-render the Calendar without custom renderers applied.
4371 removeRenderers : function() {
4372 this._renderStack = [];
4373 this.renderStack = [];
4377 * Clears the inner HTML, CSS class and style information from the specified cell.
4378 * @method clearElement
4379 * @param {HTMLTableCellElement} cell The cell to clear
4381 clearElement : function(cell) {
4382 cell.innerHTML = " ";
4387 * Adds a renderer to the render stack. The function reference passed to this method will be executed
4388 * when a date cell matches the conditions specified in the date string for this renderer.
4390 * <p>NOTE: The contents of the cell set by the renderer will be added to the DOM as HTML. The custom renderer implementation should
4391 * escape markup used to set the cell contents, if coming from an external source.<p>
4392 * @method addRenderer
4393 * @param {String} sDates A date string to associate with the specified renderer. Valid formats
4394 * include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
4395 * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
4397 addRenderer : function(sDates, fnRender) {
4398 var aDates = this._parseDates(sDates);
4399 for (var i=0;i<aDates.length;++i) {
4400 var aDate = aDates[i];
4402 if (aDate.length == 2) { // this is either a range or a month/day combo
4403 if (aDate[0] instanceof Array) { // this is a range
4404 this._addRenderer(Calendar.RANGE,aDate,fnRender);
4405 } else { // this is a month/day combo
4406 this._addRenderer(Calendar.MONTH_DAY,aDate,fnRender);
4408 } else if (aDate.length == 3) {
4409 this._addRenderer(Calendar.DATE,aDate,fnRender);
4415 * The private method used for adding cell renderers to the local render stack.
4416 * This method is called by other methods that set the renderer type prior to the method call.
4417 * @method _addRenderer
4419 * @param {String} type The type string that indicates the type of date renderer being added.
4420 * Values are YAHOO.widget.Calendar.DATE, YAHOO.widget.Calendar.MONTH_DAY, YAHOO.widget.Calendar.WEEKDAY,
4421 * YAHOO.widget.Calendar.RANGE, YAHOO.widget.Calendar.MONTH
4422 * @param {Array} aDates An array of dates used to construct the renderer. The format varies based
4423 * on the renderer type
4424 * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
4426 _addRenderer : function(type, aDates, fnRender) {
4427 var add = [type,aDates,fnRender];
4428 this.renderStack.unshift(add);
4429 this._renderStack = this.renderStack.concat();
4433 * Adds a month renderer to the render stack. The function reference passed to this method will be executed
4434 * when a date cell matches the month passed to this method
4436 * <p>NOTE: The contents of the cell set by the renderer will be added to the DOM as HTML. The custom renderer implementation should
4437 * escape markup used to set the cell contents, if coming from an external source.<p>
4438 * @method addMonthRenderer
4439 * @param {Number} month The month (1-12) to associate with this renderer
4440 * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
4442 addMonthRenderer : function(month, fnRender) {
4443 this._addRenderer(Calendar.MONTH,[month],fnRender);
4447 * Adds a weekday renderer to the render stack. The function reference passed to this method will be executed
4448 * when a date cell matches the weekday passed to this method.
4450 * <p>NOTE: The contents of the cell set by the renderer will be added to the DOM as HTML. The custom renderer implementation should
4451 * escape HTML used to set the cell contents, if coming from an external source.<p>
4453 * @method addWeekdayRenderer
4454 * @param {Number} weekday The weekday (Sunday = 1, Monday = 2 ... Saturday = 7) to associate with this renderer
4455 * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
4457 addWeekdayRenderer : function(weekday, fnRender) {
4458 this._addRenderer(Calendar.WEEKDAY,[weekday],fnRender);
4461 // END RENDERER METHODS
4463 // BEGIN CSS METHODS
4466 * Removes all styles from all body cells in the current calendar table.
4467 * @method clearAllBodyCellStyles
4468 * @param {style} style The CSS class name to remove from all calendar body cells
4470 clearAllBodyCellStyles : function(style) {
4471 for (var c=0;c<this.cells.length;++c) {
4472 Dom.removeClass(this.cells[c],style);
4478 // BEGIN GETTER/SETTER METHODS
4480 * Sets the calendar's month explicitly
4482 * @param {Number} month The numeric month, from 0 (January) to 11 (December)
4484 setMonth : function(month) {
4485 var cfgPageDate = DEF_CFG.PAGEDATE.key,
4486 current = this.cfg.getProperty(cfgPageDate);
4487 current.setMonth(parseInt(month, 10));
4488 this.cfg.setProperty(cfgPageDate, current);
4492 * Sets the calendar's year explicitly.
4494 * @param {Number} year The numeric 4-digit year
4496 setYear : function(year) {
4497 var cfgPageDate = DEF_CFG.PAGEDATE.key,
4498 current = this.cfg.getProperty(cfgPageDate);
4500 current.setFullYear(parseInt(year, 10) - this.Locale.YEAR_OFFSET);
4501 this.cfg.setProperty(cfgPageDate, current);
4505 * Gets the list of currently selected dates from the calendar.
4506 * @method getSelectedDates
4507 * @return {Date[]} An array of currently selected JavaScript Date objects.
4509 getSelectedDates : function() {
4510 var returnDates = [],
4511 selected = this.cfg.getProperty(DEF_CFG.SELECTED.key);
4513 for (var d=0;d<selected.length;++d) {
4514 var dateArray = selected[d];
4516 var date = DateMath.getDate(dateArray[0],dateArray[1]-1,dateArray[2]);
4517 returnDates.push(date);
4520 returnDates.sort( function(a,b) { return a-b; } );
4524 /// END GETTER/SETTER METHODS ///
4527 * Hides the Calendar's outer container from view.
4531 if (this.beforeHideEvent.fire()) {
4532 this.oDomContainer.style.display = "none";
4533 this.hideEvent.fire();
4538 * Shows the Calendar's outer container.
4542 if (this.beforeShowEvent.fire()) {
4543 this.oDomContainer.style.display = "block";
4544 this.showEvent.fire();
4549 * Returns a string representing the current browser.
4550 * @deprecated As of 2.3.0, environment information is available in YAHOO.env.ua
4555 browser : (function() {
4556 var ua = navigator.userAgent.toLowerCase();
4557 if (ua.indexOf('opera')!=-1) { // Opera (check first in case of spoof)
4559 } else if (ua.indexOf('msie 7')!=-1) { // IE7
4561 } else if (ua.indexOf('msie') !=-1) { // IE
4563 } else if (ua.indexOf('safari')!=-1) { // Safari (check before Gecko because it includes "like Gecko")
4565 } else if (ua.indexOf('gecko') != -1) { // Gecko
4572 * Returns a string representation of the object.
4574 * @return {String} A string representation of the Calendar object.
4576 toString : function() {
4577 return "Calendar " + this.id;
4581 * Destroys the Calendar instance. The method will remove references
4582 * to HTML elements, remove any event listeners added by the Calendar,
4583 * and destroy the Config and CalendarNavigator instances it has created.
4587 destroy : function() {
4589 if (this.beforeDestroyEvent.fire()) {
4593 if (cal.navigator) {
4594 cal.navigator.destroy();
4601 // DOM event listeners
4602 Event.purgeElement(cal.oDomContainer, true);
4604 // Generated markup/DOM - Not removing the container DIV since we didn't create it.
4605 Dom.removeClass(cal.oDomContainer, cal.Style.CSS_WITH_TITLE);
4606 Dom.removeClass(cal.oDomContainer, cal.Style.CSS_CONTAINER);
4607 Dom.removeClass(cal.oDomContainer, cal.Style.CSS_SINGLE);
4608 cal.oDomContainer.innerHTML = "";
4610 // JS-to-DOM references
4611 cal.oDomContainer = null;
4614 this.destroyEvent.fire();
4619 YAHOO.widget.Calendar = Calendar;
4622 * @namespace YAHOO.widget
4623 * @class Calendar_Core
4624 * @extends YAHOO.widget.Calendar
4625 * @deprecated The old Calendar_Core class is no longer necessary.
4627 YAHOO.widget.Calendar_Core = YAHOO.widget.Calendar;
4629 YAHOO.widget.Cal_Core = YAHOO.widget.Calendar;
4634 var Dom = YAHOO.util.Dom,
4635 DateMath = YAHOO.widget.DateMath,
4636 Event = YAHOO.util.Event,
4638 Calendar = YAHOO.widget.Calendar;
4641 * YAHOO.widget.CalendarGroup is a special container class for YAHOO.widget.Calendar. This class facilitates
4642 * the ability to have multi-page calendar views that share a single dataset and are
4643 * dependent on each other.
4645 * The calendar group instance will refer to each of its elements using a 0-based index.
4646 * For example, to construct the placeholder for a calendar group widget with id "cal1" and
4647 * containerId of "cal1Container", the markup would be as follows:
4649 * <div id="cal1Container_0"></div>
4650 * <div id="cal1Container_1"></div>
4652 * The tables for the calendars ("cal1_0" and "cal1_1") will be inserted into those containers.
4655 * <strong>NOTE: As of 2.4.0, the constructor's ID argument is optional.</strong>
4656 * The CalendarGroup can be constructed by simply providing a container ID string,
4657 * or a reference to a container DIV HTMLElement (the element needs to exist
4662 * var c = new YAHOO.widget.CalendarGroup("calContainer", configOptions);
4666 * var containerDiv = YAHOO.util.Dom.get("calContainer");
4667 * var c = new YAHOO.widget.CalendarGroup(containerDiv, configOptions);
4671 * If not provided, the ID will be generated from the container DIV ID by adding an "_t" suffix.
4672 * 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".
4675 * @namespace YAHOO.widget
4676 * @class CalendarGroup
4678 * @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.
4679 * @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.
4680 * @param {Object} config optional The configuration object containing the initial configuration values for the CalendarGroup.
4682 function CalendarGroup(id, containerId, config) {
4683 if (arguments.length > 0) {
4684 this.init.apply(this, arguments);
4689 * The set of default Config property keys and values for the CalendarGroup.
4692 * NOTE: This property is made public in order to allow users to change
4693 * the default values of configuration properties. Users should not
4694 * modify the key string, unless they are overriding the Calendar implementation
4697 * @property YAHOO.widget.CalendarGroup.DEFAULT_CONFIG
4699 * @type Object An object with key/value pairs, the key being the
4700 * uppercase configuration property name and the value being an objec
4701 * literal with a key string property, and a value property, specifying the
4702 * default value of the property
4706 * The set of default Config property keys and values for the CalendarGroup
4707 * @property YAHOO.widget.CalendarGroup._DEFAULT_CONFIG
4708 * @deprecated Made public. See the public DEFAULT_CONFIG property for details
4713 CalendarGroup.DEFAULT_CONFIG = CalendarGroup._DEFAULT_CONFIG = Calendar.DEFAULT_CONFIG;
4714 CalendarGroup.DEFAULT_CONFIG.PAGES = {key:"pages", value:2};
4716 var DEF_CFG = CalendarGroup.DEFAULT_CONFIG;
4718 CalendarGroup.prototype = {
4721 * Initializes the calendar group. All subclasses must call this method in order for the
4722 * group to be initialized properly.
4724 * @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.
4725 * @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.
4726 * @param {Object} config optional The configuration object containing the initial configuration values for the CalendarGroup.
4728 init : function(id, container, config) {
4730 // Normalize 2.4.0, pre 2.4.0 args
4731 var nArgs = this._parseArgs(arguments);
4734 container = nArgs.container;
4735 config = nArgs.config;
4737 this.oDomContainer = Dom.get(container);
4739 if (!this.oDomContainer.id) {
4740 this.oDomContainer.id = Dom.generateId();
4743 id = this.oDomContainer.id + "_t";
4747 * The unique id associated with the CalendarGroup
4754 * The unique id associated with the CalendarGroup container
4755 * @property containerId
4758 this.containerId = this.oDomContainer.id;
4764 * The collection of Calendar pages contained within the CalendarGroup
4766 * @type YAHOO.widget.Calendar[]
4770 Dom.addClass(this.oDomContainer, CalendarGroup.CSS_CONTAINER);
4771 Dom.addClass(this.oDomContainer, CalendarGroup.CSS_MULTI_UP);
4774 * The Config object used to hold the configuration variables for the CalendarGroup
4776 * @type YAHOO.util.Config
4778 this.cfg = new YAHOO.util.Config(this);
4781 * The local object which contains the CalendarGroup's options
4788 * The local object which contains the CalendarGroup's locale settings
4797 this.cfg.applyConfig(config, true);
4800 this.cfg.fireQueue();
4804 setupConfig : function() {
4809 * The number of pages to include in the CalendarGroup. This value can only be set once, in the CalendarGroup's constructor arguments.
4814 cfg.addProperty(DEF_CFG.PAGES.key, { value:DEF_CFG.PAGES.value, validator:cfg.checkNumber, handler:this.configPages } );
4817 * The positive or negative year offset from the Gregorian calendar year (assuming a January 1st rollover) to
4818 * be used when displaying or parsing dates. NOTE: All JS Date objects returned by methods, or expected as input by
4819 * methods will always represent the Gregorian year, in order to maintain date/month/week values.
4821 * @config year_offset
4825 cfg.addProperty(DEF_CFG.YEAR_OFFSET.key, { value:DEF_CFG.YEAR_OFFSET.value, handler: this.delegateConfig, supercedes:DEF_CFG.YEAR_OFFSET.supercedes, suppressEvent:true } );
4828 * The date to use to represent "Today".
4832 * @default Today's date
4834 cfg.addProperty(DEF_CFG.TODAY.key, { value: new Date(DEF_CFG.TODAY.value.getTime()), supercedes:DEF_CFG.TODAY.supercedes, handler: this.configToday, suppressEvent:false } );
4837 * The month/year representing the current visible Calendar date (mm/yyyy)
4839 * @type String | Date
4840 * @default Today's date
4842 cfg.addProperty(DEF_CFG.PAGEDATE.key, { value: DEF_CFG.PAGEDATE.value || new Date(DEF_CFG.TODAY.value.getTime()), handler:this.configPageDate } );
4845 * The date or range of dates representing the current Calendar selection
4851 cfg.addProperty(DEF_CFG.SELECTED.key, { value:[], handler:this.configSelected } );
4854 * 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 cfg.addProperty(DEF_CFG.TITLE.key, { value:DEF_CFG.TITLE.value, handler:this.configTitle } );
4862 * Whether or not a close button should be displayed for this CalendarGroup
4867 cfg.addProperty(DEF_CFG.CLOSE.key, { value:DEF_CFG.CLOSE.value, handler:this.configClose } );
4870 * 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.
4871 * This property is enabled by default for IE6 and below. It is disabled by default for other browsers for performance reasons, but can be
4872 * enabled if required.
4876 * @default true for IE6 and below, false for all other browsers
4878 cfg.addProperty(DEF_CFG.IFRAME.key, { value:DEF_CFG.IFRAME.value, handler:this.configIframe, validator:cfg.checkBoolean } );
4881 * The minimum selectable date in the current Calendar (mm/dd/yyyy)
4883 * @type String | Date
4886 cfg.addProperty(DEF_CFG.MINDATE.key, { value:DEF_CFG.MINDATE.value, handler:this.delegateConfig } );
4889 * The maximum selectable date in the current Calendar (mm/dd/yyyy)
4891 * @type String | Date
4894 cfg.addProperty(DEF_CFG.MAXDATE.key, { value:DEF_CFG.MAXDATE.value, handler:this.delegateConfig } );
4897 * True if the Calendar should allow multiple selections. False by default.
4898 * @config MULTI_SELECT
4902 cfg.addProperty(DEF_CFG.MULTI_SELECT.key, { value:DEF_CFG.MULTI_SELECT.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4905 * True if the Calendar should allow selection of out-of-month dates. False by default.
4906 * @config OOM_SELECT
4910 cfg.addProperty(DEF_CFG.OOM_SELECT.key, { value:DEF_CFG.OOM_SELECT.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4913 * The weekday the week begins on. Default is 0 (Sunday).
4914 * @config START_WEEKDAY
4918 cfg.addProperty(DEF_CFG.START_WEEKDAY.key, { value:DEF_CFG.START_WEEKDAY.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
4921 * True if the Calendar should show weekday labels. True by default.
4922 * @config SHOW_WEEKDAYS
4926 cfg.addProperty(DEF_CFG.SHOW_WEEKDAYS.key, { value:DEF_CFG.SHOW_WEEKDAYS.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4929 * True if the Calendar should show week row headers. False by default.
4930 * @config SHOW_WEEK_HEADER
4934 cfg.addProperty(DEF_CFG.SHOW_WEEK_HEADER.key,{ value:DEF_CFG.SHOW_WEEK_HEADER.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4937 * True if the Calendar should show week row footers. False by default.
4938 * @config SHOW_WEEK_FOOTER
4942 cfg.addProperty(DEF_CFG.SHOW_WEEK_FOOTER.key,{ value:DEF_CFG.SHOW_WEEK_FOOTER.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4945 * True if the Calendar should suppress weeks that are not a part of the current month. False by default.
4946 * @config HIDE_BLANK_WEEKS
4950 cfg.addProperty(DEF_CFG.HIDE_BLANK_WEEKS.key,{ value:DEF_CFG.HIDE_BLANK_WEEKS.value, handler:this.delegateConfig, validator:cfg.checkBoolean } );
4953 * 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.
4954 * @config NAV_ARROW_LEFT
4956 * @deprecated You can customize the image by overriding the default CSS class for the left arrow - "calnavleft"
4959 cfg.addProperty(DEF_CFG.NAV_ARROW_LEFT.key, { value:DEF_CFG.NAV_ARROW_LEFT.value, handler:this.delegateConfig } );
4962 * 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.
4963 * @config NAV_ARROW_RIGHT
4965 * @deprecated You can customize the image by overriding the default CSS class for the right arrow - "calnavright"
4968 cfg.addProperty(DEF_CFG.NAV_ARROW_RIGHT.key, { value:DEF_CFG.NAV_ARROW_RIGHT.value, handler:this.delegateConfig } );
4970 // Locale properties
4973 * 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.
4974 * @config MONTHS_SHORT
4976 * @default ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
4978 cfg.addProperty(DEF_CFG.MONTHS_SHORT.key, { value:DEF_CFG.MONTHS_SHORT.value, handler:this.delegateConfig } );
4981 * 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.
4982 * @config MONTHS_LONG
4984 * @default ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
4986 cfg.addProperty(DEF_CFG.MONTHS_LONG.key, { value:DEF_CFG.MONTHS_LONG.value, handler:this.delegateConfig } );
4989 * 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.
4990 * @config WEEKDAYS_1CHAR
4992 * @default ["S", "M", "T", "W", "T", "F", "S"]
4994 cfg.addProperty(DEF_CFG.WEEKDAYS_1CHAR.key, { value:DEF_CFG.WEEKDAYS_1CHAR.value, handler:this.delegateConfig } );
4997 * 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.
4998 * @config WEEKDAYS_SHORT
5000 * @default ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
5002 cfg.addProperty(DEF_CFG.WEEKDAYS_SHORT.key, { value:DEF_CFG.WEEKDAYS_SHORT.value, handler:this.delegateConfig } );
5005 * 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.
5006 * @config WEEKDAYS_MEDIUM
5008 * @default ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
5010 cfg.addProperty(DEF_CFG.WEEKDAYS_MEDIUM.key, { value:DEF_CFG.WEEKDAYS_MEDIUM.value, handler:this.delegateConfig } );
5013 * 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.
5014 * @config WEEKDAYS_LONG
5016 * @default ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
5018 cfg.addProperty(DEF_CFG.WEEKDAYS_LONG.key, { value:DEF_CFG.WEEKDAYS_LONG.value, handler:this.delegateConfig } );
5021 * The setting that determines which length of month labels should be used. Possible values are "short" and "long".
5022 * @config LOCALE_MONTHS
5026 cfg.addProperty(DEF_CFG.LOCALE_MONTHS.key, { value:DEF_CFG.LOCALE_MONTHS.value, handler:this.delegateConfig } );
5029 * The setting that determines which length of weekday labels should be used. Possible values are "1char", "short", "medium", and "long".
5030 * @config LOCALE_WEEKDAYS
5034 cfg.addProperty(DEF_CFG.LOCALE_WEEKDAYS.key, { value:DEF_CFG.LOCALE_WEEKDAYS.value, handler:this.delegateConfig } );
5037 * The value used to delimit individual dates in a date string passed to various Calendar functions.
5038 * @config DATE_DELIMITER
5042 cfg.addProperty(DEF_CFG.DATE_DELIMITER.key, { value:DEF_CFG.DATE_DELIMITER.value, handler:this.delegateConfig } );
5045 * The value used to delimit date fields in a date string passed to various Calendar functions.
5046 * @config DATE_FIELD_DELIMITER
5050 cfg.addProperty(DEF_CFG.DATE_FIELD_DELIMITER.key,{ value:DEF_CFG.DATE_FIELD_DELIMITER.value, handler:this.delegateConfig } );
5053 * The value used to delimit date ranges in a date string passed to various Calendar functions.
5054 * @config DATE_RANGE_DELIMITER
5058 cfg.addProperty(DEF_CFG.DATE_RANGE_DELIMITER.key,{ value:DEF_CFG.DATE_RANGE_DELIMITER.value, handler:this.delegateConfig } );
5061 * The position of the month in a month/year date string
5062 * @config MY_MONTH_POSITION
5066 cfg.addProperty(DEF_CFG.MY_MONTH_POSITION.key, { value:DEF_CFG.MY_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5069 * The position of the year in a month/year date string
5070 * @config MY_YEAR_POSITION
5074 cfg.addProperty(DEF_CFG.MY_YEAR_POSITION.key, { value:DEF_CFG.MY_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5077 * The position of the month in a month/day date string
5078 * @config MD_MONTH_POSITION
5082 cfg.addProperty(DEF_CFG.MD_MONTH_POSITION.key, { value:DEF_CFG.MD_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5085 * The position of the day in a month/year date string
5086 * @config MD_DAY_POSITION
5090 cfg.addProperty(DEF_CFG.MD_DAY_POSITION.key, { value:DEF_CFG.MD_DAY_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5093 * The position of the month in a month/day/year date string
5094 * @config MDY_MONTH_POSITION
5098 cfg.addProperty(DEF_CFG.MDY_MONTH_POSITION.key, { value:DEF_CFG.MDY_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5101 * The position of the day in a month/day/year date string
5102 * @config MDY_DAY_POSITION
5106 cfg.addProperty(DEF_CFG.MDY_DAY_POSITION.key, { value:DEF_CFG.MDY_DAY_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5109 * The position of the year in a month/day/year date string
5110 * @config MDY_YEAR_POSITION
5114 cfg.addProperty(DEF_CFG.MDY_YEAR_POSITION.key, { value:DEF_CFG.MDY_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5117 * The position of the month in the month year label string used as the Calendar header
5118 * @config MY_LABEL_MONTH_POSITION
5122 cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_POSITION.key, { value:DEF_CFG.MY_LABEL_MONTH_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5125 * The position of the year in the month year label string used as the Calendar header
5126 * @config MY_LABEL_YEAR_POSITION
5130 cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_POSITION.key, { value:DEF_CFG.MY_LABEL_YEAR_POSITION.value, handler:this.delegateConfig, validator:cfg.checkNumber } );
5133 * The suffix used after the month when rendering the Calendar header
5134 * @config MY_LABEL_MONTH_SUFFIX
5138 cfg.addProperty(DEF_CFG.MY_LABEL_MONTH_SUFFIX.key, { value:DEF_CFG.MY_LABEL_MONTH_SUFFIX.value, handler:this.delegateConfig } );
5141 * The suffix used after the year when rendering the Calendar header
5142 * @config MY_LABEL_YEAR_SUFFIX
5146 cfg.addProperty(DEF_CFG.MY_LABEL_YEAR_SUFFIX.key, { value:DEF_CFG.MY_LABEL_YEAR_SUFFIX.value, handler:this.delegateConfig } );
5149 * Configuration for the Month/Year CalendarNavigator UI which allows the user to jump directly to a
5150 * specific Month/Year without having to scroll sequentially through months.
5152 * Setting this property to null (default value) or false, will disable the CalendarNavigator UI.
5155 * Setting this property to true will enable the CalendarNavigatior UI with the default CalendarNavigator configuration values.
5158 * This property can also be set to an object literal containing configuration properties for the CalendarNavigator UI.
5159 * The configuration object expects the the following case-sensitive properties, with the "strings" property being a nested object.
5160 * Any properties which are not provided will use the default values (defined in the CalendarNavigator class).
5164 * <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.
5166 * <dt>month</dt><dd><em>HTML</em> : The markup to use for the month label. Defaults to "Month".</dd>
5167 * <dt>year</dt><dd><em>HTML</em> : The markup to use for the year label. Defaults to "Year".</dd>
5168 * <dt>submit</dt><dd><em>HTML</em> : The markup to use for the submit button label. Defaults to "Okay".</dd>
5169 * <dt>cancel</dt><dd><em>HTML</em> : The markup to use for the cancel button label. Defaults to "Cancel".</dd>
5170 * <dt>invalidYear</dt><dd><em>HTML</em> : The markup to use for invalid year values. Defaults to "Year needs to be a number".</dd>
5173 * <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>
5174 * <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
5180 * month:"Calendar Month",
5181 * year:"Calendar Year",
5184 * invalidYear: "Please enter a valid year"
5186 * monthFormat: YAHOO.widget.Calendar.SHORT,
5187 * initialFocus: "month"
5191 * @type {Object|Boolean}
5194 cfg.addProperty(DEF_CFG.NAV.key, { value:DEF_CFG.NAV.value, handler:this.configNavigator } );
5197 * The map of UI strings which the CalendarGroup UI uses.
5201 * @default An object with the properties shown below:
5203 * <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>
5204 * <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>
5205 * <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>
5208 cfg.addProperty(DEF_CFG.STRINGS.key, {
5209 value:DEF_CFG.STRINGS.value,
5210 handler:this.configStrings,
5211 validator: function(val) {
5212 return Lang.isObject(val);
5214 supercedes: DEF_CFG.STRINGS.supercedes
5219 * Initializes CalendarGroup's built-in CustomEvents
5220 * @method initEvents
5222 initEvents : function() {
5226 CE = YAHOO.util.CustomEvent;
5229 * Proxy subscriber to subscribe to the CalendarGroup's child Calendars' CustomEvents
5232 * @param {Function} fn The function to subscribe to this CustomEvent
5233 * @param {Object} obj The CustomEvent's scope object
5234 * @param {Boolean} bOverride Whether or not to apply scope correction
5236 var sub = function(fn, obj, bOverride) {
5237 for (var p=0;p<me.pages.length;++p) {
5238 var cal = me.pages[p];
5239 cal[this.type + strEvent].subscribe(fn, obj, bOverride);
5244 * Proxy unsubscriber to unsubscribe from the CalendarGroup's child Calendars' CustomEvents
5247 * @param {Function} fn The function to subscribe to this CustomEvent
5248 * @param {Object} obj The CustomEvent's scope object
5250 var unsub = function(fn, obj) {
5251 for (var p=0;p<me.pages.length;++p) {
5252 var cal = me.pages[p];
5253 cal[this.type + strEvent].unsubscribe(fn, obj);
5257 var defEvents = Calendar._EVENT_TYPES;
5260 * Fired before a date selection is made
5261 * @event beforeSelectEvent
5263 me.beforeSelectEvent = new CE(defEvents.BEFORE_SELECT);
5264 me.beforeSelectEvent.subscribe = sub; me.beforeSelectEvent.unsubscribe = unsub;
5267 * Fired when a date selection is made
5268 * @event selectEvent
5269 * @param {Array} Array of Date field arrays in the format [YYYY, MM, DD].
5271 me.selectEvent = new CE(defEvents.SELECT);
5272 me.selectEvent.subscribe = sub; me.selectEvent.unsubscribe = unsub;
5275 * Fired before a date or set of dates is deselected
5276 * @event beforeDeselectEvent
5278 me.beforeDeselectEvent = new CE(defEvents.BEFORE_DESELECT);
5279 me.beforeDeselectEvent.subscribe = sub; me.beforeDeselectEvent.unsubscribe = unsub;
5282 * Fired when a date or set of dates has been deselected
5283 * @event deselectEvent
5284 * @param {Array} Array of Date field arrays in the format [YYYY, MM, DD].
5286 me.deselectEvent = new CE(defEvents.DESELECT);
5287 me.deselectEvent.subscribe = sub; me.deselectEvent.unsubscribe = unsub;
5290 * Fired when the Calendar page is changed
5291 * @event changePageEvent
5293 me.changePageEvent = new CE(defEvents.CHANGE_PAGE);
5294 me.changePageEvent.subscribe = sub; me.changePageEvent.unsubscribe = unsub;
5297 * Fired before the Calendar is rendered
5298 * @event beforeRenderEvent
5300 me.beforeRenderEvent = new CE(defEvents.BEFORE_RENDER);
5301 me.beforeRenderEvent.subscribe = sub; me.beforeRenderEvent.unsubscribe = unsub;
5304 * Fired when the Calendar is rendered
5305 * @event renderEvent
5307 me.renderEvent = new CE(defEvents.RENDER);
5308 me.renderEvent.subscribe = sub; me.renderEvent.unsubscribe = unsub;
5311 * Fired when the Calendar is reset
5314 me.resetEvent = new CE(defEvents.RESET);
5315 me.resetEvent.subscribe = sub; me.resetEvent.unsubscribe = unsub;
5318 * Fired when the Calendar is cleared
5321 me.clearEvent = new CE(defEvents.CLEAR);
5322 me.clearEvent.subscribe = sub; me.clearEvent.unsubscribe = unsub;
5325 * Fired just before the CalendarGroup is to be shown
5326 * @event beforeShowEvent
5328 me.beforeShowEvent = new CE(defEvents.BEFORE_SHOW);
5331 * Fired after the CalendarGroup is shown
5334 me.showEvent = new CE(defEvents.SHOW);
5337 * Fired just before the CalendarGroup is to be hidden
5338 * @event beforeHideEvent
5340 me.beforeHideEvent = new CE(defEvents.BEFORE_HIDE);
5343 * Fired after the CalendarGroup is hidden
5346 me.hideEvent = new CE(defEvents.HIDE);
5349 * Fired just before the CalendarNavigator is to be shown
5350 * @event beforeShowNavEvent
5352 me.beforeShowNavEvent = new CE(defEvents.BEFORE_SHOW_NAV);
5355 * Fired after the CalendarNavigator is shown
5356 * @event showNavEvent
5358 me.showNavEvent = new CE(defEvents.SHOW_NAV);
5361 * Fired just before the CalendarNavigator is to be hidden
5362 * @event beforeHideNavEvent
5364 me.beforeHideNavEvent = new CE(defEvents.BEFORE_HIDE_NAV);
5367 * Fired after the CalendarNavigator is hidden
5368 * @event hideNavEvent
5370 me.hideNavEvent = new CE(defEvents.HIDE_NAV);
5373 * Fired just before the CalendarNavigator is to be rendered
5374 * @event beforeRenderNavEvent
5376 me.beforeRenderNavEvent = new CE(defEvents.BEFORE_RENDER_NAV);
5379 * Fired after the CalendarNavigator is rendered
5380 * @event renderNavEvent
5382 me.renderNavEvent = new CE(defEvents.RENDER_NAV);
5385 * Fired just before the CalendarGroup is to be destroyed
5386 * @event beforeDestroyEvent
5388 me.beforeDestroyEvent = new CE(defEvents.BEFORE_DESTROY);
5391 * Fired after the CalendarGroup is destroyed. This event should be used
5392 * for notification only. When this event is fired, important CalendarGroup instance
5393 * properties, dom references and event listeners have already been
5394 * removed/dereferenced, and hence the CalendarGroup instance is not in a usable
5397 * @event destroyEvent
5399 me.destroyEvent = new CE(defEvents.DESTROY);
5403 * The default Config handler for the "pages" property
5404 * @method configPages
5405 * @param {String} type The CustomEvent type (usually the property name)
5406 * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
5407 * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
5409 configPages : function(type, args, obj) {
5410 var pageCount = args[0],
5411 cfgPageDate = DEF_CFG.PAGEDATE.key,
5414 firstPageDate = null,
5415 groupCalClass = "groupcal",
5416 firstClass = "first-of-type",
5417 lastClass = "last-of-type";
5419 for (var p=0;p<pageCount;++p) {
5420 var calId = this.id + sep + p,
5421 calContainerId = this.containerId + sep + p,
5422 childConfig = this.cfg.getConfig();
5424 childConfig.close = false;
5425 childConfig.title = false;
5426 childConfig.navigator = null;
5429 caldate = new Date(firstPageDate);
5430 this._setMonthOnDate(caldate, caldate.getMonth() + p);
5431 childConfig.pageDate = caldate;
5434 var cal = this.constructChild(calId, calContainerId, childConfig);
5436 Dom.removeClass(cal.oDomContainer, this.Style.CSS_SINGLE);
5437 Dom.addClass(cal.oDomContainer, groupCalClass);
5440 firstPageDate = cal.cfg.getProperty(cfgPageDate);
5441 Dom.addClass(cal.oDomContainer, firstClass);
5444 if (p==(pageCount-1)) {
5445 Dom.addClass(cal.oDomContainer, lastClass);
5451 this.pages[this.pages.length] = cal;
5456 * The default Config handler for the "pagedate" property
5457 * @method configPageDate
5458 * @param {String} type The CustomEvent type (usually the property name)
5459 * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
5460 * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
5462 configPageDate : function(type, args, obj) {
5466 var cfgPageDate = DEF_CFG.PAGEDATE.key;
5468 for (var p=0;p<this.pages.length;++p) {
5469 var cal = this.pages[p];
5471 firstPageDate = cal._parsePageDate(val);
5472 cal.cfg.setProperty(cfgPageDate, firstPageDate);
5474 var pageDate = new Date(firstPageDate);
5475 this._setMonthOnDate(pageDate, pageDate.getMonth() + p);
5476 cal.cfg.setProperty(cfgPageDate, pageDate);
5482 * The default Config handler for the CalendarGroup "selected" property
5483 * @method configSelected
5484 * @param {String} type The CustomEvent type (usually the property name)
5485 * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
5486 * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
5488 configSelected : function(type, args, obj) {
5489 var cfgSelected = DEF_CFG.SELECTED.key;
5490 this.delegateConfig(type, args, obj);
5491 var selected = (this.pages.length > 0) ? this.pages[0].cfg.getProperty(cfgSelected) : [];
5492 this.cfg.setProperty(cfgSelected, selected, true);
5497 * Delegates a configuration property to the CustomEvents associated with the CalendarGroup's children
5498 * @method delegateConfig
5499 * @param {String} type The CustomEvent type (usually the property name)
5500 * @param {Object[]} args The CustomEvent arguments. For configuration handlers, args[0] will equal the newly applied value for the property.
5501 * @param {Object} obj The scope object. For configuration handlers, this will usually equal the owner.
5503 delegateConfig : function(type, args, obj) {
5507 for (var p=0;p<this.pages.length;p++) {
5508 cal = this.pages[p];
5509 cal.cfg.setProperty(type, val);
5514 * Adds a function to all child Calendars within this CalendarGroup.
5515 * @method setChildFunction
5516 * @param {String} fnName The name of the function
5517 * @param {Function} fn The function to apply to each Calendar page object
5519 setChildFunction : function(fnName, fn) {
5520 var pageCount = this.cfg.getProperty(DEF_CFG.PAGES.key);
5522 for (var p=0;p<pageCount;++p) {
5523 this.pages[p][fnName] = fn;
5528 * Calls a function within all child Calendars within this CalendarGroup.
5529 * @method callChildFunction
5530 * @param {String} fnName The name of the function
5531 * @param {Array} args The arguments to pass to the function
5533 callChildFunction : function(fnName, args) {
5534 var pageCount = this.cfg.getProperty(DEF_CFG.PAGES.key);
5536 for (var p=0;p<pageCount;++p) {
5537 var page = this.pages[p];
5539 var fn = page[fnName];
5540 fn.call(page, args);
5546 * Constructs a child calendar. This method can be overridden if a subclassed version of the default
5547 * calendar is to be used.
5548 * @method constructChild
5549 * @param {String} id The id of the table element that will represent the calendar widget
5550 * @param {String} containerId The id of the container div element that will wrap the calendar table
5551 * @param {Object} config The configuration object containing the Calendar's arguments
5552 * @return {YAHOO.widget.Calendar} The YAHOO.widget.Calendar instance that is constructed
5554 constructChild : function(id,containerId,config) {
5555 var container = document.getElementById(containerId);
5557 container = document.createElement("div");
5558 container.id = containerId;
5559 this.oDomContainer.appendChild(container);
5561 return new Calendar(id,containerId,config);
5565 * Sets the calendar group's month explicitly. This month will be set into the first
5566 * page of the multi-page calendar, and all other months will be iterated appropriately.
5568 * @param {Number} month The numeric month, from 0 (January) to 11 (December)
5570 setMonth : function(month) {
5571 month = parseInt(month, 10);
5574 var cfgPageDate = DEF_CFG.PAGEDATE.key;
5576 for (var p=0; p<this.pages.length; ++p) {
5577 var cal = this.pages[p];
5578 var pageDate = cal.cfg.getProperty(cfgPageDate);
5580 currYear = pageDate.getFullYear();
5582 pageDate.setFullYear(currYear);
5584 this._setMonthOnDate(pageDate, month+p);
5585 cal.cfg.setProperty(cfgPageDate, pageDate);
5590 * Sets the calendar group's year explicitly. This year will be set into the first
5591 * page of the multi-page calendar, and all other months will be iterated appropriately.
5593 * @param {Number} year The numeric 4-digit year
5595 setYear : function(year) {
5597 var cfgPageDate = DEF_CFG.PAGEDATE.key;
5599 year = parseInt(year, 10);
5600 for (var p=0;p<this.pages.length;++p) {
5601 var cal = this.pages[p];
5602 var pageDate = cal.cfg.getProperty(cfgPageDate);
5604 if ((pageDate.getMonth()+1) == 1 && p>0) {
5612 * Calls the render function of all child calendars within the group.
5615 render : function() {
5616 this.renderHeader();
5617 for (var p=0;p<this.pages.length;++p) {
5618 var cal = this.pages[p];
5621 this.renderFooter();
5625 * Selects a date or a collection of dates on the current calendar. This method, by default,
5626 * does not call the render method explicitly. Once selection has completed, render must be
5627 * called for the changes to be reflected visually.
5629 * @param {String/Date/Date[]} date The date string of dates to select in the current calendar. Valid formats are
5630 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
5631 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
5632 * This method can also take a JavaScript Date object or an array of Date objects.
5633 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
5635 select : function(date) {
5636 for (var p=0;p<this.pages.length;++p) {
5637 var cal = this.pages[p];
5640 return this.getSelectedDates();
5644 * 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.
5645 * The value of the MULTI_SELECT Configuration attribute will determine the set of dates which get selected.
5647 * <li>If MULTI_SELECT is false, selectCell will select the cell at the specified index for only the last displayed Calendar page.</li>
5648 * <li>If MULTI_SELECT is true, selectCell will select the cell at the specified index, on each displayed Calendar page.</li>
5650 * @method selectCell
5651 * @param {Number} cellIndex The index of the cell to be selected.
5652 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
5654 selectCell : function(cellIndex) {
5655 for (var p=0;p<this.pages.length;++p) {
5656 var cal = this.pages[p];
5657 cal.selectCell(cellIndex);
5659 return this.getSelectedDates();
5663 * Deselects a date or a collection of dates on the current calendar. This method, by default,
5664 * does not call the render method explicitly. Once deselection has completed, render must be
5665 * called for the changes to be reflected visually.
5667 * @param {String/Date/Date[]} date The date string of dates to deselect in the current calendar. Valid formats are
5668 * individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
5669 * Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
5670 * This method can also take a JavaScript Date object or an array of Date objects.
5671 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
5673 deselect : function(date) {
5674 for (var p=0;p<this.pages.length;++p) {
5675 var cal = this.pages[p];
5678 return this.getSelectedDates();
5682 * Deselects all dates on the current calendar.
5683 * @method deselectAll
5684 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
5685 * Assuming that this function executes properly, the return value should be an empty array.
5686 * However, the empty array is returned for the sake of being able to check the selection status
5689 deselectAll : function() {
5690 for (var p=0;p<this.pages.length;++p) {
5691 var cal = this.pages[p];
5694 return this.getSelectedDates();
5698 * 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.
5699 * deselectCell will deselect the cell at the specified index on each displayed Calendar page.
5701 * @method deselectCell
5702 * @param {Number} cellIndex The index of the cell to deselect.
5703 * @return {Date[]} Array of JavaScript Date objects representing all individual dates that are currently selected.
5705 deselectCell : function(cellIndex) {
5706 for (var p=0;p<this.pages.length;++p) {
5707 var cal = this.pages[p];
5708 cal.deselectCell(cellIndex);
5710 return this.getSelectedDates();
5714 * Resets the calendar widget to the originally selected month and year, and
5715 * sets the calendar to the initial selection(s).
5718 reset : function() {
5719 for (var p=0;p<this.pages.length;++p) {
5720 var cal = this.pages[p];
5726 * Clears the selected dates in the current calendar widget and sets the calendar
5727 * to the current month and year.
5730 clear : function() {
5731 for (var p=0;p<this.pages.length;++p) {
5732 var cal = this.pages[p];
5736 this.cfg.setProperty(DEF_CFG.SELECTED.key, []);
5737 this.cfg.setProperty(DEF_CFG.PAGEDATE.key, new Date(this.pages[0].today.getTime()));
5742 * Navigates to the next month page in the calendar widget.
5745 nextMonth : function() {
5746 for (var p=0;p<this.pages.length;++p) {
5747 var cal = this.pages[p];
5753 * Navigates to the previous month page in the calendar widget.
5754 * @method previousMonth
5756 previousMonth : function() {
5757 for (var p=this.pages.length-1;p>=0;--p) {
5758 var cal = this.pages[p];
5759 cal.previousMonth();
5764 * Navigates to the next year in the currently selected month in the calendar widget.
5767 nextYear : function() {
5768 for (var p=0;p<this.pages.length;++p) {
5769 var cal = this.pages[p];
5775 * Navigates to the previous year in the currently selected month in the calendar widget.
5776 * @method previousYear
5778 previousYear : function() {
5779 for (var p=0;p<this.pages.length;++p) {
5780 var cal = this.pages[p];
5786 * Gets the list of currently selected dates from the calendar.
5787 * @return An array of currently selected JavaScript Date objects.
5790 getSelectedDates : function() {
5791 var returnDates = [];
5792 var selected = this.cfg.getProperty(DEF_CFG.SELECTED.key);
5793 for (var d=0;d<selected.length;++d) {
5794 var dateArray = selected[d];
5796 var date = DateMath.getDate(dateArray[0],dateArray[1]-1,dateArray[2]);
5797 returnDates.push(date);
5800 returnDates.sort( function(a,b) { return a-b; } );
5805 * Adds a renderer to the render stack. The function reference passed to this method will be executed
5806 * when a date cell matches the conditions specified in the date string for this renderer.
5808 * <p>NOTE: The contents of the cell set by the renderer will be added to the DOM as HTML. The custom renderer implementation should
5809 * escape markup used to set the cell contents, if coming from an external source.<p>
5810 * @method addRenderer
5811 * @param {String} sDates A date string to associate with the specified renderer. Valid formats
5812 * include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
5813 * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
5815 addRenderer : function(sDates, fnRender) {
5816 for (var p=0;p<this.pages.length;++p) {
5817 var cal = this.pages[p];
5818 cal.addRenderer(sDates, fnRender);
5823 * Adds a month renderer to the render stack. The function reference passed to this method will be executed
5824 * when a date cell matches the month passed to this method
5826 * <p>NOTE: The contents of the cell set by the renderer will be added to the DOM as HTML. The custom renderer implementation should
5827 * escape markup used to set the cell contents, if coming from an external source.<p>
5828 * @method addMonthRenderer
5829 * @param {Number} month The month (1-12) to associate with this renderer
5830 * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
5832 addMonthRenderer : function(month, fnRender) {
5833 for (var p=0;p<this.pages.length;++p) {
5834 var cal = this.pages[p];
5835 cal.addMonthRenderer(month, fnRender);
5840 * Adds a weekday renderer to the render stack. The function reference passed to this method will be executed
5841 * when a date cell matches the weekday passed to this method.
5843 * <p>NOTE: The contents of the cell set by the renderer will be added to the DOM as HTML. The custom renderer implementation should
5844 * escape HTML used to set the cell contents, if coming from an external source.<p>
5846 * @method addWeekdayRenderer
5847 * @param {Number} weekday The weekday (Sunday = 1, Monday = 2 ... Saturday = 7) to associate with this renderer
5848 * @param {Function} fnRender The function executed to render cells that match the render rules for this renderer.
5850 addWeekdayRenderer : function(weekday, fnRender) {
5851 for (var p=0;p<this.pages.length;++p) {
5852 var cal = this.pages[p];
5853 cal.addWeekdayRenderer(weekday, fnRender);
5858 * Removes all custom renderers added to the CalendarGroup through the addRenderer, addMonthRenderer and
5859 * addWeekRenderer methods. CalendarGroup's render method needs to be called to after removing renderers
5860 * to see the changes applied.
5862 * @method removeRenderers
5864 removeRenderers : function() {
5865 this.callChildFunction("removeRenderers");
5869 * Renders the header for the CalendarGroup.
5870 * @method renderHeader
5872 renderHeader : function() {
5873 // EMPTY DEFAULT IMPL
5877 * Renders a footer for the 2-up calendar container. By default, this method is
5879 * @method renderFooter
5881 renderFooter : function() {
5882 // EMPTY DEFAULT IMPL
5886 * Adds the designated number of months to the current calendar month, and sets the current
5887 * calendar page date to the new month.
5889 * @param {Number} count The number of months to add to the current calendar
5891 addMonths : function(count) {
5892 this.callChildFunction("addMonths", count);
5896 * Subtracts the designated number of months from the current calendar month, and sets the current
5897 * calendar page date to the new month.
5898 * @method subtractMonths
5899 * @param {Number} count The number of months to subtract from the current calendar
5901 subtractMonths : function(count) {
5902 this.callChildFunction("subtractMonths", count);
5906 * Adds the designated number of years to the current calendar, and sets the current
5907 * calendar page date to the new month.
5909 * @param {Number} count The number of years to add to the current calendar
5911 addYears : function(count) {
5912 this.callChildFunction("addYears", count);
5916 * Subtcats the designated number of years from the current calendar, and sets the current
5917 * calendar page date to the new month.
5918 * @method subtractYears
5919 * @param {Number} count The number of years to subtract from the current calendar
5921 subtractYears : function(count) {
5922 this.callChildFunction("subtractYears", count);
5926 * Returns the Calendar page instance which has a pagedate (month/year) matching the given date.
5927 * Returns null if no match is found.
5929 * @method getCalendarPage
5930 * @param {Date} date The JavaScript Date object for which a Calendar page is to be found.
5931 * @return {Calendar} The Calendar page instance representing the month to which the date
5934 getCalendarPage : function(date) {
5937 var y = date.getFullYear(),
5938 m = date.getMonth();
5940 var pages = this.pages;
5941 for (var i = 0; i < pages.length; ++i) {
5942 var pageDate = pages[i].cfg.getProperty("pagedate");
5943 if (pageDate.getFullYear() === y && pageDate.getMonth() === m) {
5953 * Sets the month on a Date object, taking into account year rollover if the month is less than 0 or greater than 11.
5954 * 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
5955 * @method _setMonthOnDate
5957 * @param {Date} date The Date object on which to set the month index
5958 * @param {Number} iMonth The month index to set
5960 _setMonthOnDate : function(date, iMonth) {
5961 // Bug in Safari 1.3, 2.0 (WebKit build < 420), Date.setMonth does not work consistently if iMonth is not 0-11
5962 if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420 && (iMonth < 0 || iMonth > 11)) {
5963 var newDate = DateMath.add(date, DateMath.MONTH, iMonth-date.getMonth());
5964 date.setTime(newDate.getTime());
5966 date.setMonth(iMonth);
5971 * Fixes the width of the CalendarGroup container element, to account for miswrapped floats
5975 _fixWidth : function() {
5977 for (var p=0;p<this.pages.length;++p) {
5978 var cal = this.pages[p];
5979 w += cal.oDomContainer.offsetWidth;
5982 this.oDomContainer.style.width = w + "px";
5987 * Returns a string representation of the object.
5989 * @return {String} A string representation of the CalendarGroup object.
5991 toString : function() {
5992 return "CalendarGroup " + this.id;
5996 * Destroys the CalendarGroup instance. The method will remove references
5997 * to HTML elements, remove any event listeners added by the CalendarGroup.
5999 * It will also destroy the Config and CalendarNavigator instances created by the
6000 * CalendarGroup and the individual Calendar instances created for each page.
6004 destroy : function() {
6006 if (this.beforeDestroyEvent.fire()) {
6011 if (cal.navigator) {
6012 cal.navigator.destroy();
6019 // DOM event listeners
6020 Event.purgeElement(cal.oDomContainer, true);
6022 // Generated markup/DOM - Not removing the container DIV since we didn't create it.
6023 Dom.removeClass(cal.oDomContainer, CalendarGroup.CSS_CONTAINER);
6024 Dom.removeClass(cal.oDomContainer, CalendarGroup.CSS_MULTI_UP);
6026 for (var i = 0, l = cal.pages.length; i < l; i++) {
6027 cal.pages[i].destroy();
6028 cal.pages[i] = null;
6031 cal.oDomContainer.innerHTML = "";
6033 // JS-to-DOM references
6034 cal.oDomContainer = null;
6036 this.destroyEvent.fire();
6042 * CSS class representing the container for the calendar
6043 * @property YAHOO.widget.CalendarGroup.CSS_CONTAINER
6048 CalendarGroup.CSS_CONTAINER = "yui-calcontainer";
6051 * CSS class representing the container for the calendar
6052 * @property YAHOO.widget.CalendarGroup.CSS_MULTI_UP
6057 CalendarGroup.CSS_MULTI_UP = "multi";
6060 * CSS class representing the title for the 2-up calendar
6061 * @property YAHOO.widget.CalendarGroup.CSS_2UPTITLE
6066 CalendarGroup.CSS_2UPTITLE = "title";
6069 * CSS class representing the close icon for the 2-up calendar
6070 * @property YAHOO.widget.CalendarGroup.CSS_2UPCLOSE
6073 * @deprecated Along with Calendar.IMG_ROOT and NAV_ARROW_LEFT, NAV_ARROW_RIGHT configuration properties.
6074 * 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
6077 CalendarGroup.CSS_2UPCLOSE = "close-icon";
6079 YAHOO.lang.augmentProto(CalendarGroup, Calendar, "buildDayLabel",
6081 "renderOutOfBoundsDate",
6084 "renderCellDefault",
6086 "renderCellStyleHighlight1",
6087 "renderCellStyleHighlight2",
6088 "renderCellStyleHighlight3",
6089 "renderCellStyleHighlight4",
6090 "renderCellStyleToday",
6091 "renderCellStyleSelected",
6092 "renderCellNotThisMonth",
6093 "styleCellNotThisMonth",
6094 "renderBodyCellRestricted",
6103 "createCloseButton",
6105 "removeCloseButton",
6113 YAHOO.widget.CalGrp = CalendarGroup;
6114 YAHOO.widget.CalendarGroup = CalendarGroup;
6117 * @class YAHOO.widget.Calendar2up
6118 * @extends YAHOO.widget.CalendarGroup
6119 * @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
6121 YAHOO.widget.Calendar2up = function(id, containerId, config) {
6122 this.init(id, containerId, config);
6125 YAHOO.extend(YAHOO.widget.Calendar2up, CalendarGroup);
6128 * @deprecated The old Calendar2up class is no longer necessary, since CalendarGroup renders in a 2up view by default.
6130 YAHOO.widget.Cal2up = YAHOO.widget.Calendar2up;
6134 * The CalendarNavigator is used along with a Calendar/CalendarGroup to
6135 * provide a Month/Year popup navigation control, allowing the user to navigate
6136 * to a specific month/year in the Calendar/CalendarGroup without having to
6137 * scroll through months sequentially
6139 * @namespace YAHOO.widget
6140 * @class CalendarNavigator
6142 * @param {Calendar|CalendarGroup} cal The instance of the Calendar or CalendarGroup to which this CalendarNavigator should be attached.
6144 YAHOO.widget.CalendarNavigator = function(cal) {
6149 // Setup static properties (inside anon fn, so that we can use shortcuts)
6150 var CN = YAHOO.widget.CalendarNavigator;
6153 * YAHOO.widget.CalendarNavigator.CLASSES contains constants
6154 * for the class values applied to the CalendarNaviatgator's
6156 * @property YAHOO.widget.CalendarNavigator.CLASSES
6162 * Class applied to the Calendar Navigator's bounding box
6163 * @property YAHOO.widget.CalendarNavigator.CLASSES.NAV
6169 * Class applied to the Calendar/CalendarGroup's bounding box to indicate
6170 * the Navigator is currently visible
6171 * @property YAHOO.widget.CalendarNavigator.CLASSES.NAV_VISIBLE
6175 NAV_VISIBLE: "yui-cal-nav-visible",
6177 * Class applied to the Navigator mask's bounding box
6178 * @property YAHOO.widget.CalendarNavigator.CLASSES.MASK
6182 MASK : "yui-cal-nav-mask",
6184 * Class applied to the year label/control bounding box
6185 * @property YAHOO.widget.CalendarNavigator.CLASSES.YEAR
6189 YEAR : "yui-cal-nav-y",
6191 * Class applied to the month label/control bounding box
6192 * @property YAHOO.widget.CalendarNavigator.CLASSES.MONTH
6196 MONTH : "yui-cal-nav-m",
6198 * Class applied to the submit/cancel button's bounding box
6199 * @property YAHOO.widget.CalendarNavigator.CLASSES.BUTTONS
6203 BUTTONS : "yui-cal-nav-b",
6205 * Class applied to buttons wrapping element
6206 * @property YAHOO.widget.CalendarNavigator.CLASSES.BUTTON
6210 BUTTON : "yui-cal-nav-btn",
6212 * Class applied to the validation error area's bounding box
6213 * @property YAHOO.widget.CalendarNavigator.CLASSES.ERROR
6217 ERROR : "yui-cal-nav-e",
6219 * Class applied to the year input control
6220 * @property YAHOO.widget.CalendarNavigator.CLASSES.YEAR_CTRL
6224 YEAR_CTRL : "yui-cal-nav-yc",
6226 * Class applied to the month input control
6227 * @property YAHOO.widget.CalendarNavigator.CLASSES.MONTH_CTRL
6231 MONTH_CTRL : "yui-cal-nav-mc",
6233 * Class applied to controls with invalid data (e.g. a year input field with invalid an year)
6234 * @property YAHOO.widget.CalendarNavigator.CLASSES.INVALID
6238 INVALID : "yui-invalid",
6240 * Class applied to default controls
6241 * @property YAHOO.widget.CalendarNavigator.CLASSES.DEFAULT
6245 DEFAULT : "yui-default"
6249 * Object literal containing the default configuration values for the CalendarNavigator
6250 * The configuration object is expected to follow the format below, with the properties being
6254 * <dd><em>Object</em> : An object with the properties shown below, defining the string labels to use in the Navigator's UI
6256 * <dt>month</dt><dd><em>HTML</em> : The markup to use for the month label. Defaults to "Month".</dd>
6257 * <dt>year</dt><dd><em>HTML</em> : The markup to use for the year label. Defaults to "Year".</dd>
6258 * <dt>submit</dt><dd><em>HTML</em> : The markup to use for the submit button label. Defaults to "Okay".</dd>
6259 * <dt>cancel</dt><dd><em>HTML</em> : The markup to use for the cancel button label. Defaults to "Cancel".</dd>
6260 * <dt>invalidYear</dt><dd><em>HTML</em> : The markup to use for invalid year values. Defaults to "Year needs to be a number".</dd>
6263 * <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>
6264 * <dt>initialFocus</dt><dd><em>String</em> : Either "year" or "month" specifying which input control should get initial focus. Defaults to "year"</dd>
6266 * @property DEFAULT_CONFIG
6270 CN.DEFAULT_CONFIG = {
6276 invalidYear : "Year needs to be a number"
6278 monthFormat: YAHOO.widget.Calendar.LONG,
6279 initialFocus: "year"
6283 * Object literal containing the default configuration values for the CalendarNavigator
6284 * @property _DEFAULT_CFG
6286 * @deprecated Made public. See the public DEFAULT_CONFIG property
6290 CN._DEFAULT_CFG = CN.DEFAULT_CONFIG;
6294 * The suffix added to the Calendar/CalendarGroup's ID, to generate
6295 * a unique ID for the Navigator and it's bounding box.
6296 * @property YAHOO.widget.CalendarNavigator.ID_SUFFIX
6301 CN.ID_SUFFIX = "_nav";
6303 * The suffix added to the Navigator's ID, to generate
6304 * a unique ID for the month control.
6305 * @property YAHOO.widget.CalendarNavigator.MONTH_SUFFIX
6310 CN.MONTH_SUFFIX = "_month";
6312 * The suffix added to the Navigator's ID, to generate
6313 * a unique ID for the year control.
6314 * @property YAHOO.widget.CalendarNavigator.YEAR_SUFFIX
6319 CN.YEAR_SUFFIX = "_year";
6321 * The suffix added to the Navigator's ID, to generate
6322 * a unique ID for the error bounding box.
6323 * @property YAHOO.widget.CalendarNavigator.ERROR_SUFFIX
6328 CN.ERROR_SUFFIX = "_error";
6330 * The suffix added to the Navigator's ID, to generate
6331 * a unique ID for the "Cancel" button.
6332 * @property YAHOO.widget.CalendarNavigator.CANCEL_SUFFIX
6337 CN.CANCEL_SUFFIX = "_cancel";
6339 * The suffix added to the Navigator's ID, to generate
6340 * a unique ID for the "Submit" button.
6341 * @property YAHOO.widget.CalendarNavigator.SUBMIT_SUFFIX
6346 CN.SUBMIT_SUFFIX = "_submit";
6349 * The number of digits to which the year input control is to be limited.
6350 * @property YAHOO.widget.CalendarNavigator.YR_MAX_DIGITS
6354 CN.YR_MAX_DIGITS = 4;
6357 * The amount by which to increment the current year value,
6358 * when the arrow up/down key is pressed on the year control
6359 * @property YAHOO.widget.CalendarNavigator.YR_MINOR_INC
6363 CN.YR_MINOR_INC = 1;
6366 * The amount by which to increment the current year value,
6367 * when the page up/down key is pressed on the year control
6368 * @property YAHOO.widget.CalendarNavigator.YR_MAJOR_INC
6372 CN.YR_MAJOR_INC = 10;
6375 * Artificial delay (in ms) between the time the Navigator is hidden
6376 * and the Calendar/CalendarGroup state is updated. Allows the user
6377 * the see the Calendar/CalendarGroup page changing. If set to 0
6378 * the Calendar/CalendarGroup page will be updated instantly
6379 * @property YAHOO.widget.CalendarNavigator.UPDATE_DELAY
6383 CN.UPDATE_DELAY = 50;
6386 * Regular expression used to validate the year input
6387 * @property YAHOO.widget.CalendarNavigator.YR_PATTERN
6391 CN.YR_PATTERN = /^\d+$/;
6393 * Regular expression used to trim strings
6394 * @property YAHOO.widget.CalendarNavigator.TRIM
6398 CN.TRIM = /^\s*(.*?)\s*$/;
6401 YAHOO.widget.CalendarNavigator.prototype = {
6404 * The unique ID for this CalendarNavigator instance
6411 * The Calendar/CalendarGroup instance to which the navigator belongs
6413 * @type {Calendar|CalendarGroup}
6418 * Reference to the HTMLElement used to render the navigator's bounding box
6425 * Reference to the HTMLElement used to render the navigator's mask
6432 * Reference to the HTMLElement used to input the year
6439 * Reference to the HTMLElement used to input the month
6446 * Reference to the HTMLElement used to display validation errors
6453 * Reference to the HTMLElement used to update the Calendar/Calendar group
6454 * with the month/year values
6455 * @property submitEl
6461 * Reference to the HTMLElement used to hide the navigator without updating the
6462 * Calendar/Calendar group
6463 * @property cancelEl
6469 * Reference to the first focusable control in the navigator (by default monthEl)
6470 * @property firstCtrl
6476 * Reference to the last focusable control in the navigator (by default cancelEl)
6477 * @property lastCtrl
6483 * The document containing the Calendar/Calendar group instance
6486 * @type HTMLDocument
6491 * Internal state property for the current year displayed in the navigator
6499 * Internal state property for the current month index displayed in the navigator
6507 * Private internal state property which indicates whether or not the
6508 * Navigator has been rendered.
6510 * @property __rendered
6516 * Init lifecycle method called as part of construction
6519 * @param {Calendar} cal The instance of the Calendar or CalendarGroup to which this CalendarNavigator should be attached
6521 init : function(cal) {
6522 var calBox = cal.oDomContainer;
6525 this.id = calBox.id + YAHOO.widget.CalendarNavigator.ID_SUFFIX;
6526 this._doc = calBox.ownerDocument;
6529 * Private flag, to identify IE Quirks
6531 * @property __isIEQuirks
6533 var ie = YAHOO.env.ua.ie;
6534 this.__isIEQuirks = (ie && ((ie <= 6) || (this._doc.compatMode == "BackCompat")));
6538 * Displays the navigator and mask, updating the input controls to reflect the
6539 * currently set month and year. The show method will invoke the render method
6540 * if the navigator has not been renderered already, allowing for lazy rendering
6543 * The show method will fire the Calendar/CalendarGroup's beforeShowNav and showNav events
6548 var CLASSES = YAHOO.widget.CalendarNavigator.CLASSES;
6550 if (this.cal.beforeShowNavEvent.fire()) {
6551 if (!this.__rendered) {
6556 this._updateMonthUI();
6557 this._updateYearUI();
6558 this._show(this.navEl, true);
6560 this.setInitialFocus();
6563 YAHOO.util.Dom.addClass(this.cal.oDomContainer, CLASSES.NAV_VISIBLE);
6564 this.cal.showNavEvent.fire();
6569 * Hides the navigator and mask
6571 * The show method will fire the Calendar/CalendarGroup's beforeHideNav event and hideNav events
6575 var CLASSES = YAHOO.widget.CalendarNavigator.CLASSES;
6577 if (this.cal.beforeHideNavEvent.fire()) {
6578 this._show(this.navEl, false);
6580 YAHOO.util.Dom.removeClass(this.cal.oDomContainer, CLASSES.NAV_VISIBLE);
6581 this.cal.hideNavEvent.fire();
6587 * Displays the navigator's mask element
6591 showMask : function() {
6592 this._show(this.maskEl, true);
6593 if (this.__isIEQuirks) {
6599 * Hides the navigator's mask element
6603 hideMask : function() {
6604 this._show(this.maskEl, false);
6608 * Returns the current month set on the navigator
6610 * Note: This may not be the month set in the UI, if
6611 * the UI contains an invalid value.
6614 * @return {Number} The Navigator's current month index
6616 getMonth: function() {
6621 * Returns the current year set on the navigator
6623 * Note: This may not be the year set in the UI, if
6624 * the UI contains an invalid value.
6627 * @return {Number} The Navigator's current year value
6629 getYear: function() {
6634 * Sets the current month on the Navigator, and updates the UI
6637 * @param {Number} nMonth The month index, from 0 (Jan) through 11 (Dec).
6639 setMonth : function(nMonth) {
6640 if (nMonth >= 0 && nMonth < 12) {
6641 this._month = nMonth;
6643 this._updateMonthUI();
6647 * Sets the current year on the Navigator, and updates the UI. If the
6648 * provided year is invalid, it will not be set.
6651 * @param {Number} nYear The full year value to set the Navigator to.
6653 setYear : function(nYear) {
6654 var yrPattern = YAHOO.widget.CalendarNavigator.YR_PATTERN;
6655 if (YAHOO.lang.isNumber(nYear) && yrPattern.test(nYear+"")) {
6658 this._updateYearUI();
6662 * Renders the HTML for the navigator, adding it to the
6663 * document and attaches event listeners if it has not
6664 * already been rendered.
6668 render: function() {
6669 this.cal.beforeRenderNavEvent.fire();
6670 if (!this.__rendered) {
6673 this.applyListeners();
6674 this.__rendered = true;
6676 this.cal.renderNavEvent.fire();
6680 * Creates the navigator's containing HTMLElement, it's contents, and appends
6681 * the containg element to the Calendar/CalendarGroup's container.
6685 createNav : function() {
6686 var NAV = YAHOO.widget.CalendarNavigator;
6687 var doc = this._doc;
6689 var d = doc.createElement("div");
6690 d.className = NAV.CLASSES.NAV;
6692 var htmlBuf = this.renderNavContents([]);
6694 d.innerHTML = htmlBuf.join('');
6695 this.cal.oDomContainer.appendChild(d);
6699 this.yearEl = doc.getElementById(this.id + NAV.YEAR_SUFFIX);
6700 this.monthEl = doc.getElementById(this.id + NAV.MONTH_SUFFIX);
6701 this.errorEl = doc.getElementById(this.id + NAV.ERROR_SUFFIX);
6702 this.submitEl = doc.getElementById(this.id + NAV.SUBMIT_SUFFIX);
6703 this.cancelEl = doc.getElementById(this.id + NAV.CANCEL_SUFFIX);
6705 if (YAHOO.env.ua.gecko && this.yearEl && this.yearEl.type == "text") {
6706 // Avoid XUL error on focus, select [ https://bugzilla.mozilla.org/show_bug.cgi?id=236791,
6707 // supposedly fixed in 1.8.1, but there are reports of it still being around for methods other than blur ]
6708 this.yearEl.setAttribute("autocomplete", "off");
6711 this._setFirstLastElements();
6715 * Creates the Mask HTMLElement and appends it to the Calendar/CalendarGroups
6718 * @method createMask
6720 createMask : function() {
6721 var C = YAHOO.widget.CalendarNavigator.CLASSES;
6723 var d = this._doc.createElement("div");
6724 d.className = C.MASK;
6726 this.cal.oDomContainer.appendChild(d);
6731 * Used to set the width/height of the mask in pixels to match the Calendar Container.
6732 * Currently only used for IE6 or IE in quirks mode. The other A-Grade browser are handled using CSS (width/height 100%).
6734 * The method is also registered as an HTMLElement resize listener on the Calendars container element.
6739 _syncMask : function() {
6740 var c = this.cal.oDomContainer;
6741 if (c && this.maskEl) {
6742 var r = YAHOO.util.Dom.getRegion(c);
6743 YAHOO.util.Dom.setStyle(this.maskEl, "width", r.right - r.left + "px");
6744 YAHOO.util.Dom.setStyle(this.maskEl, "height", r.bottom - r.top + "px");
6749 * 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.
6751 * @method renderNavContents
6753 * @param {HTML[]} html The HTML buffer to append the HTML to.
6754 * @return {HTML[]} A reference to the buffer passed in.
6756 renderNavContents : function(html) {
6757 var NAV = YAHOO.widget.CalendarNavigator,
6759 h = html; // just to use a shorter name
6761 h[h.length] = '<div class="' + C.MONTH + '">';
6762 this.renderMonth(h);
6763 h[h.length] = '</div>';
6764 h[h.length] = '<div class="' + C.YEAR + '">';
6766 h[h.length] = '</div>';
6767 h[h.length] = '<div class="' + C.BUTTONS + '">';
6768 this.renderButtons(h);
6769 h[h.length] = '</div>';
6770 h[h.length] = '<div class="' + C.ERROR + '" id="' + this.id + NAV.ERROR_SUFFIX + '"></div>';
6776 * 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.
6778 * @method renderNavContents
6779 * @param {HTML[]} html The HTML buffer to append the HTML to.
6780 * @return {HTML[]} A reference to the buffer passed in.
6782 renderMonth : function(html) {
6783 var NAV = YAHOO.widget.CalendarNavigator,
6786 var id = this.id + NAV.MONTH_SUFFIX,
6787 mf = this.__getCfg("monthFormat"),
6788 months = this.cal.cfg.getProperty((mf == YAHOO.widget.Calendar.SHORT) ? "MONTHS_SHORT" : "MONTHS_LONG"),
6791 if (months && months.length > 0) {
6792 h[h.length] = '<label for="' + id + '">';
6793 h[h.length] = this.__getCfg("month", true);
6794 h[h.length] = '</label>';
6795 h[h.length] = '<select name="' + id + '" id="' + id + '" class="' + C.MONTH_CTRL + '">';
6796 for (var i = 0; i < months.length; i++) {
6797 h[h.length] = '<option value="' + i + '">';
6798 h[h.length] = months[i];
6799 h[h.length] = '</option>';
6801 h[h.length] = '</select>';
6807 * 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.
6809 * @method renderYear
6810 * @param {Array} html The HTML buffer to append the HTML to.
6811 * @return {Array} A reference to the buffer passed in.
6813 renderYear : function(html) {
6814 var NAV = YAHOO.widget.CalendarNavigator,
6817 var id = this.id + NAV.YEAR_SUFFIX,
6818 size = NAV.YR_MAX_DIGITS,
6821 h[h.length] = '<label for="' + id + '">';
6822 h[h.length] = this.__getCfg("year", true);
6823 h[h.length] = '</label>';
6824 h[h.length] = '<input type="text" name="' + id + '" id="' + id + '" class="' + C.YEAR_CTRL + '" maxlength="' + size + '"/>';
6829 * 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.
6831 * @method renderButtons
6832 * @param {Array} html The HTML buffer to append the HTML to.
6833 * @return {Array} A reference to the buffer passed in.
6835 renderButtons : function(html) {
6836 var C = YAHOO.widget.CalendarNavigator.CLASSES;
6839 h[h.length] = '<span class="' + C.BUTTON + ' ' + C.DEFAULT + '">';
6840 h[h.length] = '<button type="button" id="' + this.id + '_submit' + '">';
6841 h[h.length] = this.__getCfg("submit", true);
6842 h[h.length] = '</button>';
6843 h[h.length] = '</span>';
6844 h[h.length] = '<span class="' + C.BUTTON +'">';
6845 h[h.length] = '<button type="button" id="' + this.id + '_cancel' + '">';
6846 h[h.length] = this.__getCfg("cancel", true);
6847 h[h.length] = '</button>';
6848 h[h.length] = '</span>';
6854 * Attaches DOM event listeners to the rendered elements
6856 * The method will call applyKeyListeners, to setup keyboard specific
6859 * @method applyListeners
6861 applyListeners : function() {
6862 var E = YAHOO.util.Event;
6864 function yearUpdateHandler() {
6865 if (this.validate()) {
6866 this.setYear(this._getYearFromUI());
6870 function monthUpdateHandler() {
6871 this.setMonth(this._getMonthFromUI());
6874 E.on(this.submitEl, "click", this.submit, this, true);
6875 E.on(this.cancelEl, "click", this.cancel, this, true);
6876 E.on(this.yearEl, "blur", yearUpdateHandler, this, true);
6877 E.on(this.monthEl, "change", monthUpdateHandler, this, true);
6879 if (this.__isIEQuirks) {
6880 YAHOO.util.Event.on(this.cal.oDomContainer, "resize", this._syncMask, this, true);
6883 this.applyKeyListeners();
6887 * Removes/purges DOM event listeners from the rendered elements
6889 * @method purgeListeners
6891 purgeListeners : function() {
6892 var E = YAHOO.util.Event;
6893 E.removeListener(this.submitEl, "click", this.submit);
6894 E.removeListener(this.cancelEl, "click", this.cancel);
6895 E.removeListener(this.yearEl, "blur");
6896 E.removeListener(this.monthEl, "change");
6897 if (this.__isIEQuirks) {
6898 E.removeListener(this.cal.oDomContainer, "resize", this._syncMask);
6901 this.purgeKeyListeners();
6905 * Attaches DOM listeners for keyboard support.
6906 * Tab/Shift-Tab looping, Enter Key Submit on Year element,
6907 * Up/Down/PgUp/PgDown year increment on Year element
6909 * NOTE: MacOSX Safari 2.x doesn't let you tab to buttons and
6910 * MacOSX Gecko does not let you tab to buttons or select controls,
6911 * so for these browsers, Tab/Shift-Tab looping is limited to the
6912 * elements which can be reached using the tab key.
6914 * @method applyKeyListeners
6916 applyKeyListeners : function() {
6917 var E = YAHOO.util.Event,
6920 // IE/Safari 3.1 doesn't fire keypress for arrow/pg keys (non-char keys)
6921 var arrowEvt = (ua.ie || ua.webkit) ? "keydown" : "keypress";
6923 // - IE/Safari 3.1 doesn't fire keypress for non-char keys
6924 // - Opera doesn't allow us to cancel keydown or keypress for tab, but
6925 // changes focus successfully on keydown (keypress is too late to change focus - opera's already moved on).
6926 var tabEvt = (ua.ie || ua.opera || ua.webkit) ? "keydown" : "keypress";
6928 // Everyone likes keypress for Enter (char keys) - whoo hoo!
6929 E.on(this.yearEl, "keypress", this._handleEnterKey, this, true);
6931 E.on(this.yearEl, arrowEvt, this._handleDirectionKeys, this, true);
6932 E.on(this.lastCtrl, tabEvt, this._handleTabKey, this, true);
6933 E.on(this.firstCtrl, tabEvt, this._handleShiftTabKey, this, true);
6937 * Removes/purges DOM listeners for keyboard support
6939 * @method purgeKeyListeners
6941 purgeKeyListeners : function() {
6942 var E = YAHOO.util.Event,
6945 var arrowEvt = (ua.ie || ua.webkit) ? "keydown" : "keypress";
6946 var tabEvt = (ua.ie || ua.opera || ua.webkit) ? "keydown" : "keypress";
6948 E.removeListener(this.yearEl, "keypress", this._handleEnterKey);
6949 E.removeListener(this.yearEl, arrowEvt, this._handleDirectionKeys);
6950 E.removeListener(this.lastCtrl, tabEvt, this._handleTabKey);
6951 E.removeListener(this.firstCtrl, tabEvt, this._handleShiftTabKey);
6955 * Updates the Calendar/CalendarGroup's pagedate with the currently set month and year if valid.
6957 * If the currently set month/year is invalid, a validation error will be displayed and the
6958 * Calendar/CalendarGroup's pagedate will not be updated.
6962 submit : function() {
6963 if (this.validate()) {
6966 this.setMonth(this._getMonthFromUI());
6967 this.setYear(this._getYearFromUI());
6971 // Artificial delay, just to help the user see something changed
6972 var delay = YAHOO.widget.CalendarNavigator.UPDATE_DELAY;
6975 window.setTimeout(function(){ nav._update(cal); }, delay);
6983 * Updates the Calendar rendered state, based on the state of the CalendarNavigator
6985 * @param cal The Calendar instance to update
6988 _update : function(cal) {
6989 var date = YAHOO.widget.DateMath.getDate(this.getYear() - cal.cfg.getProperty("YEAR_OFFSET"), this.getMonth(), 1);
6990 cal.cfg.setProperty("pagedate", date);
6995 * Hides the navigator and mask, without updating the Calendar/CalendarGroup's state
6999 cancel : function() {
7004 * Validates the current state of the UI controls
7007 * @return {Boolean} true, if the current UI state contains valid values, false if not
7009 validate : function() {
7010 if (this._getYearFromUI() !== null) {
7014 this.setYearError();
7015 this.setError(this.__getCfg("invalidYear", true));
7021 * Displays an error message in the Navigator's error panel.
7024 * @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.
7026 setError : function(msg) {
7028 this.errorEl.innerHTML = msg;
7029 this._show(this.errorEl, true);
7034 * Clears the navigator's error message and hides the error panel
7035 * @method clearError
7037 clearError : function() {
7039 this.errorEl.innerHTML = "";
7040 this._show(this.errorEl, false);
7045 * Displays the validation error UI for the year control
7046 * @method setYearError
7048 setYearError : function() {
7049 YAHOO.util.Dom.addClass(this.yearEl, YAHOO.widget.CalendarNavigator.CLASSES.INVALID);
7053 * Removes the validation error UI for the year control
7054 * @method clearYearError
7056 clearYearError : function() {
7057 YAHOO.util.Dom.removeClass(this.yearEl, YAHOO.widget.CalendarNavigator.CLASSES.INVALID);
7061 * Clears all validation and error messages in the UI
7062 * @method clearErrors
7064 clearErrors : function() {
7066 this.clearYearError();
7070 * Sets the initial focus, based on the configured value
7071 * @method setInitialFocus
7073 setInitialFocus : function() {
7074 var el = this.submitEl,
7075 f = this.__getCfg("initialFocus");
7077 if (f && f.toLowerCase) {
7078 f = f.toLowerCase();
7082 this.yearEl.select();
7086 } else if (f == "month") {
7091 if (el && YAHOO.lang.isFunction(el.focus)) {
7094 } catch (focusErr) {
7095 // TODO: Fall back if focus fails?
7101 * Removes all renderered HTML elements for the Navigator from
7102 * the DOM, purges event listeners and clears (nulls) any property
7103 * references to HTML references
7106 erase : function() {
7107 if (this.__rendered) {
7108 this.purgeListeners();
7110 // Clear out innerHTML references
7112 this.monthEl = null;
7113 this.errorEl = null;
7114 this.submitEl = null;
7115 this.cancelEl = null;
7116 this.firstCtrl = null;
7117 this.lastCtrl = null;
7119 this.navEl.innerHTML = "";
7122 var p = this.navEl.parentNode;
7124 p.removeChild(this.navEl);
7128 var pm = this.maskEl.parentNode;
7130 pm.removeChild(this.maskEl);
7133 this.__rendered = false;
7138 * Destroys the Navigator object and any HTML references
7141 destroy : function() {
7149 * Protected implementation to handle how UI elements are
7155 _show : function(el, bShow) {
7157 YAHOO.util.Dom.setStyle(el, "display", (bShow) ? "block" : "none");
7162 * Returns the month value (index), from the month UI element
7164 * @method _getMonthFromUI
7165 * @return {Number} The month index, or 0 if a UI element for the month
7168 _getMonthFromUI : function() {
7170 return this.monthEl.selectedIndex;
7172 return 0; // Default to Jan
7177 * Returns the year value, from the Navitator's year UI element
7179 * @method _getYearFromUI
7180 * @return {Number} The year value set in the UI, if valid. null is returned if
7181 * the UI does not contain a valid year value.
7183 _getYearFromUI : function() {
7184 var NAV = YAHOO.widget.CalendarNavigator;
7188 var value = this.yearEl.value;
7189 value = value.replace(NAV.TRIM, "$1");
7191 if (NAV.YR_PATTERN.test(value)) {
7192 yr = parseInt(value, 10);
7199 * Updates the Navigator's year UI, based on the year value set on the Navigator object
7201 * @method _updateYearUI
7203 _updateYearUI : function() {
7204 if (this.yearEl && this._year !== null) {
7205 this.yearEl.value = this._year;
7210 * Updates the Navigator's month UI, based on the month value set on the Navigator object
7212 * @method _updateMonthUI
7214 _updateMonthUI : function() {
7216 this.monthEl.selectedIndex = this._month;
7221 * Sets up references to the first and last focusable element in the Navigator's UI
7222 * in terms of tab order (Naviagator's firstEl and lastEl properties). The references
7223 * are used to control modality by looping around from the first to the last control
7224 * and visa versa for tab/shift-tab navigation.
7226 * See <a href="#applyKeyListeners">applyKeyListeners</a>
7229 * @method _setFirstLastElements
7231 _setFirstLastElements : function() {
7232 this.firstCtrl = this.monthEl;
7233 this.lastCtrl = this.cancelEl;
7235 // Special handling for MacOSX.
7236 // - Safari 2.x can't focus on buttons
7237 // - Gecko can't focus on select boxes or buttons
7239 if (YAHOO.env.ua.webkit && YAHOO.env.ua.webkit < 420){
7240 this.firstCtrl = this.monthEl;
7241 this.lastCtrl = this.yearEl;
7243 if (YAHOO.env.ua.gecko) {
7244 this.firstCtrl = this.yearEl;
7245 this.lastCtrl = this.yearEl;
7251 * Default Keyboard event handler to capture Enter
7252 * on the Navigator's year control (yearEl)
7254 * @method _handleEnterKey
7256 * @param {Event} e The DOM event being handled
7258 _handleEnterKey : function(e) {
7259 var KEYS = YAHOO.util.KeyListener.KEY;
7261 if (YAHOO.util.Event.getCharCode(e) == KEYS.ENTER) {
7262 YAHOO.util.Event.preventDefault(e);
7268 * Default Keyboard event handler to capture up/down/pgup/pgdown
7269 * on the Navigator's year control (yearEl).
7271 * @method _handleDirectionKeys
7273 * @param {Event} e The DOM event being handled
7275 _handleDirectionKeys : function(e) {
7276 var E = YAHOO.util.Event,
7277 KEYS = YAHOO.util.KeyListener.KEY,
7278 NAV = YAHOO.widget.CalendarNavigator;
7280 var value = (this.yearEl.value) ? parseInt(this.yearEl.value, 10) : null;
7281 if (isFinite(value)) {
7283 switch(E.getCharCode(e)) {
7285 this.yearEl.value = value + NAV.YR_MINOR_INC;
7289 this.yearEl.value = Math.max(value - NAV.YR_MINOR_INC, 0);
7293 this.yearEl.value = value + NAV.YR_MAJOR_INC;
7296 case KEYS.PAGE_DOWN:
7297 this.yearEl.value = Math.max(value - NAV.YR_MAJOR_INC, 0);
7304 E.preventDefault(e);
7306 this.yearEl.select();
7315 * Default Keyboard event handler to capture Tab
7316 * on the last control (lastCtrl) in the Navigator.
7318 * @method _handleTabKey
7320 * @param {Event} e The DOM event being handled
7322 _handleTabKey : function(e) {
7323 var E = YAHOO.util.Event,
7324 KEYS = YAHOO.util.KeyListener.KEY;
7326 if (E.getCharCode(e) == KEYS.TAB && !e.shiftKey) {
7328 E.preventDefault(e);
7329 this.firstCtrl.focus();
7331 // Ignore - mainly for focus edge cases
7337 * Default Keyboard event handler to capture Shift-Tab
7338 * on the first control (firstCtrl) in the Navigator.
7340 * @method _handleShiftTabKey
7342 * @param {Event} e The DOM event being handled
7344 _handleShiftTabKey : function(e) {
7345 var E = YAHOO.util.Event,
7346 KEYS = YAHOO.util.KeyListener.KEY;
7348 if (e.shiftKey && E.getCharCode(e) == KEYS.TAB) {
7350 E.preventDefault(e);
7351 this.lastCtrl.focus();
7353 // Ignore - mainly for focus edge cases
7359 * Retrieve Navigator configuration values from
7360 * the parent Calendar/CalendarGroup's config value.
7362 * If it has not been set in the user provided configuration, the method will
7363 * return the default value of the configuration property, as set in DEFAULT_CONFIG
7367 * @param {String} Case sensitive property name.
7368 * @param {Boolean} true, if the property is a string property, false if not.
7369 * @return The value of the configuration property
7371 __getCfg : function(prop, bIsStr) {
7372 var DEF_CFG = YAHOO.widget.CalendarNavigator.DEFAULT_CONFIG;
7373 var cfg = this.cal.cfg.getProperty("navigator");
7376 return (cfg !== true && cfg.strings && cfg.strings[prop]) ? cfg.strings[prop] : DEF_CFG.strings[prop];
7378 return (cfg !== true && cfg[prop]) ? cfg[prop] : DEF_CFG[prop];
7383 * Private flag, to identify MacOS
7387 __isMac : (navigator.userAgent.toLowerCase().indexOf("macintosh") != -1)
7390 YAHOO.register("calendar", YAHOO.widget.Calendar, {version: "2.9.0", build: "2800"});