2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2025-09-06 10:50:21 +08:00

update pikaday.js

This commit is contained in:
Régis Hanol 2017-06-23 17:50:13 +02:00
parent 73a4a05c5b
commit 9206741190

View file

@ -59,22 +59,6 @@
} }
}, },
fireEvent = function(el, eventName, data)
{
var ev;
if (document.createEvent) {
ev = document.createEvent('HTMLEvents');
ev.initEvent(eventName, true, false);
ev = extend(ev, data);
el.dispatchEvent(ev);
} else if (document.createEventObject) {
ev = document.createEventObject();
ev = extend(ev, data);
el.fireEvent('on' + eventName, ev);
}
},
trim = function(str) trim = function(str)
{ {
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,''); return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,'');
@ -160,6 +144,22 @@
return to; return to;
}, },
fireEvent = function(el, eventName, data)
{
var ev;
if (document.createEvent) {
ev = document.createEvent('HTMLEvents');
ev.initEvent(eventName, true, false);
ev = extend(ev, data);
el.dispatchEvent(ev);
} else if (document.createEventObject) {
ev = document.createEventObject();
ev = extend(ev, data);
el.fireEvent('on' + eventName, ev);
}
},
adjustCalendar = function(calendar) { adjustCalendar = function(calendar) {
if (calendar.month < 0) { if (calendar.month < 0) {
calendar.year -= Math.ceil(Math.abs(calendar.month)/12); calendar.year -= Math.ceil(Math.abs(calendar.month)/12);
@ -183,6 +183,9 @@
// automatically show/hide the picker on `field` focus (default `true` if `field` is set) // automatically show/hide the picker on `field` focus (default `true` if `field` is set)
bound: undefined, bound: undefined,
// data-attribute on the input field with an aria assistance tekst (only applied when `bound` is set)
ariaLabel: 'Use the arrow keys to pick a date',
// position of the datepicker, relative to the field (default to bottom & left) // position of the datepicker, relative to the field (default to bottom & left)
// ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position) // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
position: 'bottom left', position: 'bottom left',
@ -193,6 +196,13 @@
// the default output format for `.toString()` and `field` value // the default output format for `.toString()` and `field` value
format: 'YYYY-MM-DD', format: 'YYYY-MM-DD',
// the toString function which gets passed a current date object and format
// and returns a string
toString: null,
// used to create date object from current input string
parse: null,
// the initial date to view when first opened // the initial date to view when first opened
defaultDate: null, defaultDate: null,
@ -216,6 +226,9 @@
// show week numbers at head of row // show week numbers at head of row
showWeekNumber: false, showWeekNumber: false,
// Week picker mode
pickWholeWeek: false,
// used internally (don't config outside) // used internally (don't config outside)
minYear: 0, minYear: 0,
maxYear: 9999, maxYear: 9999,
@ -236,6 +249,9 @@
// Render days of the calendar grid that fall in the next or previous month // Render days of the calendar grid that fall in the next or previous month
showDaysInNextAndPreviousMonths: false, showDaysInNextAndPreviousMonths: false,
// Allows user to select days that fall in the next or previous month
enableSelectionDaysInNextAndPreviousMonths: false,
// how many months are visible // how many months are visible
numberOfMonths: 1, numberOfMonths: 1,
@ -246,6 +262,9 @@
// Specify a DOM element to render the calendar in // Specify a DOM element to render the calendar in
container: undefined, container: undefined,
// Blur field when date is selected
blurFieldOnSelect : true,
// internationalization // internationalization
i18n: { i18n: {
previousMonth : 'Previous Month', previousMonth : 'Previous Month',
@ -258,11 +277,17 @@
// Theme Classname // Theme Classname
theme: null, theme: null,
// events array
events: [],
// callback function // callback function
onSelect: null, onSelect: null,
onOpen: null, onOpen: null,
onClose: null, onClose: null,
onDraw: null onDraw: null,
// Enable keyboard input
keyboardInput: true
}, },
@ -281,9 +306,15 @@
renderDay = function(opts) renderDay = function(opts)
{ {
var arr = []; var arr = [];
var ariaSelected = 'false';
if (opts.isEmpty) { if (opts.isEmpty) {
if (opts.showDaysInNextAndPreviousMonths) { if (opts.showDaysInNextAndPreviousMonths) {
arr.push('is-outside-current-month'); arr.push('is-outside-current-month');
if(!opts.enableSelectionDaysInNextAndPreviousMonths) {
arr.push('is-selection-disabled');
}
} else { } else {
return '<td class="is-empty"></td>'; return '<td class="is-empty"></td>';
} }
@ -296,6 +327,10 @@
} }
if (opts.isSelected) { if (opts.isSelected) {
arr.push('is-selected'); arr.push('is-selected');
ariaSelected = 'true';
}
if (opts.hasEvent) {
arr.push('has-event');
} }
if (opts.isInRange) { if (opts.isInRange) {
arr.push('is-inrange'); arr.push('is-inrange');
@ -306,7 +341,7 @@
if (opts.isEndRange) { if (opts.isEndRange) {
arr.push('is-endrange'); arr.push('is-endrange');
} }
return '<td data-day="' + opts.day + '" class="' + arr.join(' ') + '">' + return '<td data-day="' + opts.day + '" class="' + arr.join(' ') + '" aria-selected="' + ariaSelected + '">' +
'<button class="pika-button pika-day" type="button" ' + '<button class="pika-button pika-day" type="button" ' +
'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' + 'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' +
opts.day + opts.day +
@ -321,9 +356,9 @@
return '<td class="pika-week">' + weekNum + '</td>'; return '<td class="pika-week">' + weekNum + '</td>';
}, },
renderRow = function(days, isRTL) renderRow = function(days, isRTL, pickWholeWeek, isRowSelected)
{ {
return '<tr>' + (isRTL ? days.reverse() : days).join('') + '</tr>'; return '<tr class="pika-row' + (pickWholeWeek ? ' pick-whole-week' : '') + (isRowSelected ? ' is-selected' : '') + '">' + (isRTL ? days.reverse() : days).join('') + '</tr>';
}, },
renderBody = function(rows) renderBody = function(rows)
@ -343,13 +378,13 @@
return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>'; return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>';
}, },
renderTitle = function(instance, c, year, month, refYear) renderTitle = function(instance, c, year, month, refYear, randId)
{ {
var i, j, arr, var i, j, arr,
opts = instance._o, opts = instance._o,
isMinYear = year === opts.minYear, isMinYear = year === opts.minYear,
isMaxYear = year === opts.maxYear, isMaxYear = year === opts.maxYear,
html = '<div class="pika-title">', html = '<div id="' + randId + '" class="pika-title" role="heading" aria-live="assertive">',
monthHtml, monthHtml,
yearHtml, yearHtml,
prev = true, prev = true,
@ -361,6 +396,7 @@
((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled="disabled"' : '') + '>' + ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled="disabled"' : '') + '>' +
opts.i18n.months[i] + '</option>'); opts.i18n.months[i] + '</option>');
} }
monthHtml = '<div class="pika-label">' + opts.i18n.months[month] + '<select class="pika-select pika-select-month" tabindex="-1">' + arr.join('') + '</select></div>'; monthHtml = '<div class="pika-label">' + opts.i18n.months[month] + '<select class="pika-select pika-select-month" tabindex="-1">' + arr.join('') + '</select></div>';
if (isArray(opts.yearRange)) { if (isArray(opts.yearRange)) {
@ -402,9 +438,9 @@
return html += '</div>'; return html += '</div>';
}, },
renderTable = function(opts, data) renderTable = function(opts, data, randId)
{ {
return '<table cellpadding="0" cellspacing="0" class="pika-table">' + renderHead(opts) + renderBody(data) + '</table>'; return '<table cellpadding="0" cellspacing="0" class="pika-table" role="grid" aria-labelledby="' + randId + '">' + renderHead(opts) + renderBody(data) + '</table>';
}, },
@ -433,7 +469,7 @@
if (opts.bound) { if (opts.bound) {
sto(function() { sto(function() {
self.hide(); self.hide();
if (opts.field) { if (opts.blurFieldOnSelect && opts.field) {
opts.field.blur(); opts.field.blur();
} }
}, 100); }, 100);
@ -474,6 +510,36 @@
} }
}; };
self._onKeyChange = function(e)
{
e = e || window.event;
if (self.isVisible()) {
switch(e.keyCode){
case 13:
case 27:
if (opts.field) {
opts.field.blur();
}
break;
case 37:
e.preventDefault();
self.adjustDate('subtract', 1);
break;
case 38:
self.adjustDate('subtract', 7);
break;
case 39:
self.adjustDate('add', 1);
break;
case 40:
self.adjustDate('add', 7);
break;
}
}
};
self._onInputChange = function(e) self._onInputChange = function(e)
{ {
var date; var date;
@ -481,7 +547,9 @@
if (e.firedBy === self) { if (e.firedBy === self) {
return; return;
} }
if (hasMoment) { if (opts.parse) {
date = opts.parse(opts.field.value, opts.format);
} else if (hasMoment) {
date = moment(opts.field.value, opts.format, opts.formatStrict); date = moment(opts.field.value, opts.format, opts.formatStrict);
date = (date && date.isValid()) ? date.toDate() : null; date = (date && date.isValid()) ? date.toDate() : null;
} }
@ -557,6 +625,10 @@
addEvent(self.el, 'touchend', self._onMouseDown, true); addEvent(self.el, 'touchend', self._onMouseDown, true);
addEvent(self.el, 'change', self._onChange); addEvent(self.el, 'change', self._onChange);
if (opts.keyboardInput) {
addEvent(document, 'keydown', self._onKeyChange);
}
if (opts.field) { if (opts.field) {
if (opts.container) { if (opts.container) {
opts.container.appendChild(self.el); opts.container.appendChild(self.el);
@ -670,7 +742,17 @@
*/ */
toString: function(format) toString: function(format)
{ {
return !isDate(this._d) ? '' : hasMoment ? moment(this._d).format(format || this._o.format) : this._d.toDateString(); format = format || this._o.format;
if (!isDate(this._d)) {
return '';
}
if (this._o.toString) {
return this._o.toString(this._d, format);
}
if (hasMoment) {
return moment(this._d).format(format);
}
return this._d.toDateString();
}, },
/** /**
@ -777,6 +859,22 @@
this.adjustCalendars(); this.adjustCalendars();
}, },
adjustDate: function(sign, days) {
var day = this.getDate() || new Date();
var difference = parseInt(days)*24*60*60*1000;
var newDay;
if (sign === 'add') {
newDay = new Date(day.valueOf() + difference);
} else if (sign === 'subtract') {
newDay = new Date(day.valueOf() - difference);
}
this.setDate(newDay);
},
adjustCalendars: function() { adjustCalendars: function() {
this.calendars[0] = adjustCalendar(this.calendars[0]); this.calendars[0] = adjustCalendar(this.calendars[0]);
for (var c = 1; c < this._o.numberOfMonths; c++) { for (var c = 1; c < this._o.numberOfMonths; c++) {
@ -832,10 +930,18 @@
*/ */
setMinDate: function(value) setMinDate: function(value)
{ {
if(value instanceof Date) {
setToStartOfDay(value); setToStartOfDay(value);
this._o.minDate = value; this._o.minDate = value;
this._o.minYear = value.getFullYear(); this._o.minYear = value.getFullYear();
this._o.minMonth = value.getMonth(); this._o.minMonth = value.getMonth();
} else {
this._o.minDate = defaults.minDate;
this._o.minYear = defaults.minYear;
this._o.minMonth = defaults.minMonth;
this._o.startRange = defaults.startRange;
}
this.draw(); this.draw();
}, },
@ -844,10 +950,18 @@
*/ */
setMaxDate: function(value) setMaxDate: function(value)
{ {
if(value instanceof Date) {
setToStartOfDay(value); setToStartOfDay(value);
this._o.maxDate = value; this._o.maxDate = value;
this._o.maxYear = value.getFullYear(); this._o.maxYear = value.getFullYear();
this._o.maxMonth = value.getMonth(); this._o.maxMonth = value.getMonth();
} else {
this._o.maxDate = defaults.maxDate;
this._o.maxYear = defaults.maxYear;
this._o.maxMonth = defaults.maxMonth;
this._o.endRange = defaults.endRange;
}
this.draw(); this.draw();
}, },
@ -874,7 +988,8 @@
maxYear = opts.maxYear, maxYear = opts.maxYear,
minMonth = opts.minMonth, minMonth = opts.minMonth,
maxMonth = opts.maxMonth, maxMonth = opts.maxMonth,
html = ''; html = '',
randId;
if (this._y <= minYear) { if (this._y <= minYear) {
this._y = minYear; this._y = minYear;
@ -889,8 +1004,10 @@
} }
} }
randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2);
for (var c = 0; c < opts.numberOfMonths; c++) { for (var c = 0; c < opts.numberOfMonths; c++) {
html += '<div class="pika-lendar">' + renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year) + this.render(this.calendars[c].year, this.calendars[c].month) + '</div>'; html += '<div class="pika-lendar">' + renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId) + '</div>';
} }
this.el.innerHTML = html; this.el.innerHTML = html;
@ -906,6 +1023,11 @@
if (typeof this._o.onDraw === 'function') { if (typeof this._o.onDraw === 'function') {
this._o.onDraw(this); this._o.onDraw(this);
} }
if (opts.bound) {
// let the screen reader user know to use arrow keys
opts.field.setAttribute('aria-label', opts.ariaLabel);
}
}, },
adjustPosition: function() adjustPosition: function()
@ -962,7 +1084,7 @@
/** /**
* render HTML for a particular month * render HTML for a particular month
*/ */
render: function(year, month) render: function(year, month, randId)
{ {
var opts = this._o, var opts = this._o,
now = new Date(), now = new Date(),
@ -988,11 +1110,13 @@
after -= 7; after -= 7;
} }
cells += 7 - after; cells += 7 - after;
var isWeekSelected = false;
for (var i = 0, r = 0; i < cells; i++) for (var i = 0, r = 0; i < cells; i++)
{ {
var day = new Date(year, month, 1 + (i - before)), var day = new Date(year, month, 1 + (i - before)),
isSelected = isDate(this._d) ? compareDates(day, this._d) : false, isSelected = isDate(this._d) ? compareDates(day, this._d) : false,
isToday = compareDates(day, now), isToday = compareDates(day, now),
hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false,
isEmpty = i < before || i >= (days + before), isEmpty = i < before || i >= (days + before),
dayNumber = 1 + (i - before), dayNumber = 1 + (i - before),
monthNumber = month, monthNumber = month,
@ -1021,6 +1145,7 @@
day: dayNumber, day: dayNumber,
month: monthNumber, month: monthNumber,
year: yearNumber, year: yearNumber,
hasEvent: hasEvent,
isSelected: isSelected, isSelected: isSelected,
isToday: isToday, isToday: isToday,
isDisabled: isDisabled, isDisabled: isDisabled,
@ -1028,21 +1153,27 @@
isStartRange: isStartRange, isStartRange: isStartRange,
isEndRange: isEndRange, isEndRange: isEndRange,
isInRange: isInRange, isInRange: isInRange,
showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths,
enableSelectionDaysInNextAndPreviousMonths: opts.enableSelectionDaysInNextAndPreviousMonths
}; };
if (opts.pickWholeWeek && isSelected) {
isWeekSelected = true;
}
row.push(renderDay(dayConfig)); row.push(renderDay(dayConfig));
if (++r === 7) { if (++r === 7) {
if (opts.showWeekNumber) { if (opts.showWeekNumber) {
row.unshift(renderWeek(i - before, month, year)); row.unshift(renderWeek(i - before, month, year));
} }
data.push(renderRow(row, opts.isRTL)); data.push(renderRow(row, opts.isRTL, opts.pickWholeWeek, isWeekSelected));
row = []; row = [];
r = 0; r = 0;
isWeekSelected = false;
} }
} }
return renderTable(opts, data); return renderTable(opts, data, randId);
}, },
isVisible: function() isVisible: function()
@ -1052,10 +1183,10 @@
show: function() show: function()
{ {
if (!this._v) { if (!this.isVisible()) {
removeClass(this.el, 'is-hidden');
this._v = true; this._v = true;
this.draw(); this.draw();
removeClass(this.el, 'is-hidden');
if (this._o.bound) { if (this._o.bound) {
addEvent(document, 'click', this._onClick); addEvent(document, 'click', this._onClick);
this.adjustPosition(); this.adjustPosition();
@ -1089,16 +1220,21 @@
*/ */
destroy: function() destroy: function()
{ {
var opts = this._o;
this.hide(); this.hide();
removeEvent(this.el, 'mousedown', this._onMouseDown, true); removeEvent(this.el, 'mousedown', this._onMouseDown, true);
removeEvent(this.el, 'touchend', this._onMouseDown, true); removeEvent(this.el, 'touchend', this._onMouseDown, true);
removeEvent(this.el, 'change', this._onChange); removeEvent(this.el, 'change', this._onChange);
if (this._o.field) { if (opts.keyboardInput) {
removeEvent(this._o.field, 'change', this._onInputChange); removeEvent(document, 'keydown', this._onKeyChange);
if (this._o.bound) { }
removeEvent(this._o.trigger, 'click', this._onInputClick); if (opts.field) {
removeEvent(this._o.trigger, 'focus', this._onInputFocus); removeEvent(opts.field, 'change', this._onInputChange);
removeEvent(this._o.trigger, 'blur', this._onInputBlur); if (opts.bound) {
removeEvent(opts.trigger, 'click', this._onInputClick);
removeEvent(opts.trigger, 'focus', this._onInputFocus);
removeEvent(opts.trigger, 'blur', this._onInputBlur);
} }
} }
if (this.el.parentNode) { if (this.el.parentNode) {
@ -1109,5 +1245,4 @@
}; };
return Pikaday; return Pikaday;
})); }));