vanillajs-datepicker
Version:
A vanilla JavaScript remake of bootstrap-datepicker for Bulma and other CSS frameworks
149 lines (136 loc) • 4.51 kB
JavaScript
import {pushUnique, createTagRepeat} from '../../lib/utils.js';
import {dateValue, regularizeDate} from '../../lib/date.js';
import {parseHTML} from '../../lib/dom.js';
import View from './View.js';
function computeMonthRange(range, thisYear) {
if (!range || !range[0] || !range[1]) {
return;
}
const [[startY, startM], [endY, endM]] = range;
if (startY > thisYear || endY < thisYear) {
return;
}
return [
startY === thisYear ? startM : -1,
endY === thisYear ? endM : 12,
];
}
export default class MonthsView extends View {
constructor(picker) {
super(picker, {
id: 1,
name: 'months',
cellClass: 'month',
});
}
init(options, onConstruction = true) {
if (onConstruction) {
this.grid = this.element;
this.element.classList.add('months', 'datepicker-grid');
this.grid.appendChild(parseHTML(createTagRepeat('span', 12, {'data-month': ix => ix})));
this.first = 0;
this.last = 11;
}
super.init(options);
}
setOptions(options) {
if (options.locale) {
this.monthNames = options.locale.monthsShort;
}
if ('minDate' in options) {
if (options.minDate === undefined) {
this.minYear = this.minMonth = this.minDate = undefined;
} else {
const minDateObj = new Date(options.minDate);
this.minYear = minDateObj.getFullYear();
this.minMonth = minDateObj.getMonth();
this.minDate = minDateObj.setDate(1);
}
}
if ('maxDate' in options) {
if (options.maxDate === undefined) {
this.maxYear = this.maxMonth = this.maxDate = undefined;
} else {
const maxDateObj = new Date(options.maxDate);
this.maxYear = maxDateObj.getFullYear();
this.maxMonth = maxDateObj.getMonth();
this.maxDate = dateValue(this.maxYear, this.maxMonth + 1, 0);
}
}
if (options.checkDisabled) {
this.checkDisabled = this.isMinView || options.datesDisabled === null
? options.checkDisabled
: () => false;
}
if ('beforeShowMonth' in options) {
this.beforeShow = typeof options.beforeShowMonth === 'function'
? options.beforeShowMonth
: undefined;
}
}
// Update view's settings to reflect the viewDate set on the picker
updateFocus() {
const viewDate = new Date(this.picker.viewDate);
this.year = viewDate.getFullYear();
this.focused = viewDate.getMonth();
}
// Update view's settings to reflect the selected dates
updateSelection() {
const {dates, rangepicker} = this.picker.datepicker;
this.selected = dates.reduce((selected, timeValue) => {
const date = new Date(timeValue);
const year = date.getFullYear();
const month = date.getMonth();
if (selected[year] === undefined) {
selected[year] = [month];
} else {
pushUnique(selected[year], month);
}
return selected;
}, {});
if (rangepicker && rangepicker.dates) {
this.range = rangepicker.dates.map(timeValue => {
const date = new Date(timeValue);
return isNaN(date) ? undefined : [date.getFullYear(), date.getMonth()];
});
}
}
// Update the entire view UI
render() {
this.prepareForRender(
this.year,
this.year <= this.minYear,
this.year >= this.maxYear
);
const selected = this.selected[this.year] || [];
const yrOutOfRange = this.year < this.minYear || this.year > this.maxYear;
const isMinYear = this.year === this.minYear;
const isMaxYear = this.year === this.maxYear;
const range = computeMonthRange(this.range, this.year);
Array.from(this.grid.children).forEach((el, index) => {
const date = regularizeDate(new Date(this.year, index, 1), 1, this.isRangeEnd);
this.renderCell(
el,
this.monthNames[index],
index,
date,
{selected, range},
yrOutOfRange
|| isMinYear && index < this.minMonth
|| isMaxYear && index > this.maxMonth
);
});
}
// Update the view UI by applying the changes of selected and focused items
refresh() {
const selected = this.selected[this.year] || [];
const range = computeMonthRange(this.range, this.year) || [];
Array.from(this.grid.children).forEach((el, index) => {
this.refreshCell(el, index, selected, range);
});
}
// Update the view UI by applying the change of focused item
refreshFocus() {
this.changeFocusedCell(this.focused);
}
}