calendar-base.js revision 79cf858565f2b256d816b50edb025ff71589dcc0
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * The CalendarBase submodule is a basic UI calendar view that displays
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * a range of dates in a two-dimensional month grid, with one or more
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * months visible at a single time. CalendarBase supports custom date
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * rendering, multiple calendar panes, and selection.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @module calendar
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @submodule calendar-base
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass CAL_COL_HIDDEN = getCN(CALENDAR, 'column-hidden'),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass CAL_DAY_SELECTED = getCN(CALENDAR, 'day-selected'),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass SELECTION_DISABLED = getCN(CALENDAR, 'selection-disabled'),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass CAL_PREVMONTH_DAY = getCN(CALENDAR, 'prevmonth-day'),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass CAL_NEXTMONTH_DAY = getCN(CALENDAR, 'nextmonth-day'),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/** Create a calendar view to represent a single or multiple
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * month range of dates, rendered as a grid with date and
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * weekday labels.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @class CalendarBase
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @extends Widget
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param config {Object} Configuration object (see Configuration
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * attributes)
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @constructor
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass CalendarBase.superclass.constructor.apply ( this, arguments );
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.CalendarBase = Y.extend( CalendarBase, Y.Widget, {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * A storage for various properties of individual month
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property _paneProperties
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type Object
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * The number of month panes in the calendar, deduced
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * from the CONTENT_TEMPLATE's number of {calendar_grid}
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property _paneNumber
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type Number
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * The unique id used to prefix various elements of this
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * calendar instance.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property _calendarId
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type String
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * The hash map of selected dates, populated with
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * selectDates() and deselectDates() methods
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property _selectedDates
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type Object
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * A private copy of the rules object, populated
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * by setting the customRenderer attribute.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property _rules
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type Object
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * A private copy of the filterFunction, populated
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * by setting the customRenderer attribute.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property _filterFunction
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type Function
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Storage for calendar cells modified by any custom
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * formatting. The storage is cleared, used to restore
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * cells to the original state, and repopulated accordingly
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * when the calendar is rerendered.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @property _storedDateCells
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @type Object
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Designated initializer
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Initializes instance-level properties of
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method initializer
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass initializer : function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * renderUI implementation
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Creates a visual representation of the calendar based on existing parameters.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method renderUI
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass renderUI : function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass contentBox.appendChild(this._initCalendarHTML(this.get('date')));
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * bindUI implementation
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Assigns listeners to relevant events that change the state
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * of the calendar.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method bindUI
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass bindUI : function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.after('showPrevMonthChange', this._afterShowPrevMonthChange);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.after('showNextMonthChange', this._afterShowNextMonthChange);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.after('headerRendererChange', this._afterHeaderRendererChange);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.after('customRendererChange', this._afterCustomRendererChange);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * syncUI implementation
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * Update the scroll position, based on the current value of scrollY
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method syncUI
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass syncUI : function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * An internal utility method that generates a list of selected dates
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * from the hash storage.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method _getSelectedDatesList
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {Array} The array of `Date`s that are currently selected.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * A utility method that returns all dates selected in a specific month.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method _getSelectedDatesInMonth
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Date} oDate corresponding to the month for which selected dates
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * are requested.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {Array} The array of `Date`s in a given month that are currently selected.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (hasKey(this._selectedDates, year) && hasKey(this._selectedDates[year], month)) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return Y.Object.values(this._selectedDates[year][month]);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * An internal rendering method that modifies a date cell to have the
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * selected CSS class if the date cell is visible.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method _renderSelectedDate
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Date} oDate The date corresponding to a specific date cell.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._dateToNode(oDate).addClass(CAL_DAY_SELECTED);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * An internal rendering method that modifies a date cell to remove the
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * selected CSS class if the date cell is visible.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method _renderUnelectedDate
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Date} oDate The date corresponding to a specific date cell.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._dateToNode(oDate).removeClass(CAL_DAY_SELECTED);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * An internal utility method that checks whether a particular date
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * is in the current view of the calendar.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @method _isDateVisible
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @param {Date} oDate The date corresponding to a specific date cell.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * @return {boolean} Returns true if the given date is in the current
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * view of the calendar.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass maxDate = ydate.addMonths(minDate, this._paneNumber - 1),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (minDate.getTime() <= oDateTime && oDateTime <= maxDate) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return true;
val;
outputRules = [],
return outputRules;
if (enabledDatesRule) {
else if (disabledDatesRule) {
if (dates == null) {
this._clearSelection();
if (index == null) {
this._fireSelectionChange();
this._fireSelectionChange();
this._fireSelectionChange();
if (index == null) {
this._fireSelectionChange();
this._fireSelectionChange();
this._fireSelectionChange();
this._selectedDates = {};
if (!noevent) {
this._fireSelectionChange();
_fireSelectionChange : function () {
_restoreModifiedCells : function () {
id;
_renderCustomRules : function () {
this.get("contentBox").all("." + CAL_DAY + ",." + CAL_NEXTMONTH_DAY).removeClass(SELECTION_DISABLED);
_renderSelectedDates : function () {
switch (daymod) {
return(this.get("contentBox").one("#" + this._calendarId + "_pane_" + paneNum + "_" + col + "_" + day));
_bindCalendarEvents : function () {
return cutOffColumn;
pane.one("#" + pane_id + "_" + cell + "_" + (cell+23)).setContent(dayCounter++).addClass(CAL_NEXTMONTH_DAY);
pane.one("#" + pane_id + "_" + cell + "_" + (cell+30)).setContent(dayCounter++).addClass(CAL_NEXTMONTH_DAY);
pane.one("#" + pane_id + "_" + cell + "_" + (cell+23)).setContent(" ").addClass(CAL_NEXTMONTH_DAY);
pane.one("#" + pane_id + "_" + cell + "_" + (cell+30)).setContent(" ").addClass(CAL_NEXTMONTH_DAY);
_afterShowNextMonthChange : function () {
_afterShowPrevMonthChange : function () {
_afterHeaderRendererChange : function () {
_afterCustomRendererChange : function () {
this._renderCustomRules();
_afterDateChange : function () {
this._restoreModifiedCells();
curNode);
this._afterShowPrevMonthChange();
this._afterShowNextMonthChange();
this._renderCustomRules();
this._renderSelectedDates();
// Get a list of short weekdays from the internationalization package, or else use default English ones.
// Get the first day of the week from the internationalization package, or else use Sunday as default.
// Compute the cutoff column of the masked calendar table, based on the start date and the first day of week.
partials = {};
// Decide on whether a column in the masked table is visible or not based on the value of the cutoff column.
// Substitute the values into the partial calendar day template and add it to the current row HTML string
{calday_row: v});
this._paneProperties[pane_id] = {cutoffCol: cutoffCol, daysInMonth: daysInMonth, paneDate: baseDate};
return output;
// Get the first day of the week from the internationalization package, or else use Sunday as default.
// Compute the cutoff column of the masked calendar table, based on the start date and the first day of week.
// Go through all columns, and flip their visibility setting based on whether they are within the unmasked range.
switch(column)
else if (headerRenderer instanceof Function) {
return headerString;
var partials = {},
function paneReplacer () {
var 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.
var output = partials["body_template"].replace(/\{calendar_grid_template\}/g, Y.bind(paneReplacer, this));
return output;
CALDAY_TEMPLATE: '<td class="{calendar_col_class} {calendar_day_class} {calendar_col_visibility_class}" id="{calendar_day_id}">' +
ATTRS: {
date: {
value: new Date(),
value: false
value: false
strings : {
value: null
value: null
selectedDates : {
readOnly: true,
return (this._getSelectedDatesList());
customRenderer : {
value: {},