bootstrap-italia
Version:
Bootstrap Italia è un tema Bootstrap 4 per la creazione di applicazioni web nel pieno rispetto delle Linee guida di design per i servizi web della PA
1,317 lines (1,278 loc) • 115 kB
JavaScript
/*!
* Accessible Datepicker v2.1.10
* Copyright 2015-2017 Eureka2, Jacques Archimède.
* Based on the example of the Open AJAX Alliance Accessibility Tools Task Force : http://www.oaa-accessibility.org/examplep/datepicker1/
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* Inspired by :
* http://wet-boew.github.io/wet-boew/demos/datepicker/datepicker-fr.html
* http://eternicode.github.io/bootstrap-datepicker
*/
/**
* Description:
* ===========
* This DatePicker widget allows the user to select a date.
* The DatePicker shows one month at least.
*
* The calendar portion of the date picker follows a table structure
* where days of the week and calendar day numbers are layed out in HTML table cells where WAI-ARIA semantics for a grid are applied.
* This provides context so an assistive technology can render the day of the week;
* its corresponding numeric calendar day, and week number if necessary.
*
* The calendar portion can be displayed in a numbers of ways, including as a popup associated with another widget,
* or as a static region of a page.
*
* This component complies with the recommendations of the guide http://www.w3.org/TR/wai-aria-practices/#datepicker of W3C, namely :
*
* Keyboard Interaction:
* =====================
*
* Keyboard navigation on days that are not included the currently displayed month should move to the month automatically and lead to the day in the next or previous month.
*
* - Tab - Like other widgets, the date picker widget receives focus by tabbing into it. Once focus is received, focus is repositioned on today's date in a grid of days and weeks. A second tab will take the user out of the date picker widget. Focus initially is placed on today's date.
* - Shift+Tab - reverses the direction of the tab order. Once in the widget, a Shift+Tab will take the user to the previous focusable element in the tab order.
* - Up Arrow and Down Arrow - goes to the same day of the week in the previous or next week respectively. If the user advances past the end of the month they continue into the next or previous month as appropriate.
* - Left Arrow and Right Arrow - advances one day to the next, also in a continuum. Visually focus is moved from day to day and wraps from row to row in a grid of days and weeks.
* - Alt+Page Up - Moves to the same date in the previous year.
* - Alt+Page Down - Moves to the same date in the next year.
* - Space -
* Singleton Mode: acts as a toggle either selecting or deselecting the date.
* Contiguous Mode: Similar to selecting a range of text. Space selects the first date. Shift+Arrows add to the selection. Pressing Space again deselects the previous selections and selects the current focused date.
* - Home - Moves to the first day of the current month.
* - End - Moves to the last day of the current month.
* - Page Up - Moves to the same date in the previous month.
* - Page Down - Moves to the same date in the next month.
* - Enter -
* If the the calendar is a popup attached to some other widget (e.g., a text field), then Enter dismisses the popup, and the selected date(s) are shown in the associated widget.
* If the calendar is a static region on the page, then Enter confirms the selected date(s).
* - Escape - in the case of a popup date picker, closes the widget without any action.
*
*
* WAI-ARIA Roles, States, and Properties:
* ======================================
*
* The current month has a label representing the month and year. It is advisable to use a role heading but is not essential. This "label" should have a unique ID.
* If the author would like to ensure that a label is announced by a screen reader, as the label changes, include live region properties with the label element: aria-live="assertive" and aria-atomic="true".
* The container for the day of week headers and numeric days of the week has a role of grid.
* The grid has an aria-labelledby property with a value equivalent to the id of the label for the grid.
* Each name for the day of the week has a role columnheader and is not navigable via the keyboard.
* Each numeric day of the week has the role gridcell.
* When a day is selected its aria-selected is set to true, otherwise it is set to false or removed.
* Changes in aria states, identified here, as well as focus, are clearly styled to show the user where their point of regard is and what days are selected.
*
* When the datepicker is active a calender day of the week always has focus.
* This can be achieved by setting the tabindex on that day as appropriate and then using script to give it focus.
* The grid container set aria-activedescendant to the id of the currently focused gridcell.
*
*/
;(function() {
'use strict'
if (typeof Date.dp_locales === 'undefined') {
Date.dp_locales = {
texts: {
buttonTitle: 'Select date ...',
buttonLabel:
'Click or press the Enter key or the spacebar to open the calendar',
prevButtonLabel: 'Go to previous month',
prevMonthButtonLabel: 'Go to the previous year',
prevYearButtonLabel: 'Go to the previous twenty years',
nextButtonLabel: 'Go to next month',
nextMonthButtonLabel: 'Go to the next year',
nextYearButtonLabel: 'Go to the next twenty years',
changeMonthButtonLabel:
'Click or press the Enter key or the spacebar to change the month',
changeYearButtonLabel:
'Click or press the Enter key or the spacebar to change the year',
changeRangeButtonLabel:
'Click or press the Enter key or the spacebar to go to the next twenty years',
closeButtonTitle: 'Close',
closeButtonLabel: 'Close the calendar',
calendarHelp:
'- Up Arrow and Down Arrow - goes to the same day of the week in the previous or next week respectively. If the end of the month is reached, continues into the next or previous month as appropriate.\r\n- Left Arrow and Right Arrow - advances one day to the next, also in a continuum. Visually focus is moved from day to day and wraps from row to row in the grid of days.\r\n- Control+Page Up - Moves to the same date in the previous year.\r\n- Control+Page Down - Moves to the same date in the next year.\r\n- Home - Moves to the first day of the current month.\r\n- End - Moves to the last day of the current month.\r\n- Page Up - Moves to the same date in the previous month.\r\n- Page Down - Moves to the same date in the next month.\r\n- Enter or Espace - closes the calendar, and the selected date is shown in the associated text box.\r\n- Escape - closes the calendar without any action.',
},
directionality: 'LTR',
month_names: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
month_names_abbreviated: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
month_names_narrow: [
'J',
'F',
'M',
'A',
'M',
'J',
'J',
'A',
'S',
'O',
'N',
'D',
],
day_names: [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
],
day_names_abbreviated: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
day_names_short: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
day_names_narrow: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
day_periods: {
am: 'AM',
noon: 'noon',
pm: 'PM',
},
day_periods_abbreviated: {
am: 'AM',
noon: 'noon',
pm: 'PM',
},
day_periods_narrow: {
am: 'a',
noon: 'n',
pm: 'p',
},
quarter_names: [
'1st quarter',
'2nd quarter',
'3rd quarter',
'4th quarter',
],
quarter_names_abbreviated: ['Q1', 'Q2', 'Q3', 'Q4'],
quarter_names_narrow: ['1', '2', '3', '4'],
era_names: ['Before Christ', 'Anno Domini'],
era_names_abbreviated: ['BC', 'AD'],
era_names_narrow: ['B', 'A'],
full_format: 'EEEE, MMMM d, y',
long_format: 'MMMM d, y',
medium_format: 'MMM d, y',
short_format: 'M/d/yy',
firstday_of_week: 0,
}
}
})()
;(function(factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory)
} else if (typeof exports === 'object') {
factory(require('jquery'))
} else {
if (typeof jQuery === 'undefined') {
throw new Error("Datepicker's JavaScript requires jQuery")
}
factory(jQuery)
}
})(function($, undefined) {
'use strict'
var datepickerButton = [
'<a class="datepicker-button input-group-addon btn" role="button" aria-haspopup="true" tabindex="0" aria-labelledby="datepicker-bn-open-label-CALENDARID">',
' <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>it-calendar</title><g><path d="M21,9V8a3,3,0,0,0-3-3h-.55V4a1,1,0,0,0-2,0V5h-7V4a1,1,0,1,0-2,0V5H6A3,3,0,0,0,3,8V18a3,3,0,0,0,3,3H18a3,3,0,0,0,3-3V9ZM15.46,5h2V6a1,1,0,1,1-2,0Zm-9,0h2V6a1,1,0,1,1-2,0ZM20,18a2,2,0,0,1-2,2H6a2,2,0,0,1-2-2V10H20Z"/></g></svg>',
'</a>',
]
var datepickerCalendar = [
'<div class="datepicker-calendar" id="datepicker-calendar-CALENDARID" aria-hidden="false">',
' <div class="datepicker-month-wrap">',
' <div class="datepicker-month-fast-next pull-right" role="button" aria-labelledby="datepicker-bn-fast-next-label-CALENDARID" tabindex="0"><span class="icon-right"></span><span class="icon-right"></span></div>',
' <div class="datepicker-month-next pull-right" role="button" aria-labelledby="datepicker-bn-next-label-CALENDARID" tabindex="0"><span class="icon-right"></span></div>',
' <div class="datepicker-month-fast-prev pull-left" role="button" aria-labelledby="datepicker-bn-fast-prev-label-CALENDARID" tabindex="0"><span class="icon-left"></span><span class="icon-left"></span></div>',
' <div class="datepicker-month-prev pull-left" role="button" aria-labelledby="datepicker-bn-prev-label-CALENDARID" tabindex="0"><span class="icon-left"></span></div>',
' <div id="datepicker-month-CALENDARID" class="datepicker-month" tabindex="0" role="heading" aria-live="assertive" aria-atomic="true" title="Click or press the Enter key or the spacebar to change the month">July 2015</div>',
' </div>',
' <table class="datepicker-grid" role="grid" aria-readonly="true" aria-activedescendant="datepicker-err-msg-CALENDARID" aria-labelledby="datepicker-month-CALENDARID" tabindex="0">',
' <thead>',
' <tr class="datepicker-weekdays" role="row">',
' <th scope="col" id="day0-header-CALENDARID" class="datepicker-day" role="columnheader" aria-label="Sunday"><abbr title="Sunday">Su</abbr></th>',
' <th scope="col" id="day1-header-CALENDARID" class="datepicker-day" role="columnheader" aria-label="Monday"><abbr title="Monday">Mo</abbr></th>',
' <th scope="col" id="day2-header-CALENDARID" class="datepicker-day" role="columnheader" aria-label="Tuesday"><abbr title="Tuesday">Tu</abbr></th>',
' <th scope="col" id="day3-header-CALENDARID" class="datepicker-day" role="columnheader" aria-label="Wednesday"><abbr title="Wednesday">We</abbr></th>',
' <th scope="col" id="day4-header-CALENDARID" class="datepicker-day" role="columnheader" aria-label="Thursday"><abbr title="Thursday">Th</abbr></th>',
' <th scope="col" id="day5-header-CALENDARID" class="datepicker-day" role="columnheader" aria-label="Friday"><abbr title="Friday">Fr</abbr></th>',
' <th scope="col" id="day6-header-CALENDARID" class="datepicker-day" role="columnheader" aria-label="Saturday"><abbr title="Saturday">Sa</abbr></th>',
' </tr>',
' </thead>',
' <tbody>',
' <tr>',
' <td id="datepicker-err-msg-CALENDARID" colspan="7"><span>Javascript must be enabled</span></td>',
' </tr>',
' </tbody>',
' </table>',
' <div class="datepicker-close-wrap">',
' <button class="datepicker-close" id="datepicker-close-CALENDARID" aria-labelledby="datepicker-bn-close-label-CALENDARID">Close</button>',
' </div>',
' <div id="datepicker-bn-open-label-CALENDARID" class="datepicker-bn-open-label offscreen">Click or press the Enter key or the spacebar to open the calendar</div>',
' <div id="datepicker-bn-prev-label-CALENDARID" class="datepicker-bn-prev-label offscreen">Go to previous month</div>',
' <div id="datepicker-bn-next-label-CALENDARID" class="datepicker-bn-next-label offscreen">Go to next month</div>',
' <div id="datepicker-bn-fast-prev-label-CALENDARID" class="datepicker-bn-fast-prev-label offscreen">Go to previous year</div>',
' <div id="datepicker-bn-fast-next-label-CALENDARID" class="datepicker-bn-fast-next-label offscreen">Go to next year</div>',
' <div id="datepicker-bn-close-label-CALENDARID" class="datepicker-bn-close-label offscreen">Close the date picker</div>',
'</div>',
]
var Datepicker = function(target, options) {
var self = this
this.$target = $(target) // textbox that will receive the selected date string and focus (if modal)
this.options = $.extend({}, Datepicker.DEFAULTS, options)
this.locales = Date.dp_locales
this.startview(this.options.startView)
if (typeof this.options.inputFormat === 'string') {
this.options.inputFormat = [this.options.inputFormat]
}
if (!$.isArray(this.options.datesDisabled)) {
this.options.datesDisabled = [this.options.datesDisabled]
}
$.each(this.options.datesDisabled, function(i, v) {
if (typeof v === 'string') {
var date = self.parseDate(v)
if (date === null) {
self.options.datesDisabled[i] = null
} else {
self.options.datesDisabled[i] = self.format(date)
}
} else if (v instanceof Date && !isNaN(v.valueOf())) {
self.options.datesDisabled[i] = self.format(v)
} else {
self.options.datesDisabled[i] = null
}
})
if (this.options.min != null) {
this.options.min = this.parseDate(this.options.min)
} else if (this.$target.attr('min')) {
this.options.min = this.parseDate(this.$target.attr('min'))
}
if (this.options.max != null) {
this.options.max = this.parseDate(this.options.max)
} else if (this.$target.attr('max')) {
this.options.max = this.parseDate(this.$target.attr('max'))
}
if (typeof this.options.previous === 'string') {
this.options.previous = $(this.options.previous)
} else if (!(this.options.previous instanceof jQuery)) {
this.options.previous = null
}
if (typeof this.options.next === 'string') {
this.options.next = $(this.options.next)
} else if (!(this.options.next instanceof jQuery)) {
this.options.next = null
}
this.id =
this.$target.attr('id') ||
'datepicker-' + Math.floor(Math.random() * 100000)
var calendar = datepickerCalendar.join('')
calendar = calendar.replace(/CALENDARID/g, this.id + '')
// complete the target textbox if any
if (this.$target.parent('.input-group').length == 0) {
this.$target.wrap('<div class="input-group"></div>')
}
this.$label = this.$target.parents().find('label[for=' + this.id + ']')
this.$group = this.$target.parent('.input-group')
this.$target.attr('aria-autocomplete', 'none')
this.$target.css('min-width', '7em')
this.$target.addClass('form-control')
if (!this.$target.attr('placeholder')) {
this.$target.attr('placeholder', this.options.inputFormat[0])
}
var button = datepickerButton.join('')
button = button.replace(/CALENDARID/g, this.id + '')
this.$button = $(button)
this.$button.addClass(this.options.theme)
this.$calendar = $(calendar)
this.$calendar.addClass(this.options.theme)
this.$target.after(this.$button)
// be sure parent of the calendar is positionned to calculate the position of the calendar
if (this.$calendar.parent().css('position') === 'static') {
this.$calendar.parent().css('position', 'relative')
}
this.$calendar
.find('.datepicker-bn-open-label')
.html(this.options.buttonLabel)
if (this.$target.attr('id')) {
this.$calendar.attr('aria-controls', this.$target.attr('id'))
}
this.$button.find('span').attr('title', this.options.buttonTitle)
this.$calendar.css('left', this.$target.parent().position().left + 'px')
this.$monthObj = this.$calendar.find('.datepicker-month')
this.$prev = this.$calendar.find('.datepicker-month-prev')
this.$next = this.$calendar.find('.datepicker-month-next')
this.$fastprev = this.$calendar.find('.datepicker-month-fast-prev')
this.$fastnext = this.$calendar.find('.datepicker-month-fast-next')
this.$grid = this.$calendar.find('.datepicker-grid')
if (this.locales.directionality === 'RTL') {
this.$grid.addClass('rtl')
}
var $days = this.$grid.find('th.datepicker-day abbr')
this.drawCalendarHeader()
if (this.options.inline == false && this.options.modal == true) {
this.$close = this.$calendar.find('.datepicker-close')
this.$close
.html(this.options.closeButtonTitle)
.attr('title', this.options.closeButtonLabel)
this.$calendar
.find('.datepicker-bn-close-label')
.html(this.options.closeButtonLabel)
} else {
this.hideObject(this.$calendar.find('.datepicker-close-wrap'))
this.hideObject(this.$calendar.find('.datepicker-bn-close-label'))
}
if (this.options.inline != false) {
this.hideObject(this.$button)
var $container =
typeof this.options.inline === 'string'
? $('#' + this.options.inline)
: this.options.inline
$container.append(this.$calendar)
this.$calendar.css({ position: 'relative', left: '0px' })
this.initializeDate()
} else {
this.$calendar.css({ display: 'none' })
this.$target.parent().after(this.$calendar)
this.hide(!this.options.gainFocusOnConstruction)
}
this.keys = {
tab: 9,
enter: 13,
esc: 27,
space: 32,
pageup: 33,
pagedown: 34,
end: 35,
home: 36,
left: 37,
up: 38,
right: 39,
down: 40,
}
this.bindHandlers()
this.$button.click(function(e) {
if (!$(this).hasClass('disabled')) {
if (self.$calendar.attr('aria-hidden') === 'true') {
self.initializeDate()
self.show()
} else {
self.hide()
}
self.selectGridCell(self.$grid.attr('aria-activedescendant'))
}
e.stopPropagation()
return false
})
this.$button.keydown(function(e) {
var ev = e || event
if (ev.keyCode == self.keys.enter || ev.keyCode == self.keys.space) {
$(this).trigger('click')
return false
}
})
this.$calendar.on('blur', function(e) {
if (self.$calendar.attr('aria-hidden') === 'false') {
self.hide()
}
})
}
Datepicker.VERSION = '2.1.10'
Datepicker.DEFAULTS = {
firstDayOfWeek: Date.dp_locales.firstday_of_week, // Determines the first column of the calendar grid
weekDayFormat: 'short', // Display format of the weekday names - values are 'short' or 'narrow'
startView: 0, // Initial calendar - values are 0 or 'days', 1 or 'months', 2 or 'years'
daysOfWeekDisabled: [],
datesDisabled: [],
isDateDisabled: null,
isMonthDisabled: null,
isYearDisabled: null,
inputFormat: [Date.dp_locales.short_format],
outputFormat: Date.dp_locales.short_format,
titleFormat: Date.dp_locales.full_format,
buttonTitle: Date.dp_locales.texts.buttonTitle,
buttonLabel: Date.dp_locales.texts.buttonLabel,
prevButtonLabel: Date.dp_locales.texts.prevButtonLabel,
prevMonthButtonLabel: Date.dp_locales.texts.prevMonthButtonLabel,
prevYearButtonLabel: Date.dp_locales.texts.prevYearButtonLabel,
nextButtonLabel: Date.dp_locales.texts.nextButtonLabel,
nextMonthButtonLabel: Date.dp_locales.texts.nextMonthButtonLabel,
nextYearButtonLabel: Date.dp_locales.texts.nextYearButtonLabel,
changeMonthButtonLabel: Date.dp_locales.texts.changeMonthButtonLabel,
changeYearButtonLabel: Date.dp_locales.texts.changeYearButtonLabel,
changeRangeButtonLabel: Date.dp_locales.texts.changeRangeButtonLabel,
closeButtonTitle: Date.dp_locales.texts.closeButtonTitle,
closeButtonLabel: Date.dp_locales.texts.closeButtonLabel,
onUpdate: function(value) {},
previous: null,
next: null,
theme: 'default',
modal: false,
inline: false,
gainFocusOnConstruction: false,
min: null,
max: null,
}
/**
* initializeDate() is a member function to initialize the Datepicker date with the content of the target textbox
*
* @return N/A
*
*/
Datepicker.prototype.initializeDate = function() {
var val = this.$target.val()
var date = val === '' ? new Date() : this.parseDate(val)
this.setDate(date, true)
} // end initializeDate()
/**
* getDate() is a member function to retrieve the current Datepicker date.
* @return the Date object
*/
Datepicker.prototype.getDate = function() {
var val = this.$target.val()
var date = val === '' ? new Date() : this.parseDate(val)
return date
} // end getDate()
/**
* setDate() is a member function to set the Datepicker date with the content of newDate
*
* @param (newDate Date) the new value of the Datepicker date.
* @return N/A
*
*/
Datepicker.prototype.setDate = function(newDate, init) {
this.dateObj = newDate
init = typeof init === 'undefined' ? false : init
if (this.dateObj == null) {
this.$target.attr('aria-invalid', true)
this.$target.parents('.form-group').addClass('has-error')
this.dateObj = new Date()
this.dateObj.setHours(0, 0, 0, 0)
}
if (this.options.min != null && this.dateObj < this.options.min) {
this.$target.attr('aria-invalid', true)
this.$target.parents('.form-group').addClass('has-error')
this.dateObj = this.options.min
} else if (this.options.max != null && this.dateObj > this.options.max) {
this.$target.attr('aria-invalid', true)
this.$target.parents('.form-group').addClass('has-error')
this.dateObj = this.options.max
}
if (!init || this.$target.val() != '') {
this.$target.val(this.format(this.dateObj))
}
this.curYear = this.dateObj.getFullYear()
this.year = this.curYear
this.curMonth = this.dateObj.getMonth()
this.month = this.curMonth
this.date = this.dateObj.getDate()
// populate the calendar grid
switch (this.options.startView) {
case 1: // months
this.populateMonthsCalendar()
// update the table's activedescdendant to point to the current month
this.$grid.attr(
'aria-activedescendant',
this.$grid.find('.curMonth').attr('id')
)
break
case 2: // years
this.populateYearsCalendar()
// update the table's activedescdendant to point to the current year
this.$grid.attr(
'aria-activedescendant',
this.$grid.find('.curYear').attr('id')
)
break
default:
this.populateDaysCalendar()
// update the table's activedescdendant to point to the current day
this.$grid.attr(
'aria-activedescendant',
this.$grid.find('.curDay').attr('id')
)
}
} // end setDate()
/**
* drawCalendarHeader() is a member function to populate the calendar header with the days name.
*
* @return N/A
*/
Datepicker.prototype.drawCalendarHeader = function() {
var $days = this.$grid.find('th.datepicker-day')
var weekday = this.options.firstDayOfWeek
for (var i = 0; i < 7; i++) {
$days.eq(i).attr('aria-label', this.locales.day_names[weekday])
$days
.children('abbr')
.eq(i)
.attr('title', this.locales.day_names[weekday])
.text(
this.options.weekDayFormat === 'short'
? this.locales.day_names_short[weekday]
: this.locales.day_names_narrow[weekday]
)
weekday = (weekday + 1) % 7
}
} // end drawCalendarHeader()
/**
* populateDaysCalendar() is a member function to populate the datepicker grid with calendar days
* representing the current month
*
* @return N/A
*
*/
Datepicker.prototype.populateDaysCalendar = function() {
this.$calendar
.find('.datepicker-bn-prev-label')
.html(this.options.prevButtonLabel)
this.$calendar
.find('.datepicker-bn-next-label')
.html(this.options.nextButtonLabel)
this.$calendar
.find('.datepicker-bn-fast-prev-label')
.html(this.options.prevMonthButtonLabel)
this.$calendar
.find('.datepicker-bn-fast-next-label')
.html(this.options.nextMonthButtonLabel)
if (
this.options.min != null &&
(this.year - 1 < this.options.min.getFullYear() ||
(this.year - 1 == this.options.min.getFullYear() &&
this.month < this.options.min.getMonth()))
) {
this.$fastprev.attr('title', '')
this.$fastprev.addClass('disabled')
this.$fastprev.removeClass('enabled')
} else {
this.$fastprev.attr('title', this.options.prevMonthButtonLabel)
this.$fastprev.addClass('enabled')
this.$fastprev.removeClass('disabled')
}
var previousMonth = this.previousMonth(this.year, this.month)
if (
this.options.min != null &&
(previousMonth.year < this.options.min.getFullYear() ||
(previousMonth.year == this.options.min.getFullYear() &&
previousMonth.month < this.options.min.getMonth()))
) {
this.$prev.attr('title', '')
this.$prev.addClass('disabled')
this.$prev.removeClass('enabled')
} else {
this.$prev.attr('title', this.options.prevButtonLabel)
this.$prev.addClass('enabled')
this.$prev.removeClass('disabled')
}
this.$monthObj.attr('title', this.options.changeMonthButtonLabel)
var nextMonth = this.nextMonth(this.year, this.month)
if (
this.options.max != null &&
(nextMonth.year > this.options.max.getFullYear() ||
(nextMonth.year == this.options.max.getFullYear() &&
nextMonth.month > this.options.max.getMonth()))
) {
this.$next.attr('title', '')
this.$next.addClass('disabled')
this.$next.removeClass('enabled')
} else {
this.$next.attr('title', this.options.nextButtonLabel)
this.$next.addClass('enabled')
this.$next.removeClass('disabled')
}
if (
this.options.max != null &&
(this.year + 1 > this.options.max.getFullYear() ||
(this.year + 1 == this.options.max.getFullYear() &&
this.month > this.options.max.getMonth()))
) {
this.$fastnext.attr('title', '')
this.$fastnext.addClass('disabled')
this.$fastnext.removeClass('enabled')
} else {
this.$fastnext.attr('title', this.options.nextMonthButtonLabel)
this.$fastnext.addClass('enabled')
this.$fastnext.removeClass('disabled')
}
this.showObject(this.$fastprev)
this.showObject(this.$fastnext)
var numDays = this.getDaysInMonth(this.year, this.month)
var numPrevDays = this.getDaysInMonth(
previousMonth.year,
previousMonth.month
)
var startWeekday = new Date(this.year, this.month, 1).getDay()
var lastDayOfWeek = (this.options.firstDayOfWeek + 6) % 7
var curDay = 1
var rowCount = 1
this.$monthObj.html(this.locales.month_names[this.month] + ' ' + this.year)
this.showObject(this.$grid.find('thead'))
// clear the grid
var gridCells = '\t<tr id="row0-' + this.id + '" role="row">\n'
// Insert the leading empty cells
var numEmpties = 0
var weekday = this.options.firstDayOfWeek
while (weekday != startWeekday) {
numEmpties++
weekday = (weekday + 1) % 7
}
for (; numEmpties > 0; numEmpties--) {
gridCells +=
'\t\t<td class="empty">' + (numPrevDays - numEmpties + 1) + '</td>\n'
}
var isYearDisabled =
this.options.isYearDisabled && this.options.isYearDisabled(this.year)
var isMonthDisabled =
this.options.isMonthDisabled &&
this.options.isMonthDisabled(this.year, this.month + 1)
// insert the days of the month.
for (curDay = 1; curDay <= numDays; curDay++) {
var date = new Date(this.year, this.month, curDay, 0, 0, 0, 0)
var longdate = this.formatDate(date, this.options.titleFormat)
var curDayClass =
curDay == this.date &&
this.month == this.curMonth &&
this.year == this.curYear
? ' curDay'
: ''
if (isYearDisabled || isMonthDisabled) {
gridCells +=
'\t\t<td id="cell' +
curDay +
'-' +
this.id +
'" class="day unselectable' +
curDayClass +
'"'
} else if ($.inArray(weekday, this.options.daysOfWeekDisabled) > -1) {
gridCells +=
'\t\t<td id="cell' +
curDay +
'-' +
this.id +
'" class="day unselectable' +
curDayClass +
'"'
} else if (this.options.min != null && date < this.options.min) {
gridCells +=
'\t\t<td id="cell' +
curDay +
'-' +
this.id +
'" class="day unselectable' +
curDayClass +
'"'
} else if (this.options.max != null && date > this.options.max) {
gridCells +=
'\t\t<td id="cell' +
curDay +
'-' +
this.id +
'" class="day unselectable' +
curDayClass +
'"'
} else if (
$.inArray(this.format(date), this.options.datesDisabled) > -1
) {
gridCells +=
'\t\t<td id="cell' +
curDay +
'-' +
this.id +
'" class="day unselectable' +
curDayClass +
'"'
} else if (
this.options.isDateDisabled &&
this.options.isDateDisabled(date)
) {
gridCells +=
'\t\t<td id="cell' +
curDay +
'-' +
this.id +
'" class="day unselectable' +
curDayClass +
'"'
} else {
gridCells +=
'\t\t<td id="cell' +
curDay +
'-' +
this.id +
'" class="day selectable' +
curDayClass +
'"'
}
gridCells += ' data-value="' + curDay + '"'
gridCells += ' title="' + longdate + '"'
gridCells += ' aria-label="' + longdate + '"'
gridCells +=
' headers="day' +
weekday +
'-header-' +
this.id +
'" role="gridcell" tabindex="-1" aria-selected="false"><span>' +
curDay +
'</span>'
gridCells += '</td>'
if (weekday == lastDayOfWeek && curDay < numDays) {
// This was the last day of the week, close it out
// and begin a new one
gridCells +=
'\t</tr>\n\t<tr id="row' +
rowCount +
'-' +
this.id +
'" role="row">\n'
rowCount++
}
if (curDay < numDays) {
weekday = (weekday + 1) % 7
}
}
// Insert any trailing empty cells
while (weekday != lastDayOfWeek) {
gridCells += '\t\t<td class="empty">' + ++numEmpties + '</td>\n'
weekday = (weekday + 1) % 7
}
gridCells += '\t</tr>'
var $tbody = this.$grid.find('tbody')
$tbody.empty()
$tbody.append(gridCells)
this.gridType = 0 // 0 = days grid, 1 = months grid, 2 = years Grid
} // end populateDaysCalendar()
/**
* populateMonthsCalendar() is a member function to populate the datepicker grid with calendar months
* representing the current year
*
* @return N/A
*
*/
Datepicker.prototype.populateMonthsCalendar = function() {
this.$calendar
.find('.datepicker-bn-prev-label')
.html(this.options.prevMonthButtonLabel)
this.$calendar
.find('.datepicker-bn-next-label')
.html(this.options.nextMonthButtonLabel)
this.hideObject(this.$fastprev)
this.hideObject(this.$fastnext)
if (
this.options.min != null &&
this.year - 1 < this.options.min.getFullYear()
) {
this.$prev.attr('title', '')
this.$prev.addClass('disabled')
this.$prev.removeClass('enabled')
} else {
this.$prev.attr('title', this.options.prevMonthButtonLabel)
this.$prev.addClass('enabled')
this.$prev.removeClass('disabled')
}
this.$monthObj.attr('title', this.options.changeYearButtonLabel)
if (
this.options.max != null &&
this.year + 1 > this.options.max.getFullYear()
) {
this.$next.attr('title', '')
this.$next.addClass('disabled')
this.$next.removeClass('enabled')
} else {
this.$next.attr('title', this.options.nextMonthButtonLabel)
this.$next.addClass('enabled')
this.$next.removeClass('disabled')
}
var curMonth = 0
var rowCount = 1
var $tbody = this.$grid.find('tbody')
this.$monthObj.html(this.year)
// clear the grid
this.hideObject(this.$grid.find('thead'))
$tbody.empty()
$('#datepicker-err-msg-' + this.id).empty()
var gridCells = '\t<tr id="row0-' + this.id + '" role="row">\n'
var isYearDisabled =
this.options.isYearDisabled && this.options.isYearDisabled(this.year)
// insert the months of the year.
for (curMonth = 0; curMonth < 12; curMonth++) {
if (isYearDisabled) {
gridCells +=
'\t\t<td id="cell' +
(curMonth + 1) +
'-' +
this.id +
'" class="month unselectable"'
} else if (curMonth == this.month && this.year == this.curYear) {
gridCells +=
'\t\t<td id="cell' +
(curMonth + 1) +
'-' +
this.id +
'" class="month curMonth selectable"'
} else if (
this.options.min != null &&
(this.year < this.options.min.getFullYear() ||
(this.year == this.options.min.getFullYear() &&
curMonth < this.options.min.getMonth()))
) {
gridCells +=
'\t\t<td id="cell' +
(curMonth + 1) +
'-' +
this.id +
'" class="month unselectable"'
} else if (
this.options.max != null &&
(this.year > this.options.max.getFullYear() ||
(this.year == this.options.max.getFullYear() &&
curMonth > this.options.max.getMonth()))
) {
gridCells +=
'\t\t<td id="cell' +
(curMonth + 1) +
'-' +
this.id +
'" class="month unselectable"'
} else if (
this.options.isMonthDisabled &&
this.options.isMonthDisabled(this.year, curMonth + 1)
) {
gridCells +=
'\t\t<td id="cell' +
(curMonth + 1) +
'-' +
this.id +
'" class="month unselectable"'
} else {
gridCells +=
'\t\t<td id="cell' +
(curMonth + 1) +
'-' +
this.id +
'" class="month selectable"'
}
gridCells += ' data-value="' + curMonth + '"'
gridCells +=
' title="' + this.locales.month_names[curMonth] + ' ' + this.year + '"'
gridCells +=
' aria-label="' +
this.locales.month_names[curMonth] +
' ' +
this.year +
'"'
gridCells +=
' role="gridcell" tabindex="-1" aria-selected="false">' +
this.locales.month_names_abbreviated[curMonth]
gridCells += '</td>'
if (curMonth == 3 || curMonth == 7) {
gridCells +=
'\t</tr>\n\t<tr id="row' +
rowCount +
'-' +
this.id +
'" role="row">\n'
rowCount++
}
}
gridCells += '\t</tr>'
$tbody.append(gridCells)
this.gridType = 1 // 0 = days grid, 1 = months grid, 2 = years Grid
} // end populateMonthsCalendar()
/**
* populateYearsCalendar() is a member function to populate the datepicker grid with 20 calendar years
* around the current year
*
* @return N/A
*
*/
Datepicker.prototype.populateYearsCalendar = function() {
this.$calendar
.find('.datepicker-bn-prev-label')
.html(this.options.prevYearButtonLabel)
this.$calendar
.find('.datepicker-bn-next-label')
.html(this.options.nextYearButtonLabel)
this.hideObject(this.$fastprev)
this.hideObject(this.$fastnext)
if (
this.options.min != null &&
this.year - 20 < this.options.min.getFullYear()
) {
this.$prev.attr('title', '')
this.$prev.addClass('disabled')
this.$prev.removeClass('enabled')
} else {
this.$prev.attr('title', this.options.prevYearButtonLabel)
this.$prev.addClass('enabled')
this.$prev.removeClass('disabled')
}
this.$monthObj.attr('title', this.options.changeRangeButtonLabel)
if (
this.options.max != null &&
this.year + 20 > this.options.max.getFullYear()
) {
this.$next.attr('title', '')
this.$next.addClass('disabled')
this.$next.removeClass('enabled')
} else {
this.$next.attr('title', this.options.nextYearButtonLabel)
this.$next.addClass('enabled')
this.$next.removeClass('disabled')
}
var startYear = Math.floor(this.year / 10) * 10
var endYear = startYear + 19
var rowCount = 1
var $tbody = this.$grid.find('tbody')
this.$monthObj.html(startYear + '-' + endYear)
// clear the grid
this.hideObject(this.$grid.find('thead'))
$tbody.empty()
$('#datepicker-err-msg-' + this.id).empty()
var gridCells = '\t<tr id="row0-' + this.id + '" role="row">\n'
// insert the months of the year.
for (var curYear = startYear; curYear <= endYear; curYear++) {
if (curYear == this.year) {
gridCells +=
'\t\t<td id="cell' +
(curYear - startYear + 1) +
'-' +
this.id +
'" class="year curYear selectable"'
} else if (
this.options.min != null &&
curYear < this.options.min.getFullYear()
) {
gridCells +=
'\t\t<td id="cell' +
(curYear - startYear + 1) +
'-' +
this.id +
'" class="year unselectable"'
} else if (
this.options.max != null &&
curYear > this.options.max.getFullYear()
) {
gridCells +=
'\t\t<td id="cell' +
(curYear - startYear + 1) +
'-' +
this.id +
'" class="year unselectable"'
} else if (
this.options.isYearDisabled &&
this.options.isYearDisabled(curYear)
) {
gridCells +=
'\t\t<td id="cell' +
(curYear - startYear + 1) +
'-' +
this.id +
'" class="year unselectable"'
} else {
gridCells +=
'\t\t<td id="cell' +
(curYear - startYear + 1) +
'-' +
this.id +
'" class="year selectable"'
}
gridCells += ' data-value="' + curYear + '"'
gridCells += ' title="' + curYear + '"'
gridCells +=
' role="gridcell" tabindex="-1" aria-selected="false">' + curYear
gridCells += '</td>'
var curPos = curYear - startYear
if (curPos == 4 || curPos == 9 || curPos == 14) {
gridCells +=
'\t</tr>\n\t<tr id="row' +
rowCount +
'-' +
this.id +
'" role="row">\n'
rowCount++
}
}
gridCells += '\t</tr>'
$tbody.append(gridCells)
this.gridType = 2 // 0 = days grid, 1 = months grid, 2 = years Grid
} // end populateYearsCalendar()
/**
* showDaysOfPrevMonth() is a member function to show the days of the previous month
*
* @param (offset int) offset may be used to specify an offset for setting
* focus on a day the specified number of days from the end of the month.
* @return true if the previous month is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showDaysOfPrevMonth = function(offset) {
// show the previous month
var previousMonth = this.previousMonth(this.year, this.month)
if (
this.options.min != null &&
(previousMonth.year < this.options.min.getFullYear() ||
(previousMonth.year == this.options.min.getFullYear() &&
previousMonth.month < this.options.min.getMonth()))
) {
return false
}
this.month = previousMonth.month
this.year = previousMonth.year
// populate the calendar grid
this.populateDaysCalendar()
// if offset was specified, set focus on the last day - specified offset
if (offset != null) {
var numDays = this.getDaysInMonth(this.year, this.month)
var day = 'cell' + (numDays - offset) + '-' + this.id
this.$grid.attr('aria-activedescendant', day)
this.selectGridCell(day)
}
return true
} // end showDaysOfPrevMonth()
/**
* showDaysOfMonth() is a member function to show the days of the specified month
*
* @param (month int) the month to show.
* @return true if the month is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showDaysOfMonth = function(month) {
if (
this.options.min != null &&
(this.year < this.options.min.getFullYear() ||
(this.year == this.options.min.getFullYear() &&
month < this.options.min.getMonth()))
) {
return false
}
if (
this.options.max != null &&
(this.year > this.options.max.getFullYear() ||
(this.year == this.options.max.getFullYear() &&
month > this.options.max.getMonth()))
) {
return false
}
this.month = month
this.date = Math.min(this.date, this.getDaysInMonth(this.year, this.month))
this.populateDaysCalendar()
// update the table's activedescendant to point to the active day
var $active = this.$grid.find("tbody td[data-value='" + this.date + "']")
this.selectGridCell($active.attr('id'))
return true
} // end showDaysOfMonth()
/**
* showMonthsOfPrevYear() is a member function to show the months of the previous year
*
* @param (offset int) offset may be used to specify an offset for setting
* focus on a month the specified number of months from the end of the year.
* @return true if the previous year is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showMonthsOfPrevYear = function(offset) {
if (
this.options.min != null &&
this.year - 1 < this.options.min.getFullYear()
) {
return false
}
// show the previous year
this.year--
// populate the calendar grid
this.populateMonthsCalendar()
// if offset was specified, set focus on the last month - specified offset
if (offset != null) {
var month = 'cell' + (12 - offset) + '-' + this.id
this.$grid.attr('aria-activedescendant', month)
this.selectGridCell(month)
}
return true
} // end showMonthsOfPrevYear()
/**
* showMonthsOfYear() is a member function to show the months of the specified year
*
* @param (year int) the year to show.
* @return true if the year is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showMonthsOfYear = function(year) {
if (this.options.min != null && year < this.options.min.getFullYear()) {
return false
}
if (this.options.max != null && year > this.options.max.getFullYear()) {
return false
}
this.year = year
this.populateMonthsCalendar()
// update the table's activedescendant to point to the active month
var $active = this.$grid.find("tbody td[data-value='" + this.month + "']")
this.$grid.attr('aria-activedescendant', $active.attr('id'))
this.selectGridCell($active.attr('id'))
return true
} // end showMonthsOfYear()
/**
* showYearsOfPrevRange() is a member function to show the years of the previous range of twenty years
*
* @param (offset int) offset may be used to specify an offset for setting
* focus on a year the specified number of years from the end of the range.
* @return true if the year - 20 is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showYearsOfPrevRange = function(offset) {
if (
this.options.min != null &&
this.year - 20 < this.options.min.getFullYear()
) {
return false
}
// show the previous range
this.year -= 20
// populate the calendar grid
this.populateYearsCalendar()
// if offset was specified, set focus on the last month - specified offset
if (offset != null) {
var year = 'cell' + (20 - offset) + '-' + this.id
this.$grid.attr('aria-activedescendant', year)
this.selectGridCell(year)
}
return true
} // end showYearsOfPrevRange()
/**
* showDaysOfNextMonth() is a member function to show the next month
*
* @param (offset int) offset may be used to specify an offset for setting
* focus on a day the specified number of days from
* the beginning of the month.
* @return true if the nextmMonth is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showDaysOfNextMonth = function(offset) {
// show the next month
var nextMonth = this.nextMonth(this.year, this.month)
if (
this.options.max != null &&
(nextMonth.year > this.options.max.getFullYear() ||
(nextMonth.year == this.options.max.getFullYear() &&
nextMonth.month > this.options.max.getMonth()))
) {
return false
}
this.month = nextMonth.month
this.year = nextMonth.year
// populate the calendar grid
this.populateDaysCalendar()
// if offset was specified, set focus on the first day + specified offset
if (offset != null) {
var day = 'cell' + offset + '-' + this.id
this.$grid.attr('aria-activedescendant', day)
this.selectGridCell(day)
}
return true
} // end showDaysOfNextMonth()
/**
* showMonthsOfNextYear() is a member function to show the months of next year
*
* @param (offset int) offset may be used to specify an offset for setting
* focus on a month the specified number of month from
* the beginning of the year.
* @return true if the next year is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showMonthsOfNextYear = function(offset) {
if (
this.options.max != null &&
this.year + 1 > this.options.max.getFullYear()
) {
return false
}
// show the next year
this.year++
// populate the calendar grid
this.populateMonthsCalendar()
// if offset was specified, set focus on the first day + specified offset
if (offset != null) {
var month = 'cell' + offset + '-' + this.id
this.$grid.attr('aria-activedescendant', month)
this.selectGridCell(month)
}
return true
} // end showMonthsOfNextYear()
/**
* showYearsOfNextRange() is a member function to show the years of next range of years
*
* @param (offset int) offset may be used to specify an offset for setting
* focus on a year the specified number of years from
* the beginning of the range.
* @return true if the year + 20 is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showYearsOfNextRange = function(offset) {
if (
this.options.max != null &&
this.year + 20 > this.options.max.getFullYear()
) {
return false
}
// show the next year
this.year += 20
// populate the calendar grid
this.populateYearsCalendar()
// if offset was specified, set focus on the first day + specified offset
if (offset != null) {
var year = 'cell' + offset + '-' + this.id
this.$grid.attr('aria-activedescendant', year)
this.selectGridCell(year)
}
return true
} // end showYearsOfNextRange()
/**
* showDaysOfPrevYear() is a member function to show the previous year
*
* @return true if the previous year is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showDaysOfPrevYear = function() {
if (
this.options.min != null &&
(this.year - 1 < this.options.min.getFullYear() ||
(this.year - 1 == this.options.min.getFullYear() &&
this.month < this.options.min.getMonth()))
) {
return false
}
// decrement the year
this.year--
// populate the calendar grid
this.populateDaysCalendar()
return true
} // end showDaysOfPrevYear()
/**
* showDaysOfNextYear() is a member function to show the next year
*
* @return true if the next year is between the minimum and the maximum date otherwise return false
*/
Datepicker.prototype.showDaysOfNextYear = function() {
if (
this.options.max != null &&
(this.year + 1 > this.options.max.getFullYear() ||
(this.year + 1 == this.options.max.getFullYear() &&
this.month > this.options.max.getMonth()))
) {
return false
}
// increment the year
this.year++
// populate the calendar grid
this.populateDaysCalendar()
return true
} // end showDaysOfNextYear()
/**
* bindHandlers() is a member function to bi