src/cm/media/js/lib/yui/yui_3.10.3/build/calendar-base/calendar-base.js
changeset 525 89ef5ed3c48b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cm/media/js/lib/yui/yui_3.10.3/build/calendar-base/calendar-base.js	Tue Jul 16 14:29:46 2013 +0200
@@ -0,0 +1,1688 @@
+/*
+YUI 3.10.3 (build 2fb5187)
+Copyright 2013 Yahoo! Inc. All rights reserved.
+Licensed under the BSD License.
+http://yuilibrary.com/license/
+*/
+
+YUI.add('calendar-base', function (Y, NAME) {
+
+/**
+ * The CalendarBase submodule is a basic UI calendar view that displays
+ * a range of dates in a two-dimensional month grid, with one or more
+ * months visible at a single time. CalendarBase supports custom date
+ * rendering, multiple calendar panes, and selection.
+ * @module calendar
+ * @submodule calendar-base
+ */
+
+var getCN                 = Y.ClassNameManager.getClassName,
+    CALENDAR              = 'calendar',
+    CAL_GRID              = getCN(CALENDAR, 'grid'),
+    CAL_LEFT_GRID         = getCN(CALENDAR, 'left-grid'),
+    CAL_RIGHT_GRID        = getCN(CALENDAR, 'right-grid'),
+    CAL_BODY              = getCN(CALENDAR, 'body'),
+    CAL_HD                = getCN(CALENDAR, 'header'),
+    CAL_HD_LABEL          = getCN(CALENDAR, 'header-label'),
+    CAL_WDAYROW           = getCN(CALENDAR, 'weekdayrow'),
+    CAL_WDAY              = getCN(CALENDAR, 'weekday'),
+    CAL_COL_HIDDEN        = getCN(CALENDAR, 'column-hidden'),
+    CAL_DAY_SELECTED      = getCN(CALENDAR, 'day-selected'),
+    SELECTION_DISABLED    = getCN(CALENDAR, 'selection-disabled'),
+    CAL_ROW               = getCN(CALENDAR, 'row'),
+    CAL_DAY               = getCN(CALENDAR, 'day'),
+    CAL_PREVMONTH_DAY     = getCN(CALENDAR, 'prevmonth-day'),
+    CAL_NEXTMONTH_DAY     = getCN(CALENDAR, 'nextmonth-day'),
+    CAL_ANCHOR            = getCN(CALENDAR, 'anchor'),
+    CAL_PANE              = getCN(CALENDAR, 'pane'),
+    CAL_STATUS            = getCN(CALENDAR, 'status'),
+    L           = Y.Lang,
+    substitute  = L.sub,
+    arrayEach   = Y.Array.each,
+    objEach     = Y.Object.each,
+    iOf         = Y.Array.indexOf,
+    hasKey      = Y.Object.hasKey,
+    setVal      = Y.Object.setValue,
+    isEmpty     = Y.Object.isEmpty,
+    ydate       = Y.DataType.Date;
+
+/** Create a calendar view to represent a single or multiple
+    * month range of dates, rendered as a grid with date and
+    * weekday labels.
+    *
+    * @class CalendarBase
+    * @extends Widget
+    * @param config {Object} Configuration object (see Configuration
+    * attributes)
+    * @constructor
+    */
+function CalendarBase() {
+    CalendarBase.superclass.constructor.apply ( this, arguments );
+}
+
+
+
+Y.CalendarBase = Y.extend( CalendarBase, Y.Widget, {
+
+    /**
+     * A storage for various properties of individual month
+     * panes.
+     *
+     * @property _paneProperties
+     * @type Object
+     * @private
+     */
+    _paneProperties : {},
+
+    /**
+     * The number of month panes in the calendar, deduced
+     * from the CONTENT_TEMPLATE's number of {calendar_grid}
+     * tokens.
+     *
+     * @property _paneNumber
+     * @type Number
+     * @private
+     */
+    _paneNumber : 1,
+
+    /**
+     * The unique id used to prefix various elements of this
+     * calendar instance.
+     *
+     * @property _calendarId
+     * @type String
+     * @private
+     */
+    _calendarId : null,
+
+    /**
+     * The hash map of selected dates, populated with
+     * selectDates() and deselectDates() methods
+     *
+     * @property _selectedDates
+     * @type Object
+     * @private
+     */
+    _selectedDates : {},
+
+    /**
+     * A private copy of the rules object, populated
+     * by setting the customRenderer attribute.
+     *
+     * @property _rules
+     * @type Object
+     * @private
+     */
+    _rules : {},
+
+    /**
+     * A private copy of the filterFunction, populated
+     * by setting the customRenderer attribute.
+     *
+     * @property _filterFunction
+     * @type Function
+     * @private
+     */
+    _filterFunction : null,
+
+    /**
+     * Storage for calendar cells modified by any custom
+     * formatting. The storage is cleared, used to restore
+     * cells to the original state, and repopulated accordingly
+     * when the calendar is rerendered.
+     *
+     * @property _storedDateCells
+     * @type Object
+     * @private
+     */
+    _storedDateCells : {},
+
+    /**
+     * Designated initializer
+     * Initializes instance-level properties of
+     * calendar.
+     *
+     * @method initializer
+     */
+    initializer : function () {
+        this._paneProperties = {};
+        this._calendarId = Y.guid('calendar');
+        this._selectedDates = {};
+        if (isEmpty(this._rules)) {
+             this._rules = {};
+        }
+        this._storedDateCells = {};
+    },
+
+    /**
+     * renderUI implementation
+     *
+     * Creates a visual representation of the calendar based on existing parameters.
+     * @method renderUI
+     */
+    renderUI : function () {
+
+        var contentBox = this.get('contentBox');
+        contentBox.appendChild(this._initCalendarHTML(this.get('date')));
+
+        if (this.get('showPrevMonth')) {
+                this._afterShowPrevMonthChange();
+        }
+        if (this.get('showNextMonth')) {
+                this._afterShowNextMonthChange();
+        }
+
+        this._renderCustomRules();
+        this._renderSelectedDates();
+
+        this.get("boundingBox").setAttribute("aria-labelledby", this._calendarId + "_header");
+
+    },
+
+    /**
+     * bindUI implementation
+     *
+     * Assigns listeners to relevant events that change the state
+     * of the calendar.
+     * @method bindUI
+     */
+    bindUI : function () {
+        this.after('dateChange', this._afterDateChange);
+        this.after('showPrevMonthChange', this._afterShowPrevMonthChange);
+        this.after('showNextMonthChange', this._afterShowNextMonthChange);
+        this.after('headerRendererChange', this._afterHeaderRendererChange);
+        this.after('customRendererChange', this._afterCustomRendererChange);
+        this.after('enabledDatesRuleChange', this._afterCustomRendererChange);
+        this.after('disabledDatesRuleChange', this._afterCustomRendererChange);
+        this.after('focusedChange', this._afterFocusedChange);
+        this.after('selectionChange', this._renderSelectedDates);
+        this._bindCalendarEvents();
+    },
+
+
+    /**
+     * An internal utility method that generates a list of selected dates
+     * from the hash storage.
+     *
+     * @method _getSelectedDatesList
+     * @protected
+     * @return {Array} The array of `Date`s that are currently selected.
+     */
+    _getSelectedDatesList : function () {
+        var output = [];
+
+        objEach (this._selectedDates, function (year) {
+            objEach (year, function (month) {
+                objEach (month, function (day) {
+                    output.push (day);
+                }, this);
+            }, this);
+        }, this);
+
+        return output;
+    },
+
+    /**
+     * A utility method that returns all dates selected in a specific month.
+     *
+     * @method _getSelectedDatesInMonth
+     * @param {Date} oDate corresponding to the month for which selected dates
+     * are requested.
+     * @protected
+     * @return {Array} The array of `Date`s in a given month that are currently selected.
+     */
+    _getSelectedDatesInMonth : function (oDate) {
+        var year = oDate.getFullYear(),
+            month = oDate.getMonth();
+
+        if (hasKey(this._selectedDates, year) && hasKey(this._selectedDates[year], month)) {
+            return Y.Object.values(this._selectedDates[year][month]);
+        } else {
+            return [];
+        }
+    },
+
+
+    /**
+     * An internal parsing method that receives a String list of numbers
+     * and number ranges (of the form "1,2,3,4-6,7-9,10,11" etc.) and checks
+     * whether a specific number is included in this list. Used for looking
+     * up dates in the customRenderer rule set.
+     *
+     * @method _isNumInList
+     * @param {Number} num The number to look for in a list.
+     * @param {String} strList The list of numbers of the form "1,2,3,4-6,7-8,9", etc.
+     * @private
+     * @return {boolean} Returns true if the given number is in the given list.
+     */
+    _isNumInList : function (num, strList) {
+        if (strList === "all") {
+            return true;
+        } else {
+            var elements = strList.split(","),
+                i = elements.length,
+                range;
+
+            while (i--) {
+                range = elements[i].split("-");
+                if (range.length === 2 && num >= parseInt(range[0], 10) && num <= parseInt(range[1], 10)) {
+                    return true;
+                }
+                else if (range.length === 1 && (parseInt(elements[i], 10) === num)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    },
+
+    /**
+     * Given a specific date, returns an array of rules (from the customRenderer rule set)
+     * that the given date matches.
+     *
+     * @method _getRulesForDate
+     * @param {Date} oDate The date for which an array of rules is needed
+     * @private
+     * @return {Array} Returns an array of `String`s, each containg the name of
+     * a rule that the given date matches.
+     */
+    _getRulesForDate : function (oDate) {
+        var year = oDate.getFullYear(),
+                month = oDate.getMonth(),
+                date = oDate.getDate(),
+                wday = oDate.getDay(),
+                rules = this._rules,
+                outputRules = [],
+                years, months, dates, days;
+
+        for (years in rules) {
+            if (this._isNumInList(year, years)) {
+                if (L.isString(rules[years])) {
+                        outputRules.push(rules[years]);
+                }
+                else {
+                    for (months in rules[years]) {
+                        if (this._isNumInList(month, months)) {
+                            if (L.isString(rules[years][months])) {
+                                    outputRules.push(rules[years][months]);
+                            }
+                            else {
+                                for (dates in rules[years][months]) {
+                                    if (this._isNumInList(date, dates)) {
+                                        if (L.isString(rules[years][months][dates])) {
+                                                outputRules.push(rules[years][months][dates]);
+                                        }
+                                        else {
+                                            for (days in rules[years][months][dates]) {
+                                                if (this._isNumInList(wday, days)) {
+                                                    if (L.isString(rules[years][months][dates][days])) {
+                                                        outputRules.push(rules[years][months][dates][days]);
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return outputRules;
+    },
+
+    /**
+     * A utility method which, given a specific date and a name of the rule,
+     * checks whether the date matches the given rule.
+     *
+     * @method _matchesRule
+     * @param {Date} oDate The date to check
+     * @param {String} rule The name of the rule that the date should match.
+     * @private
+     * @return {boolean} Returns true if the date matches the given rule.
+     *
+     */
+    _matchesRule : function (oDate, rule) {
+        return (iOf(this._getRulesForDate(oDate), rule) >= 0);
+    },
+
+    /**
+     * A utility method which checks whether a given date matches the `enabledDatesRule`
+     * or does not match the `disabledDatesRule` and therefore whether it can be selected.
+     * @method _canBeSelected
+     * @param {Date} oDate The date to check
+     * @private
+     * @return {boolean} Returns true if the date can be selected; false otherwise.
+     */
+    _canBeSelected : function (oDate) {
+
+        var enabledDatesRule = this.get("enabledDatesRule"),
+            disabledDatesRule = this.get("disabledDatesRule");
+
+        if (enabledDatesRule) {
+            return this._matchesRule(oDate, enabledDatesRule);
+        } else if (disabledDatesRule) {
+            return !this._matchesRule(oDate, disabledDatesRule);
+        } else {
+            return true;
+        }
+    },
+
+    /**
+     * Selects a given date or array of dates.
+     * @method selectDates
+     * @param {Date|Array} dates A `Date` or `Array` of `Date`s.
+     * @return {CalendarBase} A reference to this object
+     * @chainable
+     */
+    selectDates : function (dates) {
+        if (ydate.isValidDate(dates)) {
+            this._addDateToSelection(dates);
+        }
+        else if (L.isArray(dates)) {
+            this._addDatesToSelection(dates);
+        }
+        return this;
+    },
+
+    /**
+     * Deselects a given date or array of dates, or deselects
+     * all dates if no argument is specified.
+     * @method deselectDates
+     * @param {Date|Array} [dates] A `Date` or `Array` of `Date`s, or no
+     * argument if all dates should be deselected.
+     * @return {CalendarBase} A reference to this object
+     * @chainable
+     */
+    deselectDates : function (dates) {
+        if (!dates) {
+            this._clearSelection();
+        }
+        else if (ydate.isValidDate(dates)) {
+            this._removeDateFromSelection(dates);
+        }
+        else if (L.isArray(dates)) {
+            this._removeDatesFromSelection(dates);
+        }
+        return this;
+    },
+
+    /**
+     * A utility method that adds a given date to selection..
+     * @method _addDateToSelection
+     * @param {Date} oDate The date to add to selection.
+     * @param {Number} [index] An optional parameter that is used
+     * to differentiate between individual date selections and multiple
+     * date selections.
+     * @private
+     */
+    _addDateToSelection : function (oDate, index) {
+
+        if (this._canBeSelected(oDate)) {
+
+            var year = oDate.getFullYear(),
+                month = oDate.getMonth(),
+                day = oDate.getDate();
+
+            if (hasKey(this._selectedDates, year)) {
+                if (hasKey(this._selectedDates[year], month)) {
+                    this._selectedDates[year][month][day] = oDate;
+                } else {
+                    this._selectedDates[year][month] = {};
+                    this._selectedDates[year][month][day] = oDate;
+                }
+            } else {
+                this._selectedDates[year] = {};
+                this._selectedDates[year][month] = {};
+                this._selectedDates[year][month][day] = oDate;
+            }
+
+            this._selectedDates = setVal(this._selectedDates, [year, month, day], oDate);
+
+            if (!index) {
+                this._fireSelectionChange();
+            }
+        }
+    },
+
+    /**
+     * A utility method that adds a given list of dates to selection.
+     * @method _addDatesToSelection
+     * @param {Array} datesArray The list of dates to add to selection.
+     * @private
+     */
+    _addDatesToSelection : function (datesArray) {
+        arrayEach(datesArray, this._addDateToSelection, this);
+        this._fireSelectionChange();
+    },
+
+    /**
+     * A utility method that adds a given range of dates to selection.
+     * @method _addDateRangeToSelection
+     * @param {Date} startDate The first date of the given range.
+     * @param {Date} endDate The last date of the given range.
+     * @private
+     */
+    _addDateRangeToSelection : function (startDate, endDate) {
+
+        var timezoneDifference = (endDate.getTimezoneOffset() - startDate.getTimezoneOffset())*60000,
+            startTime = startDate.getTime(),
+            endTime   = endDate.getTime(),
+            tempTime,
+            time,
+            addedDate;
+
+        if (startTime > endTime) {
+            tempTime = startTime;
+            startTime = endTime;
+            endTime = tempTime + timezoneDifference;
+        } else {
+            endTime = endTime - timezoneDifference;
+        }
+
+
+        for (time = startTime; time <= endTime; time += 86400000) {
+            addedDate = new Date(time);
+            addedDate.setHours(12);
+            this._addDateToSelection(addedDate, time);
+        }
+        this._fireSelectionChange();
+    },
+
+    /**
+     * A utility method that removes a given date from selection..
+     * @method _removeDateFromSelection
+     * @param {Date} oDate The date to remove from selection.
+     * @param {Number} [index] An optional parameter that is used
+     * to differentiate between individual date selections and multiple
+     * date selections.
+     * @private
+     */
+    _removeDateFromSelection : function (oDate, index) {
+        var year = oDate.getFullYear(),
+            month = oDate.getMonth(),
+            day = oDate.getDate();
+
+        if (hasKey(this._selectedDates, year) &&
+            hasKey(this._selectedDates[year], month) &&
+            hasKey(this._selectedDates[year][month], day)
+        ) {
+            delete this._selectedDates[year][month][day];
+            if (!index) {
+                this._fireSelectionChange();
+            }
+        }
+    },
+
+    /**
+     * A utility method that removes a given list of dates from selection.
+     * @method _removeDatesFromSelection
+     * @param {Array} datesArray The list of dates to remove from selection.
+     * @private
+     */
+    _removeDatesFromSelection : function (datesArray) {
+        arrayEach(datesArray, this._removeDateFromSelection, this);
+        this._fireSelectionChange();
+    },
+
+    /**
+     * A utility method that removes a given range of dates from selection.
+     * @method _removeDateRangeFromSelection
+     * @param {Date} startDate The first date of the given range.
+     * @param {Date} endDate The last date of the given range.
+     * @private
+     */
+    _removeDateRangeFromSelection : function (startDate, endDate) {
+        var startTime = startDate.getTime(),
+            endTime   = endDate.getTime(),
+            time;
+
+        for (time = startTime; time <= endTime; time += 86400000) {
+            this._removeDateFromSelection(new Date(time), time);
+        }
+
+        this._fireSelectionChange();
+    },
+
+    /**
+     * A utility method that removes all dates from selection.
+     * @method _clearSelection
+     * @param {boolean} noevent A Boolean specifying whether a selectionChange
+     * event should be fired. If true, the event is not fired.
+     * @private
+     */
+    _clearSelection : function (noevent) {
+        this._selectedDates = {};
+        this.get("contentBox").all("." + CAL_DAY_SELECTED).removeClass(CAL_DAY_SELECTED).setAttribute("aria-selected", false);
+        if (!noevent) {
+            this._fireSelectionChange();
+        }
+    },
+
+    /**
+     * A utility method that fires a selectionChange event.
+     * @method _fireSelectionChange
+     * @private
+     */
+    _fireSelectionChange : function () {
+
+        /**
+        * Fired when the set of selected dates changes. Contains a payload with
+        * a `newSelection` property with an array of selected dates.
+        *
+        * @event selectionChange
+        */
+        this.fire("selectionChange", {newSelection: this._getSelectedDatesList()});
+    },
+
+    /**
+     * A utility method that restores cells modified by custom formatting.
+     * @method _restoreModifiedCells
+     * @private
+     */
+    _restoreModifiedCells : function () {
+        var contentbox = this.get("contentBox"),
+            id;
+        for (id in this._storedDateCells) {
+            contentbox.one("#" + id).replace(this._storedDateCells[id]);
+            delete this._storedDateCells[id];
+        }
+    },
+
+    /**
+     * A rendering assist method that renders all cells modified by the customRenderer
+     * rules, as well as the enabledDatesRule and disabledDatesRule.
+     * @method _renderCustomRules
+     * @private
+     */
+    _renderCustomRules : function () {
+
+        this.get("contentBox").all("." + CAL_DAY + ",." + CAL_NEXTMONTH_DAY).removeClass(SELECTION_DISABLED).setAttribute("aria-disabled", false);
+
+        if (!isEmpty(this._rules)) {
+            var paneNum,
+                paneDate,
+                dateArray;
+
+            for (paneNum = 0; paneNum < this._paneNumber; paneNum++) {
+                paneDate = ydate.addMonths(this.get("date"), paneNum);
+                dateArray = ydate.listOfDatesInMonth(paneDate);
+                arrayEach(dateArray, Y.bind(this._renderCustomRulesHelper, this));
+            }
+        }
+    },
+
+    /**
+    * A handler for a date selection event (either a click or a keyboard
+    *   selection) that adds the appropriate CSS class to a specific DOM
+    *   node corresponding to the date and sets its aria-selected
+    *   attribute to true.
+    *
+    * @method _renderCustomRulesHelper
+    * @private
+    */
+    _renderCustomRulesHelper: function (date) {
+        var enRule = this.get("enabledDatesRule"),
+            disRule = this.get("disabledDatesRule"),
+            matchingRules,
+            dateNode;
+
+        matchingRules = this._getRulesForDate(date);
+        if (matchingRules.length > 0) {
+            dateNode = this._dateToNode(date);
+            if ((enRule && iOf(matchingRules, enRule) < 0) || (!enRule && disRule && iOf(matchingRules, disRule) >= 0)) {
+                dateNode.addClass(SELECTION_DISABLED).setAttribute("aria-disabled", true);
+            }
+
+            if (L.isFunction(this._filterFunction)) {
+                this._storedDateCells[dateNode.get("id")] = dateNode.cloneNode(true);
+                this._filterFunction (date, dateNode, matchingRules);
+            }
+        } else if (enRule) {
+             dateNode = this._dateToNode(date);
+             dateNode.addClass(SELECTION_DISABLED).setAttribute("aria-disabled", true);
+        }
+    },
+
+    /**
+     * A rendering assist method that renders all cells that are currently selected.
+     * @method _renderSelectedDates
+     * @private
+     */
+    _renderSelectedDates : function () {
+        this.get("contentBox").all("." + CAL_DAY_SELECTED).removeClass(CAL_DAY_SELECTED).setAttribute("aria-selected", false);
+
+        var paneNum,
+            paneDate,
+            dateArray;
+
+        for (paneNum = 0; paneNum < this._paneNumber; paneNum++) {
+            paneDate = ydate.addMonths(this.get("date"), paneNum);
+            dateArray = this._getSelectedDatesInMonth(paneDate);
+
+            arrayEach(dateArray, Y.bind(this._renderSelectedDatesHelper, this));
+        }
+    },
+
+    /**
+    * Takes in a date and determines whether that date has any rules
+    *   matching it in the customRenderer; then calls the specified
+    *   filterFunction if that's the case and/or disables the date
+    *   if the rule is specified as a disabledDatesRule.
+    *
+    * @method _renderSelectedDatesHelper
+    * @private
+    */
+    _renderSelectedDatesHelper: function (date) {
+        this._dateToNode(date).addClass(CAL_DAY_SELECTED).setAttribute("aria-selected", true);
+    },
+
+    /**
+     * A utility method that converts a date to the node wrapping the calendar cell
+     * the date corresponds to..
+     * @method _dateToNode
+     * @param {Date} oDate The date to convert to Node
+     * @protected
+     * @return {Node} The node wrapping the DOM element of the cell the date
+     * corresponds to.
+     */
+    _dateToNode : function (oDate) {
+        var day = oDate.getDate(),
+            col = 0,
+            daymod = day%7,
+            paneNum = (12 + oDate.getMonth() - this.get("date").getMonth()) % 12,
+            paneId = this._calendarId + "_pane_" + paneNum,
+            cutoffCol = this._paneProperties[paneId].cutoffCol;
+
+        switch (daymod) {
+            case (0):
+                if (cutoffCol >= 6) {
+                    col = 12;
+                } else {
+                    col = 5;
+                }
+                break;
+            case (1):
+                    col = 6;
+                break;
+            case (2):
+                if (cutoffCol > 0) {
+                    col = 7;
+                } else {
+                    col = 0;
+                }
+                break;
+            case (3):
+                if (cutoffCol > 1) {
+                    col = 8;
+                } else {
+                    col = 1;
+                }
+                break;
+            case (4):
+                if (cutoffCol > 2) {
+                    col = 9;
+                } else {
+                    col = 2;
+                }
+                break;
+            case (5):
+                if (cutoffCol > 3) {
+                    col = 10;
+                } else {
+                    col = 3;
+                }
+                break;
+            case (6):
+                if (cutoffCol > 4) {
+                    col = 11;
+                } else {
+                    col = 4;
+                }
+                break;
+        }
+        return(this.get("contentBox").one("#" + this._calendarId + "_pane_" + paneNum + "_" + col + "_" + day));
+
+    },
+
+    /**
+     * A utility method that converts a node corresponding to the DOM element of
+     * the cell for a particular date to that date.
+     * @method _nodeToDate
+     * @param {Node} oNode The Node wrapping the DOM element of a particular date cell.
+     * @protected
+     * @return {Date} The date corresponding to the DOM element that the given node wraps.
+     */
+    _nodeToDate : function (oNode) {
+
+        var idParts = oNode.get("id").split("_").reverse(),
+            paneNum = parseInt(idParts[2], 10),
+            day  = parseInt(idParts[0], 10),
+            shiftedDate = ydate.addMonths(this.get("date"), paneNum),
+            year = shiftedDate.getFullYear(),
+            month = shiftedDate.getMonth();
+
+        return new Date(year, month, day, 12, 0, 0, 0);
+    },
+
+    /**
+     * A placeholder method, called from bindUI, to bind the Calendar events.
+     * @method _bindCalendarEvents
+     * @protected
+     */
+    _bindCalendarEvents : function () {},
+
+    /**
+     * A utility method that normalizes a given date by converting it to the 1st
+     * day of the month the date is in, with the time set to noon.
+     * @method _normalizeDate
+     * @param {Date} oDate The date to normalize
+     * @protected
+     * @return {Date} The normalized date, set to the first of the month, with time
+     * set to noon.
+     */
+    _normalizeDate : function (date) {
+        if (date) {
+            return new Date(date.getFullYear(), date.getMonth(), 1, 12, 0, 0, 0);
+        } else {
+            return null;
+        }
+    },
+
+
+    /**
+     * A render assist utility method that computes the cutoff column for the calendar
+     * rendering mask.
+     * @method _getCutoffColumn
+     * @param {Date} date The date of the month grid to compute the cutoff column for.
+     * @param {Number} firstday The first day of the week (modified by internationalized calendars)
+     * @private
+     * @return {Number} The number of the cutoff column.
+     */
+    _getCutoffColumn : function (date, firstday) {
+        var distance = this._normalizeDate(date).getDay() - firstday,
+            cutOffColumn = 6 - (distance + 7) % 7;
+        return cutOffColumn;
+    },
+
+    /**
+     * A render assist method that turns on the view of the previous month's dates
+     * in a given calendar pane.
+     * @method _turnPrevMonthOn
+     * @param {Node} pane The calendar pane that needs its previous month's dates view
+     * modified.
+     * @protected
+     */
+    _turnPrevMonthOn : function (pane) {
+        var pane_id = pane.get("id"),
+            pane_date = this._paneProperties[pane_id].paneDate,
+            daysInPrevMonth = ydate.daysInMonth(ydate.addMonths(pane_date, -1)),
+            cell;
+
+        if (!this._paneProperties[pane_id].hasOwnProperty("daysInPrevMonth")) {
+            this._paneProperties[pane_id].daysInPrevMonth = 0;
+        }
+
+        if (daysInPrevMonth !== this._paneProperties[pane_id].daysInPrevMonth) {
+
+            this._paneProperties[pane_id].daysInPrevMonth = daysInPrevMonth;
+
+            for (cell = 5; cell >= 0; cell--) {
+                pane.one("#" + pane_id + "_" + cell + "_" + (cell-5)).set('text', daysInPrevMonth--);
+            }
+        }
+    },
+
+    /**
+     * A render assist method that turns off the view of the previous month's dates
+     * in a given calendar pane.
+     * @method _turnPrevMonthOff
+     * @param {Node} pane The calendar pane that needs its previous month's dates view
+     * modified.
+     * @protected
+     */
+    _turnPrevMonthOff : function (pane) {
+        var pane_id = pane.get("id"),
+            cell;
+
+        this._paneProperties[pane_id].daysInPrevMonth = 0;
+
+        for (cell = 5; cell >= 0; cell--) {
+            pane.one("#" + pane_id + "_" + cell + "_" + (cell-5)).setContent("&nbsp;");
+        }
+    },
+
+    /**
+     * A render assist method that cleans up the last few cells in the month grid
+     * when the number of days in the month changes.
+     * @method _cleanUpNextMonthCells
+     * @param {Node} pane The calendar pane that needs the last date cells cleaned up.
+     * @private
+     */
+    _cleanUpNextMonthCells : function (pane) {
+        var pane_id = pane.get("id");
+            pane.one("#" + pane_id + "_6_29").removeClass(CAL_NEXTMONTH_DAY);
+            pane.one("#" + pane_id + "_7_30").removeClass(CAL_NEXTMONTH_DAY);
+            pane.one("#" + pane_id + "_8_31").removeClass(CAL_NEXTMONTH_DAY);
+            pane.one("#" + pane_id + "_0_30").removeClass(CAL_NEXTMONTH_DAY);
+            pane.one("#" + pane_id + "_1_31").removeClass(CAL_NEXTMONTH_DAY);
+    },
+
+    /**
+     * A render assist method that turns on the view of the next month's dates
+     * in a given calendar pane.
+     * @method _turnNextMonthOn
+     * @param {Node} pane The calendar pane that needs its next month's dates view
+     * modified.
+     * @protected
+     */
+    _turnNextMonthOn : function (pane) {
+        var dayCounter = 1,
+            pane_id = pane.get("id"),
+            daysInMonth = this._paneProperties[pane_id].daysInMonth,
+            cutoffCol = this._paneProperties[pane_id].cutoffCol,
+            cell,
+            startingCell;
+
+        for (cell = daysInMonth - 22; cell < cutoffCol + 7; cell++) {
+            pane.one("#" + pane_id + "_" + cell + "_" + (cell+23)).set("text", dayCounter++).addClass(CAL_NEXTMONTH_DAY);
+        }
+
+        startingCell = cutoffCol;
+
+        if (daysInMonth === 31 && (cutoffCol <= 1)) {
+            startingCell = 2;
+        } else if (daysInMonth === 30 && cutoffCol === 0) {
+            startingCell = 1;
+        }
+
+        for (cell = startingCell ; cell < cutoffCol + 7; cell++) {
+            pane.one("#" + pane_id + "_" + cell + "_" + (cell+30)).set("text", dayCounter++).addClass(CAL_NEXTMONTH_DAY);
+        }
+    },
+
+    /**
+     * A render assist method that turns off the view of the next month's dates
+     * in a given calendar pane.
+     * @method _turnNextMonthOff
+     * @param {Node} pane The calendar pane that needs its next month's dates view
+     * modified.
+     * @protected
+     */
+    _turnNextMonthOff : function (pane) {
+            var pane_id = pane.get("id"),
+                daysInMonth = this._paneProperties[pane_id].daysInMonth,
+                cutoffCol = this._paneProperties[pane_id].cutoffCol,
+                cell,
+                startingCell;
+
+            for (cell = daysInMonth - 22; cell <= 12; cell++) {
+                pane.one("#" + pane_id + "_" + cell + "_" + (cell+23)).setContent("&nbsp;").addClass(CAL_NEXTMONTH_DAY);
+            }
+
+            startingCell = 0;
+
+            if (daysInMonth === 31 && (cutoffCol <= 1)) {
+                startingCell = 2;
+            } else if (daysInMonth === 30 && cutoffCol === 0) {
+                startingCell = 1;
+            }
+
+            for (cell = startingCell ; cell <= 12; cell++) {
+                pane.one("#" + pane_id + "_" + cell + "_" + (cell+30)).setContent("&nbsp;").addClass(CAL_NEXTMONTH_DAY);
+            }
+    },
+
+    /**
+     * The handler for the change in the showNextMonth attribute.
+     * @method _afterShowNextMonthChange
+     * @private
+     */
+    _afterShowNextMonthChange : function () {
+
+        var contentBox = this.get('contentBox'),
+            lastPane = contentBox.one("#" + this._calendarId + "_pane_" + (this._paneNumber - 1));
+
+        this._cleanUpNextMonthCells(lastPane);
+
+        if (this.get('showNextMonth')) {
+            this._turnNextMonthOn(lastPane);
+        } else {
+            this._turnNextMonthOff(lastPane);
+        }
+
+    },
+
+    /**
+     * The handler for the change in the showPrevMonth attribute.
+     * @method _afterShowPrevMonthChange
+     * @private
+     */
+    _afterShowPrevMonthChange : function () {
+        var contentBox = this.get('contentBox'),
+            firstPane = contentBox.one("#" + this._calendarId + "_pane_" + 0);
+
+        if (this.get('showPrevMonth')) {
+            this._turnPrevMonthOn(firstPane);
+        } else {
+            this._turnPrevMonthOff(firstPane);
+        }
+
+    },
+
+     /**
+     * The handler for the change in the headerRenderer attribute.
+     * @method _afterHeaderRendererChange
+     * @private
+     */
+    _afterHeaderRendererChange : function () {
+        var headerCell = this.get("contentBox").one("." + CAL_HD_LABEL);
+        headerCell.setContent(this._updateCalendarHeader(this.get('date')));
+    },
+
+     /**
+     * The handler for the change in the customRenderer attribute.
+     * @method _afterCustomRendererChange
+     * @private
+     */
+    _afterCustomRendererChange : function () {
+        this._restoreModifiedCells();
+        this._renderCustomRules();
+    },
+
+     /**
+     * The handler for the change in the date attribute. Modifies the calendar
+     * view by shifting the calendar grid mask and running custom rendering and
+     * selection rendering as necessary.
+     * @method _afterDateChange
+     * @private
+     */
+    _afterDateChange : function () {
+
+        var contentBox = this.get('contentBox'),
+            headerCell = contentBox.one("." + CAL_HD).one("." + CAL_HD_LABEL),
+            calendarPanes = contentBox.all("." + CAL_GRID),
+            currentDate = this.get("date"),
+            counter = 0;
+
+        contentBox.setStyle("visibility", "hidden");
+        headerCell.setContent(this._updateCalendarHeader(currentDate));
+
+        this._restoreModifiedCells();
+
+        calendarPanes.each(function (curNode) {
+            this._rerenderCalendarPane(ydate.addMonths(currentDate, counter++), curNode);
+        }, this);
+
+        this._afterShowPrevMonthChange();
+        this._afterShowNextMonthChange();
+
+        this._renderCustomRules();
+        this._renderSelectedDates();
+
+        contentBox.setStyle("visibility", "visible");
+    },
+
+
+     /**
+     * A rendering assist method that initializes the HTML for a single
+     * calendar pane.
+     * @method _initCalendarPane
+     * @param {Date} baseDate The date corresponding to the month of the given
+     * calendar pane.
+     * @param {String} pane_id The id of the pane, to be used as a prefix for
+     * element ids in the given pane.
+     * @private
+     */
+    _initCalendarPane : function (baseDate, pane_id) {
+        // Get a list of short weekdays from the internationalization package, or else use default English ones.
+        var weekdays = this.get('strings.very_short_weekdays') || ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+            fullweekdays = this.get('strings.weekdays') || ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+            // Get the first day of the week from the internationalization package, or else use Sunday as default.
+            firstday = this.get('strings.first_weekday') || 0,
+            // Compute the cutoff column of the masked calendar table, based on the start date and the first day of week.
+            cutoffCol = this._getCutoffColumn(baseDate, firstday),
+            // Compute the number of days in the month based on starting date
+            daysInMonth = ydate.daysInMonth(baseDate),
+            // Initialize the array of individual row HTML strings
+            row_array = ['','','','','',''],
+            // Initialize the partial templates object
+            partials = {},
+
+            day,
+            row,
+            column,
+            date,
+            id_date,
+            calendar_day_class,
+            column_visibility,
+            output;
+
+            // Initialize the partial template for the weekday row cells.
+            partials.weekday_row = '';
+
+        // Populate the partial template for the weekday row cells with weekday names
+        for (day = firstday; day <= firstday + 6; day++) {
+            partials.weekday_row +=
+                substitute(CalendarBase.WEEKDAY_TEMPLATE, {
+                    weekdayname: weekdays[day%7],
+                    full_weekdayname: fullweekdays[day%7]
+                });
+        }
+
+        // Populate the partial template for the weekday row container with the weekday row cells
+        partials.weekday_row_template = substitute(CalendarBase.WEEKDAY_ROW_TEMPLATE, partials);
+
+        // Populate the array of individual row HTML strings
+        for (row = 0; row <= 5; row++) {
+
+            for (column = 0; column <= 12; column++) {
+
+                // Compute the value of the date that needs to populate the cell
+                date = 7*row - 5 + column;
+
+                // Compose the value of the unique id of the current calendar cell
+                id_date = pane_id + "_" + column + "_" + date;
+
+                // Set the calendar day class to one of three possible values
+                calendar_day_class = CAL_DAY;
+
+                if (date < 1) {
+                    calendar_day_class = CAL_PREVMONTH_DAY;
+                } else if (date > daysInMonth) {
+                    calendar_day_class = CAL_NEXTMONTH_DAY;
+                }
+
+                // Cut off dates that fall before the first and after the last date of the month
+                if (date < 1 || date > daysInMonth) {
+                    date = "&nbsp;";
+                }
+
+                // Decide on whether a column in the masked table is visible or not based on the value of the cutoff column.
+                column_visibility = (column >= cutoffCol && column < (cutoffCol + 7)) ? '' : CAL_COL_HIDDEN;
+
+                // Substitute the values into the partial calendar day template and add it to the current row HTML string
+                row_array[row] += substitute (CalendarBase.CALDAY_TEMPLATE, {
+                    day_content: date,
+                    calendar_col_class: "calendar_col" + column,
+                    calendar_col_visibility_class: column_visibility,
+                    calendar_day_class: calendar_day_class,
+                    calendar_day_id: id_date
+                });
+            }
+        }
+
+        // Instantiate the partial calendar pane body template
+        partials.body_template = '';
+
+        // Populate the body template with the rows templates
+        arrayEach (row_array, function (v) {
+             partials.body_template += substitute(CalendarBase.CALDAY_ROW_TEMPLATE, {calday_row: v});
+        });
+
+        // Populate the calendar grid id
+        partials.calendar_pane_id = pane_id;
+
+        // Populate the calendar pane tabindex
+        partials.calendar_pane_tabindex = this.get("tabIndex");
+        partials.pane_arialabel = ydate.format(baseDate, { format: "%B %Y" });
+
+
+        // Generate final output by substituting class names.
+        output = substitute(substitute (CalendarBase.CALENDAR_GRID_TEMPLATE, partials),
+                                                        CalendarBase.CALENDAR_STRINGS);
+
+        // Store the initialized pane information
+        this._paneProperties[pane_id] = {cutoffCol: cutoffCol, daysInMonth: daysInMonth, paneDate: baseDate};
+
+        return output;
+    },
+
+     /**
+     * A rendering assist method that rerenders a specified calendar pane, based
+     * on a new Date.
+     * @method _rerenderCalendarPane
+     * @param {Date} newDate The date corresponding to the month of the given
+     * calendar pane.
+     * @param {Node} pane The node corresponding to the calendar pane to be rerenders.
+     * @private
+     */
+    _rerenderCalendarPane : function (newDate, pane) {
+
+        // Get the first day of the week from the internationalization package, or else use Sunday as default.
+        var firstday = this.get('strings.first_weekday') || 0,
+            // Compute the cutoff column of the masked calendar table, based on the start date and the first day of week.
+            cutoffCol = this._getCutoffColumn(newDate, firstday),
+            // Compute the number of days in the month based on starting date
+            daysInMonth = ydate.daysInMonth(newDate),
+            // Get pane id for easier reference
+            paneId = pane.get("id"),
+            column,
+            currentColumn,
+            curCell;
+
+        // Hide the pane before making DOM changes to speed them up
+        pane.setStyle("visibility", "hidden");
+        pane.setAttribute("aria-label", ydate.format(newDate, {format:"%B %Y"}));
+
+        // Go through all columns, and flip their visibility setting based on whether they are within the unmasked range.
+        for (column = 0; column <= 12; column++) {
+            currentColumn = pane.all("." + "calendar_col" + column);
+            currentColumn.removeClass(CAL_COL_HIDDEN);
+
+            if (column < cutoffCol || column >= (cutoffCol + 7)) {
+                currentColumn.addClass(CAL_COL_HIDDEN);
+            } else {
+                // Clean up dates in visible columns to account for the correct number of days in a month
+                switch(column) {
+                    case 0:
+                        curCell = pane.one("#" + paneId + "_0_30");
+                        if (daysInMonth >= 30) {
+                            curCell.set("text", "30");
+                            curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
+                        } else {
+                            curCell.setContent("&nbsp;");
+                            curCell.addClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
+                        }
+                        break;
+                    case 1:
+                        curCell = pane.one("#" + paneId + "_1_31");
+                        if (daysInMonth >= 31) {
+                            curCell.set("text", "31");
+                            curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
+                        } else {
+                            curCell.setContent("&nbsp;");
+                            curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
+                        }
+                        break;
+                    case 6:
+                        curCell = pane.one("#" + paneId + "_6_29");
+                        if (daysInMonth >= 29) {
+                            curCell.set("text", "29");
+                            curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
+                        } else {
+                            curCell.setContent("&nbsp;");
+                            curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
+                        }
+                        break;
+                    case 7:
+                        curCell = pane.one("#" + paneId + "_7_30");
+                        if (daysInMonth >= 30) {
+                            curCell.set("text", "30");
+                            curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
+                        } else {
+                            curCell.setContent("&nbsp;");
+                            curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
+                        }
+                        break;
+                    case 8:
+                        curCell = pane.one("#" + paneId + "_8_31");
+                        if (daysInMonth >= 31) {
+                            curCell.set("text", "31");
+                            curCell.removeClass(CAL_NEXTMONTH_DAY).addClass(CAL_DAY);
+                        } else {
+                            curCell.setContent("&nbsp;");
+                            curCell.removeClass(CAL_DAY).addClass(CAL_NEXTMONTH_DAY);
+                        }
+                        break;
+                }
+            }
+        }
+
+        // Update stored pane properties
+        this._paneProperties[paneId].cutoffCol = cutoffCol;
+        this._paneProperties[paneId].daysInMonth = daysInMonth;
+        this._paneProperties[paneId].paneDate = newDate;
+
+        // Bring the pane visibility back after all DOM changes are done
+        pane.setStyle("visibility", "visible");
+
+    },
+
+     /**
+     * A rendering assist method that updates the calendar header based
+     * on a given date and potentially the provided headerRenderer.
+     * @method _updateCalendarHeader
+     * @param {Date} baseDate The date with which to update the calendar header.
+     * @private
+     */
+    _updateCalendarHeader : function (baseDate) {
+        var headerString = "",
+            headerRenderer = this.get("headerRenderer");
+
+        if (Y.Lang.isString(headerRenderer)) {
+            headerString = ydate.format(baseDate, {format:headerRenderer});
+        } else if (headerRenderer instanceof Function) {
+            headerString = headerRenderer.call(this, baseDate);
+        }
+
+        return headerString;
+    },
+
+     /**
+     * A rendering assist method that initializes the calendar header HTML
+     * based on a given date and potentially the provided headerRenderer.
+     * @method _updateCalendarHeader
+     * @param {Date} baseDate The date with which to initialize the calendar header.
+     * @private
+     */
+    _initCalendarHeader : function (baseDate) {
+        return substitute(substitute(CalendarBase.HEADER_TEMPLATE, {
+                calheader: this._updateCalendarHeader(baseDate),
+                calendar_id: this._calendarId
+            }), CalendarBase.CALENDAR_STRINGS );
+    },
+
+     /**
+     * A rendering assist method that initializes the calendar HTML
+     * based on a given date.
+     * @method _initCalendarHTML
+     * @param {Date} baseDate The date with which to initialize the calendar.
+     * @private
+     */
+    _initCalendarHTML : function (baseDate) {
+        // Instantiate the partials holder
+        var partials = {},
+            // Counter for iterative template replacement.
+            counter = 0,
+            singlePane,
+            output;
+
+        // Generate the template for the header
+        partials.header_template =  this._initCalendarHeader(baseDate);
+        partials.calendar_id = this._calendarId;
+
+        partials.body_template = substitute(substitute (CalendarBase.CONTENT_TEMPLATE, partials),
+                                                                                 CalendarBase.CALENDAR_STRINGS);
+
+        // Instantiate the iterative template replacer function
+        function paneReplacer () {
+            singlePane = this._initCalendarPane(ydate.addMonths(baseDate, counter), partials.calendar_id + "_pane_" + counter);
+            counter++;
+            return singlePane;
+        }
+
+        // Go through all occurrences of the calendar_grid_template token and replace it with an appropriate calendar grid.
+        output = partials.body_template.replace(/\{calendar_grid_template\}/g, Y.bind(paneReplacer, this));
+
+        // Update the paneNumber count
+        this._paneNumber = counter;
+
+        return output;
+    }
+}, {
+
+     /**
+        * The CSS classnames for the calendar templates.
+        * @property CALENDAR_STRINGS
+        * @type Object
+        * @readOnly
+        * @protected
+        * @static
+        */
+    CALENDAR_STRINGS: {
+        calendar_grid_class       : CAL_GRID,
+        calendar_body_class       : CAL_BODY,
+        calendar_hd_class         : CAL_HD,
+        calendar_hd_label_class   : CAL_HD_LABEL,
+        calendar_weekdayrow_class : CAL_WDAYROW,
+        calendar_weekday_class    : CAL_WDAY,
+        calendar_row_class        : CAL_ROW,
+        calendar_day_class        : CAL_DAY,
+        calendar_dayanchor_class  : CAL_ANCHOR,
+        calendar_pane_class       : CAL_PANE,
+        calendar_right_grid_class : CAL_RIGHT_GRID,
+        calendar_left_grid_class  : CAL_LEFT_GRID,
+        calendar_status_class     : CAL_STATUS
+    },
+
+    /*
+
+    ARIA_STATUS_TEMPLATE: '<div role="status" aria-atomic="true" class="{calendar_status_class}"></div>',
+
+    AriaStatus : null,
+
+    updateStatus : function (statusString) {
+
+        if (!CalendarBase.AriaStatus) {
+            CalendarBase.AriaStatus = create(
+                                                         substitute (CalendarBase.ARIA_STATUS_TEMPLATE,
+                                                                                 CalendarBase.CALENDAR_STRINGS));
+            Y.one("body").append(CalendarBase.AriaStatus);
+        }
+
+            CalendarBase.AriaStatus.set("text", statusString);
+    },
+
+    */
+
+     /**
+        * The main content template for calendar.
+        * @property CONTENT_TEMPLATE
+        * @type String
+        * @protected
+        * @static
+        */
+    CONTENT_TEMPLATE:  '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' +
+                        '{header_template}' +
+                        '<div class="yui3-u-1">' +
+                        '{calendar_grid_template}' +
+                        '</div>' +
+                        '</div>',
+
+     /**
+        * A single pane template for calendar (same as default CONTENT_TEMPLATE)
+        * @property ONE_PANE_TEMPLATE
+        * @type String
+        * @protected
+        * @readOnly
+        * @static
+        */
+    ONE_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' +
+                            '{header_template}' +
+                            '<div class="yui3-u-1">' +
+                                '{calendar_grid_template}' +
+                            '</div>' +
+                        '</div>',
+
+     /**
+        * A two pane template for calendar.
+        * @property TWO_PANE_TEMPLATE
+        * @type String
+        * @protected
+        * @readOnly
+        * @static
+        */
+    TWO_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' +
+                            '{header_template}' +
+                            '<div class="yui3-u-1-2">'+
+                                '<div class = "{calendar_left_grid_class}">' +
+                                    '{calendar_grid_template}' +
+                                '</div>' +
+                            '</div>' +
+                            '<div class="yui3-u-1-2">' +
+                                '<div class = "{calendar_right_grid_class}">' +
+                                    '{calendar_grid_template}' +
+                                '</div>' +
+                            '</div>' +
+                        '</div>',
+     /**
+        * A three pane template for calendar.
+        * @property THREE_PANE_TEMPLATE
+        * @type String
+        * @protected
+        * @readOnly
+        * @static
+        */
+    THREE_PANE_TEMPLATE: '<div class="yui3-g {calendar_pane_class}" id="{calendar_id}">' +
+                            '{header_template}' +
+                            '<div class="yui3-u-1-3">' +
+                                '<div class="{calendar_left_grid_class}">' +
+                                    '{calendar_grid_template}' +
+                                '</div>' +
+                            '</div>' +
+                            '<div class="yui3-u-1-3">' +
+                                '{calendar_grid_template}' +
+                            '</div>' +
+                            '<div class="yui3-u-1-3">' +
+                                '<div class="{calendar_right_grid_class}">' +
+                                    '{calendar_grid_template}' +
+                                '</div>' +
+                            '</div>' +
+                        '</div>',
+     /**
+        * A template for the calendar grid.
+        * @property CALENDAR_GRID_TEMPLATE
+        * @type String
+        * @protected
+        * @static
+        */
+    CALENDAR_GRID_TEMPLATE: '<table class="{calendar_grid_class}" id="{calendar_pane_id}" role="grid" aria-readonly="true" ' +
+                                'aria-label="{pane_arialabel}" tabindex="{calendar_pane_tabindex}">' +
+                                '<thead>' +
+                                    '{weekday_row_template}' +
+                                '</thead>' +
+                                '<tbody>' +
+                                    '{body_template}' +
+                                '</tbody>' +
+                            '</table>',
+
+     /**
+        * A template for the calendar header.
+        * @property HEADER_TEMPLATE
+        * @type String
+        * @protected
+        * @static
+        */
+    HEADER_TEMPLATE: '<div class="yui3-g {calendar_hd_class}">' +
+                        '<div class="yui3-u {calendar_hd_label_class}" id="{calendar_id}_header" aria-role="heading">' +
+                            '{calheader}' +
+                        '</div>' +
+                    '</div>',
+
+     /**
+        * A template for the row of weekday names.
+        * @property WEEKDAY_ROW_TEMPLATE
+        * @type String
+        * @protected
+        * @static
+        */
+    WEEKDAY_ROW_TEMPLATE: '<tr class="{calendar_weekdayrow_class}" role="row">' +
+                            '{weekday_row}' +
+                        '</tr>',
+
+     /**
+        * A template for a single row of calendar days.
+        * @property CALDAY_ROW_TEMPLATE
+        * @type String
+        * @protected
+        * @static
+        */
+    CALDAY_ROW_TEMPLATE: '<tr class="{calendar_row_class}" role="row">' +
+                            '{calday_row}' +
+                        '</tr>',
+
+     /**
+        * A template for a single cell with a weekday name.
+        * @property CALDAY_ROW_TEMPLATE
+        * @type String
+        * @protected
+        * @static
+        */
+    WEEKDAY_TEMPLATE: '<th class="{calendar_weekday_class}" role="columnheader" aria-label="{full_weekdayname}">{weekdayname}</th>',
+
+     /**
+        * A template for a single cell with a calendar day.
+        * @property CALDAY_TEMPLATE
+        * @type String
+        * @protected
+        * @static
+        */
+    CALDAY_TEMPLATE: '<td class="{calendar_col_class} {calendar_day_class} {calendar_col_visibility_class}" id="{calendar_day_id}" ' +
+                        'role="gridcell" tabindex="-1">' +
+                        '{day_content}' +
+                    '</td>',
+
+     /**
+        * The identity of the widget.
+        *
+        * @property NAME
+        * @type String
+        * @default 'calendarBase'
+        * @readOnly
+        * @protected
+        * @static
+        */
+    NAME: 'calendarBase',
+
+     /**
+        * Static property used to define the default attribute configuration of
+        * the Widget.
+        *
+        * @property ATTRS
+        * @type {Object}
+        * @protected
+        * @static
+        */
+    ATTRS: {
+        tabIndex: {
+            value: 1
+        },
+        /**
+         * The date corresponding to the current calendar view. Always
+         * normalized to the first of the month that contains the date
+         * at assignment time. Used as the first date visible in the
+         * calendar.
+         *
+         * @attribute date
+         * @type Date
+         * @default The first of the month containing today's date, as
+         * set on the end user's system.
+         */
+        date: {
+            value: new Date(),
+            setter: function (val) {
+                var newDate = this._normalizeDate(val);
+                if (ydate.areEqual(newDate, this.get('date'))) {
+                        return this.get('date');
+                } else {
+                        return newDate;
+                }
+            }
+        },
+
+        /**
+         * A setting specifying whether to shows days from the previous
+         * month in the visible month's grid, if there are empty preceding
+         * cells available.
+         *
+         * @attribute showPrevMonth
+         * @type boolean
+         * @default false
+         */
+        showPrevMonth: {
+            value: false
+        },
+
+        /**
+         * A setting specifying whether to shows days from the next
+         * month in the visible month's grid, if there are empty
+         * cells available at the end.
+         *
+         * @attribute showNextMonth
+         * @type boolean
+         * @default false
+         */
+        showNextMonth: {
+            value: false
+        },
+
+        /**
+         * Strings and properties derived from the internationalization packages
+         * for the calendar.
+         *
+         * @attribute strings
+         * @type Object
+         * @protected
+         */
+        strings : {
+            valueFn: function() { return Y.Intl.get("calendar-base"); }
+        },
+
+        /**
+         * Custom header renderer for the calendar.
+         *
+         * @attribute headerRenderer
+         * @type String | Function
+         */
+        headerRenderer: {
+            value: "%B %Y"
+        },
+
+        /**
+         * The name of the rule which all enabled dates should match.
+         * Either disabledDatesRule or enabledDatesRule should be specified,
+         * or neither, but not both.
+         *
+         * @attribute enabledDatesRule
+         * @type String
+         * @default null
+         */
+        enabledDatesRule: {
+            value: null
+        },
+
+        /**
+         * The name of the rule which all disabled dates should match.
+         * Either disabledDatesRule or enabledDatesRule should be specified,
+         * or neither, but not both.
+         *
+         * @attribute disabledDatesRule
+         * @type String
+         * @default null
+         */
+        disabledDatesRule: {
+            value: null
+        },
+
+        /**
+         * A read-only attribute providing a list of currently selected dates.
+         *
+         * @attribute selectedDates
+         * @readOnly
+         * @type Array
+         */
+        selectedDates : {
+            readOnly: true,
+            getter: function () {
+                return (this._getSelectedDatesList());
+            }
+        },
+
+        /**
+         * An object of the form {rules:Object, filterFunction:Function},
+         * providing  set of rules and a custom rendering function for
+         * customizing specific calendar cells.
+         *
+         * @attribute customRenderer
+         * @readOnly
+         * @type Object
+         * @default {}
+         */
+        customRenderer : {
+            lazyAdd: false,
+            value: {},
+            setter: function (val) {
+                this._rules = val.rules;
+                this._filterFunction = val.filterFunction;
+            }
+        }
+    }
+
+});
+
+
+}, '3.10.3', {
+    "requires": [
+        "widget",
+        "datatype-date",
+        "datatype-date-math",
+        "cssgrids"
+    ],
+    "lang": [
+        "de",
+        "en",
+        "es",
+        "es-AR",
+        "fr",
+        "it",
+        "ja",
+        "nb-NO",
+        "nl",
+        "pt-BR",
+        "ru",
+        "zh-HANT-TW"
+    ],
+    "skinnable": true
+});