bulma-extensions
Advanced tools
Comparing version 2.2.2 to 3.0.0
@@ -10,74 +10,4 @@ # bulma-calendar | ||
# Examples | ||
### Date format | ||
```js | ||
date = bulmaCalendar.attach(document.querySelector('.sr-date'), { | ||
dataFormat: 'd MM yyyy' // 1 January 2018 | ||
}); | ||
``` | ||
where `dataFormat` is a string with a combination of this values: | ||
``` | ||
d: short day (1-31) | ||
dd: long day (00-31) | ||
D: weekday (es: Monday) | ||
m: short month (1-12) | ||
mm: long month (01-12) | ||
M: short month name (es: Jan, Feb) | ||
MM: full month name (es: January) | ||
yy: short year (18) | ||
yyyy: full year (2018) | ||
``` | ||
### Language | ||
```js | ||
date = bulmaCalendar.attach(document.querySelector('.sr-date'), { | ||
lang: 'it' // one of: en (default), fr, de, tr, it, th, pt-BR | ||
}); | ||
``` | ||
### Other options | ||
Here's the options object and the default values as appears on code. | ||
```js | ||
var defaultOptions = { | ||
startDate: new Date(), | ||
weekStart: null, | ||
minDate: null, | ||
maxDate: null, | ||
disabledDates: null, | ||
dateFormat: 'yyyy-mm-dd', // the default data format `field` value | ||
lang: 'en', // internationalization | ||
overlay: false, | ||
closeOnOverlayClick: true, | ||
closeOnSelect: true, | ||
toggleOnInputClick: true, | ||
icons: { | ||
month: { | ||
previous: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="45.63,75.8 0.375,38.087 45.63,0.375 "/> | ||
</svg>`, | ||
next: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="0.375,0.375 45.63,38.087 0.375,75.8 "/> | ||
</svg>` | ||
}, | ||
year: { | ||
previous: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="45.63,75.8 0.375,38.087 45.63,0.375 "/> | ||
</svg>`, | ||
next: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="0.375,0.375 45.63,38.087 0.375,75.8 "/> | ||
</svg>` | ||
} | ||
}; | ||
``` | ||
Documentation & Demo | ||
--- | ||
You can find the Documentation and a demo [here](https://wikiki.github.io/components/calendar/) | ||
Full Documentation and demo are avaible on [CreativeBulma](https://creativebulma.net/product/calendar/) |
const defaultOptions = { | ||
selectedDate: new Date(), | ||
weekStart: null, | ||
startDate: undefined, | ||
endDate: undefined, | ||
minDate: null, | ||
maxDate: null, | ||
isRange: false, | ||
disabledDates: [], | ||
disabledWeekDays: undefined, | ||
lang: 'en', // internationalization | ||
overlay: false, | ||
dateFormat: 'MM/DD/YYYY', | ||
displayMode: 'default', | ||
showHeader: true, | ||
showFooter: true, | ||
todayButton: true, | ||
clearButton: true, | ||
labelFrom: '', | ||
labelTo: '', | ||
weekStart: 0, | ||
closeOnOverlayClick: true, | ||
@@ -13,21 +23,11 @@ closeOnSelect: true, | ||
icons: { | ||
month: { | ||
previous: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="45.63,75.8 0.375,38.087 45.63,0.375 "/> | ||
</svg>`, | ||
next: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="0.375,0.375 45.63,38.087 0.375,75.8 "/> | ||
</svg>` | ||
}, | ||
year: { | ||
previous: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="45.63,75.8 0.375,38.087 45.63,0.375 "/> | ||
</svg>`, | ||
next: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="0.375,0.375 45.63,38.087 0.375,75.8 "/> | ||
</svg>` | ||
} | ||
previous: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="45.63,75.8 0.375,38.087 45.63,0.375 "/> | ||
</svg>`, | ||
next: `<svg viewBox="0 0 50 80" xml:space="preserve"> | ||
<polyline fill="none" stroke-width=".5em" stroke-linecap="round" stroke-linejoin="round" points="0.375,0.375 45.63,38.087 0.375,75.8 "/> | ||
</svg>` | ||
} | ||
}; | ||
export default defaultOptions; | ||
export default defaultOptions; |
@@ -1,17 +0,24 @@ | ||
import * as utils from './utils/type'; | ||
import * as utils from './utils/index'; | ||
import * as types from './utils/type'; | ||
import * as dateFns from 'date-fns'; | ||
import moment from 'moment'; | ||
import EventEmitter from './utils/events'; | ||
import defaultOptions from './defaultOptions'; | ||
import template from './template'; | ||
import templateCalendar from './templates/calendar'; | ||
import templateDays from './templates/days'; | ||
const onToggleDatePicker = Symbol('onToggleDatePicker'); | ||
const onCloseDatePicker = Symbol('onCloseDatePicker'); | ||
const onPreviousYearDatePicker = Symbol('onPreviousYearDatePicker'); | ||
const onNextYearDatePicker = Symbol('onNextYearDatePicker'); | ||
const onPreviousMonthDatePicker = Symbol('onPreviousMonthDatePicker'); | ||
const onNextMonthDatePicker = Symbol('onNextMonthDatePicker'); | ||
const onPreviousDatePicker = Symbol('onPreviousDatePicker'); | ||
const onNextDatePicker = Symbol('onNextDatePicker'); | ||
const onSelectMonthDatePicker = Symbol('onSelectMonthDatePicker'); | ||
const onMonthClickDatePicker = Symbol('onMonthClickDatePicker'); | ||
const onSelectYearDatePicker = Symbol('onSelectYearDatePicker'); | ||
const onYearClickDatePicker = Symbol('onYearClickDatePicker'); | ||
const onDateClickDatePicker = Symbol('onDateClickDatePicker'); | ||
const getDayNameDatePicker = Symbol('getDayNameDatePicker'); | ||
const onDocumentClickDatePicker = Symbol('onDocumentClickDatePicker'); | ||
const onValidateClickDatePicker = Symbol('onValidateClickDatePicker'); | ||
const onTodayClickDatePicker = Symbol('onTodayClickDatePicker'); | ||
const onClearClickDatePicker = Symbol('onClearClickDatePicker'); | ||
const onCancelClickDatePicker = Symbol('onCancelClickDatePicker'); | ||
@@ -21,3 +28,3 @@ let _supportsPassive = false; | ||
var opts = Object.defineProperty({}, 'passive', { | ||
get: function() { | ||
get: () => { | ||
_supportsPassive = true; | ||
@@ -34,3 +41,3 @@ } | ||
this.element = utils.isString(selector) ? document.querySelector(selector) : selector; | ||
this.element = types.isString(selector) ? document.querySelector(selector) : selector; | ||
// An invalid selector or non-DOM node has been provided. | ||
@@ -40,3 +47,3 @@ if (!this.element) { | ||
} | ||
this._clickEvents = ['click']; | ||
this._clickEvents = ['click', 'touch']; | ||
@@ -51,8 +58,14 @@ /// Set default options and merge with instance defined | ||
this[onCloseDatePicker] = this[onCloseDatePicker].bind(this); | ||
this[onPreviousYearDatePicker] = this[onPreviousYearDatePicker].bind(this); | ||
this[onNextYearDatePicker] = this[onNextYearDatePicker].bind(this); | ||
this[onPreviousMonthDatePicker] = this[onPreviousMonthDatePicker].bind(this); | ||
this[onNextMonthDatePicker] = this[onNextMonthDatePicker].bind(this); | ||
this[onPreviousDatePicker] = this[onPreviousDatePicker].bind(this); | ||
this[onNextDatePicker] = this[onNextDatePicker].bind(this); | ||
this[onSelectMonthDatePicker] = this[onSelectMonthDatePicker].bind(this); | ||
this[onMonthClickDatePicker] = this[onMonthClickDatePicker].bind(this); | ||
this[onSelectYearDatePicker] = this[onSelectYearDatePicker].bind(this); | ||
this[onYearClickDatePicker] = this[onYearClickDatePicker].bind(this); | ||
this[onDateClickDatePicker] = this[onDateClickDatePicker].bind(this); | ||
this[getDayNameDatePicker] = this[getDayNameDatePicker].bind(this); | ||
this[onDocumentClickDatePicker] = this[onDocumentClickDatePicker].bind(this); | ||
this[onValidateClickDatePicker] = this[onValidateClickDatePicker].bind(this); | ||
this[onTodayClickDatePicker] = this[onTodayClickDatePicker].bind(this); | ||
this[onClearClickDatePicker] = this[onClearClickDatePicker].bind(this); | ||
this[onCancelClickDatePicker] = this[onCancelClickDatePicker].bind(this); | ||
@@ -71,3 +84,3 @@ // Initiate plugin | ||
const datepickers = utils.isString(selector) ? document.querySelectorAll(selector) : Array.isArray(selector) ? selector : [selector]; | ||
const datepickers = types.isString(selector) ? document.querySelectorAll(selector) : Array.isArray(selector) ? selector : [selector]; | ||
[].forEach.call(datepickers, datepicker => { | ||
@@ -79,2 +92,8 @@ datepickerInstances.push(new bulmaCalendar(datepicker, options)); | ||
/**************************************************** | ||
* * | ||
* GETTERS and SETTERS * | ||
* * | ||
****************************************************/ | ||
/** | ||
@@ -89,3 +108,3 @@ * Get id of current datePicker | ||
get lang() { | ||
return moment.locale(); | ||
return this._lang; | ||
} | ||
@@ -95,14 +114,34 @@ | ||
set lang(lang = 'en') { | ||
moment.locale(lang); | ||
this._lang = lang; | ||
this._locale = require('date-fns/locale/' + lang); | ||
} | ||
get locale() { | ||
return this._locale; | ||
} | ||
// Get date object | ||
get date() { | ||
return this._date || moment(); | ||
return this._date || { | ||
start: undefined, | ||
end: undefined | ||
}; | ||
} | ||
set date(date = moment()) { | ||
this._date = moment(date).hours(0).minutes(0).seconds(0).milliseconds(0); | ||
get startDate() { | ||
return this._date.start; | ||
} | ||
get endDate() { | ||
return this._date.end; | ||
} | ||
set startDate(date) { | ||
this._date.start = date ? (this._isValidDate(date, this.minDate, this.maxDate) ? dateFns.startOfDay(date) : this._date.start) : undefined; | ||
} | ||
set endDate(date) { | ||
this._date.end = date ? (this._isValidDate(date, this.minDate, this.maxDate) ? dateFns.startOfDay(date) : this._date.end) : undefined; | ||
} | ||
// Get minDate | ||
@@ -113,5 +152,6 @@ get minDate() { | ||
// Set minDate (set to 1970-01-01 by default) | ||
set minDate(minDate = null) { | ||
this._minDate = minDate ? moment(minDate, this.dateFormat) : null; | ||
// Set minDate | ||
set minDate(date = undefined) { | ||
this._minDate = date ? (this._isValidDate(date) ? dateFns.startOfDay(date) : this._minDate) : undefined; | ||
return this; | ||
} | ||
@@ -124,5 +164,6 @@ | ||
// Set maxDate (set to 9999-12-31 by default) | ||
set maxDate(maxDate = null) { | ||
this._maxDate = maxDate ? moment(maxDate, this.dateFormat) : null; | ||
// Set maxDate | ||
set maxDate(date = null) { | ||
this._maxDate = date ? (this._isValidDate(date) ? dateFns.startOfDay(date) : this._maxDate) : undefined; | ||
return this; | ||
} | ||
@@ -138,143 +179,131 @@ | ||
this._dateFormat = dateFormat; | ||
this._initDates(); | ||
return this; | ||
} | ||
/**************************************************** | ||
* * | ||
* PUBLIC FUNCTIONS * | ||
* * | ||
****************************************************/ | ||
isRange() { | ||
return this.options.isRange; | ||
} | ||
/** | ||
* Initiate plugin instance | ||
* @method _init | ||
* @return {datePicker} Current plugin instance | ||
* Returns true if calendar picker is open, otherwise false. | ||
* @method isOpen | ||
* @return {boolean} | ||
*/ | ||
_init() { | ||
this._id = 'datePicker' + (new Date()).getTime() + Math.floor(Math.random() * Math.floor(9999)); | ||
this.lang = this.options.lang; | ||
this.dateFormat = this.options.dateFormat = this.options.dateFormat || this.element.dataset.dataFormat || moment.localeData().longDateFormat('L'); | ||
this._open = false; | ||
this._build(); | ||
this._bindEvents(); | ||
this.emit('datepicker:ready', this._date); | ||
return this; | ||
isOpen() { | ||
return this._open; | ||
} | ||
// Init dates used by datePicker core system | ||
_initDates() { | ||
// Set the selectedDate to the input value | ||
if (this.element.value) { | ||
if (this.element.getAttribute('type').toLowerCase() === 'date') { | ||
this.date = moment(this.element.value, 'YYYY-MM-DD'); | ||
/** | ||
* Get / Set datePicker value | ||
* @param {*} date | ||
*/ | ||
value(date = null) { | ||
if (date) { | ||
if (this.options.isRange) { | ||
const dates = this.element.value.split(' - '); | ||
if (dates.length) { | ||
this.startDate = new Date(dates[0]); | ||
} | ||
if (dates.length === 2) { | ||
this.endDate = new Date(dates[1]); | ||
} | ||
} else { | ||
this.date = moment(this.element.value); | ||
this.startDate = new Date(this.element.value); | ||
} | ||
} else { | ||
this.date = this.options.selectedDate ? moment(this.options.selectedDate) : moment(); | ||
} | ||
// Transform start date according to dateFormat option | ||
this.minDate = this.options.minDate ? moment(this.options.minDate) : null; | ||
this.maxDate = this.options.maxDate ? moment(this.options.maxDate) : null; | ||
if (this.options.disabledDates) { | ||
if (!Array.isArray(this.options.disabledDates)) { | ||
this.options.disabledDates = [this.options.disabledDates]; | ||
let value = ''; | ||
if (this.options.isRange) { | ||
if (this.startDate && this._isValidDate(this.startDate) && this.endDate && this._isValidDate(this.endDate)) { | ||
value = `${dateFns.format(this.startDate, this.dateFormat, { locale: this.locale })} - ${dateFns.format(this.endDate, this.dateFormat, { locale: this.locale })}`; | ||
} | ||
} else if (this.startDate && this._isValidDate(this.startDate)) { | ||
value = dateFns.format(this.startDate, this._dateFormat, { | ||
locale: this.locale | ||
}); | ||
} | ||
for (var i=0; i < this.options.disabledDates.length; i++) { | ||
this.options.disabledDates[i] = moment(this.options.disabledDates[i]); | ||
} | ||
this.emit('date:selected', this.date, this); | ||
return value; | ||
} | ||
} | ||
clear() { | ||
this._clear(); | ||
} | ||
/** | ||
* Build datePicker HTML component and append it to the DOM | ||
* @method _build | ||
* @return {datePicker} Current plugin instance | ||
* Show datePicker HTML Component | ||
* @method show | ||
* @return {void} | ||
*/ | ||
_build() { | ||
// Create datePicker HTML Fragment based on Template | ||
const datePickerFragment = document.createRange().createContextualFragment(template({ | ||
...this.options, | ||
id: this.id, | ||
date: this.date, | ||
month: moment.months()[this.date.month()], | ||
getDayName: this[getDayNameDatePicker] | ||
})); | ||
// Save pointer to each datePicker element for later use | ||
this.elementContainer = datePickerFragment.querySelector('#' + this.id); | ||
this.elementCalendar = this.elementContainer.querySelector('.calendar'); | ||
if (this.options.overlay) { | ||
this.elementOverlay = this.elementContainer.querySelector('.modal-background'); | ||
this.elementCloseButton = this.elementContainer.querySelector('.modal-close'); | ||
show() { | ||
this._snapshots = []; | ||
this._snapshot(); | ||
if (this.element.value) { | ||
this.value(this.element.value); | ||
} | ||
this.elementCalendarNav = this.elementCalendar.querySelector('.calendar-nav'); | ||
this.elementCalendarNavMonth = this.elementCalendar.querySelector('.calendar-month'); | ||
this.elementCalendarNavYear = this.elementCalendar.querySelector('.calendar-year'); | ||
this.elementCalendarNavDay = this.elementCalendar.querySelector('.calendar-day'); | ||
this.elementCalendarNavPreviousMonth = this.elementCalendarNav.querySelector('.calendar-nav-previous-month'); | ||
this.elementCalendarNavNextMonth = this.elementCalendarNav.querySelector('.calendar-nav-next-month'); | ||
this.elementCalendarNavPreviousYear = this.elementCalendarNav.querySelector('.calendar-nav-previous-year'); | ||
this.elementCalendarNavNextYear = this.elementCalendarNav.querySelector('.calendar-nav-next-year'); | ||
this.elementCalendarHeader = this.elementCalendar.querySelector('.calendar-header'); | ||
this.elementCalendarBody = this.elementCalendar.querySelector('.calendar-body'); | ||
this._visibleDate = this._isValidDate(this.startDate, this.minDate, this.maxDate) ? this.startDate : this._visibleDate; | ||
this._refreshCalendar(); | ||
this._ui.body.dates.classList.add('is-active'); | ||
this._ui.body.months.classList.remove('is-active'); | ||
this._ui.body.years.classList.remove('is-active'); | ||
this._ui.navigation.previous.removeAttribute('disabled'); | ||
this._ui.navigation.next.removeAttribute('disabled'); | ||
this._ui.container.classList.add('is-active'); | ||
if (this.options.displayMode === 'default') { | ||
this._adjustPosition(); | ||
} | ||
this._open = true; | ||
this._focus = true; | ||
// Add datepicker HTML element to Document Body | ||
document.body.appendChild(datePickerFragment); | ||
this.emit('show', this); | ||
} | ||
/** | ||
* Bind all events | ||
* @method _bindEvents | ||
* Hide datePicker HTML Component | ||
* @method hide | ||
* @return {void} | ||
*/ | ||
_bindEvents() { | ||
// Bind event to element in order to display/hide datePicker on click | ||
if(this.options.toggleOnInputClick === true){ | ||
this._clickEvents.forEach(clickEvent => { | ||
this.element.addEventListener(clickEvent, this[onToggleDatePicker]); | ||
}); | ||
} | ||
hide() { | ||
this._open = false; | ||
this._focus = false; | ||
this._ui.container.classList.remove('is-active'); | ||
this.emit('hide', this); | ||
} | ||
if (this.options.overlay) { | ||
// Bind close event on Close button | ||
if (this.elementCloseButton) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this.elementCloseButton.addEventListener(clickEvent, this[onCloseDatePicker]); | ||
}); | ||
} | ||
// Bind close event on overlay based on options | ||
if (this.options.closeOnOverlayClick && this.elementOverlay) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this.elementOverlay.addEventListener(clickEvent, this[onCloseDatePicker]); | ||
}); | ||
} | ||
} | ||
/** | ||
* Destroy datePicker | ||
* @method destroy | ||
* @return {[type]} [description] | ||
*/ | ||
destroy() { | ||
this._ui.container.remove(); | ||
} | ||
// Bind year navigation events | ||
if (this.elementCalendarNavPreviousYear) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this.elementCalendarNavPreviousYear.addEventListener(clickEvent, this[onPreviousYearDatePicker]); | ||
}); | ||
/**************************************************** | ||
* * | ||
* EVENTS FUNCTIONS * | ||
* * | ||
****************************************************/ | ||
[onDocumentClickDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
if (this.elementCalendarNavNextYear) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this.elementCalendarNavNextYear.addEventListener(clickEvent, this[onNextYearDatePicker]); | ||
}); | ||
} | ||
e.stopPropagation(); | ||
// Bind month navigation events | ||
if (this.elementCalendarNavPreviousMonth) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this.elementCalendarNavPreviousMonth.addEventListener(clickEvent, this[onPreviousMonthDatePicker]); | ||
}); | ||
if (this.options.displayMode !== 'inline' && this._open) { | ||
this[onCloseDatePicker](e); | ||
} | ||
if (this.elementCalendarNavNextMonth) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this.elementCalendarNavNextMonth.addEventListener(clickEvent, this[onNextMonthDatePicker]); | ||
}); | ||
} | ||
} | ||
[onToggleDatePicker](e) { | ||
e.preventDefault(); | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
e.stopPropagation(); | ||
@@ -288,37 +317,87 @@ if (this._open) { | ||
[onCloseDatePicker](e) { | ||
[onValidateClickDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
this.hide(); | ||
e.stopPropagation(); | ||
this[onCloseDatePicker](e); | ||
} | ||
[onPreviousYearDatePicker](e) { | ||
[onTodayClickDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
this.prevYear(); | ||
e.stopPropagation(); | ||
if (!this.options.isRange) { | ||
this.startDate = new Date(); | ||
this._visibleDate = this.startDate; | ||
} else { | ||
this._setStartAndEnd(new Date()); | ||
this._visibleDate = this.startDate; | ||
} | ||
this.element.value = this.value(); | ||
this._refreshCalendar(); | ||
} | ||
[onNextYearDatePicker](e) { | ||
[onClearClickDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
this.nextYear(); | ||
e.stopPropagation(); | ||
this._clear(); | ||
} | ||
[onPreviousMonthDatePicker](e) { | ||
[onCancelClickDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
this.prevMonth(); | ||
e.stopPropagation(); | ||
if (this._snapshots.length) { | ||
this.startDate = this._snapshots[0].start; | ||
this.endDate = this._snapshots[0].end; | ||
} | ||
this.element.value = this.value(); | ||
this[onCloseDatePicker](e); | ||
} | ||
[onNextMonthDatePicker](e) { | ||
[onCloseDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
this.nextMonth(); | ||
e.stopPropagation(); | ||
this.hide(); | ||
} | ||
[onPreviousDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
e.stopPropagation(); | ||
const prevMonth = dateFns.lastDayOfMonth(dateFns.subMonths(new Date(dateFns.getYear(this._visibleDate), dateFns.getMonth(this._visibleDate)), 1)); | ||
const day = Math.min(dateFns.getDaysInMonth(prevMonth), dateFns.getDate(this._visibleDate)); | ||
this._visibleDate = this.minDate ? dateFns.max(dateFns.setDate(prevMonth, day), this.minDate) : dateFns.setDate(prevMonth, day); | ||
this._refreshCalendar(); | ||
} | ||
[onNextDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
e.stopPropagation(); | ||
const nextMonth = dateFns.addMonths(this._visibleDate, 1); | ||
const day = Math.min(dateFns.getDaysInMonth(nextMonth), dateFns.getDate(this._visibleDate)); | ||
this._visibleDate = this.maxDate ? dateFns.min(dateFns.setDate(nextMonth, day), this.maxDate) : dateFns.setDate(nextMonth, day); | ||
this._refreshCalendar(); | ||
} | ||
[onDateClickDatePicker](e) { | ||
@@ -328,13 +407,13 @@ if (!_supportsPassive) { | ||
} | ||
e.stopPropagation(); | ||
if (!e.currentTarget.classList.contains('is-disabled')) { | ||
this.date = moment(e.currentTarget.dataset.date, this.dateFormat); | ||
this._setStartAndEnd(e.currentTarget.dataset.date); | ||
this.emit('datepicker:date:selected', this); | ||
this._refreshCalendar(); | ||
if (this.options.displayMode === 'inline' || this.options.closeOnSelect) { | ||
this.element.value = this.value(); | ||
} | ||
if (this.element.getAttribute('type').toLowerCase() === 'date') { | ||
this.element.value = this.date.format('YYYY-MM-DD'); | ||
} else { | ||
this.element.value = this.date.format(this.dateFormat); | ||
} | ||
if (this.options.closeOnSelect) { | ||
if ((!this.options.isRange || (this.startDate && this._isValidDate(this.startDate) && this.endDate && this._isValidDate(this.endDate))) && this.options.closeOnSelect) { | ||
this.hide(); | ||
@@ -345,224 +424,522 @@ } | ||
/** | ||
* Bind events on each Day item | ||
* @method _bindDaysEvents | ||
* @return {void} | ||
*/ | ||
_bindDaysEvents() { | ||
[].forEach.call(this.elementCalendarDays, (calendarDay) => { | ||
this._clickEvents.forEach(clickEvent => { | ||
calendarDay.addEventListener(clickEvent, this[onDateClickDatePicker]); | ||
}); | ||
}); | ||
[onSelectMonthDatePicker](e) { | ||
e.stopPropagation(); | ||
this._ui.body.dates.classList.remove('is-active'); | ||
this._ui.body.years.classList.remove('is-active'); | ||
this._ui.body.months.classList.add('is-active'); | ||
this._ui.navigation.previous.setAttribute('disabled', 'disabled'); | ||
this._ui.navigation.next.setAttribute('disabled', 'disabled'); | ||
} | ||
[onSelectYearDatePicker](e) { | ||
e.stopPropagation(); | ||
this._ui.body.dates.classList.remove('is-active'); | ||
this._ui.body.months.classList.remove('is-active'); | ||
this._ui.body.years.classList.add('is-active'); | ||
this._ui.navigation.previous.setAttribute('disabled', 'disabled'); | ||
this._ui.navigation.next.setAttribute('disabled', 'disabled'); | ||
const currentYear = this._ui.body.years.querySelector('.calendar-year.is-active'); | ||
if (currentYear) { | ||
this._ui.body.years.scrollTop = currentYear.offsetTop - this._ui.body.years.offsetTop - (this._ui.body.years.clientHeight / 2); | ||
} | ||
} | ||
[onMonthClickDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
e.stopPropagation(); | ||
const newDate = dateFns.setMonth(this._visibleDate, parseInt(e.currentTarget.dataset.month) - 1); | ||
this._visibleDate = this.minDate ? dateFns.max(newDate, this.minDate) : newDate; | ||
this._visibleDate = this.maxDate ? dateFns.min(this._visibleDate, this.maxDate) : this._visibleDate; | ||
this._refreshCalendar(); | ||
} | ||
[onYearClickDatePicker](e) { | ||
if (!_supportsPassive) { | ||
e.preventDefault(); | ||
} | ||
e.stopPropagation(); | ||
const newDate = dateFns.setYear(this._visibleDate, parseInt(e.currentTarget.dataset.year)); | ||
this._visibleDate = this.minDate ? dateFns.max(newDate, this.minDate) : newDate; | ||
this._visibleDate = this.maxDate ? dateFns.min(this._visibleDate, this.maxDate) : this._visibleDate; | ||
this._refreshCalendar(); | ||
} | ||
/**************************************************** | ||
* * | ||
* PRIVATE FUNCTIONS * | ||
* * | ||
****************************************************/ | ||
/** | ||
* Get localized day name | ||
* @method renderDayName | ||
* @param {[type]} day [description] | ||
* @param {Boolean} [abbr=false] [description] | ||
* @return {[type]} [description] | ||
* Initiate plugin instance | ||
* @method _init | ||
* @return {datePicker} Current plugin instance | ||
*/ | ||
[getDayNameDatePicker](day, abbr = false) { | ||
// will try to use weekStart from options if provided, also verify if it's in the range 0 ~ 6 | ||
day += typeof this.options.weekStart == 'number' && this.options.weekStart >= 0 && this.options.weekStart <= 6 ? this.options.weekStart : this.lang.weekStart; | ||
while (day >= 7) { | ||
day -= 7; | ||
_init() { | ||
this._id = utils.uuid('datePicker'); | ||
this._snapshots = []; | ||
// Cahnge element type to prevent browser default type="date" behavior | ||
if (this.element.getAttribute('type').toLowerCase() === 'date') { | ||
this.element.setAttribute('type', 'text'); | ||
} | ||
return abbr ? moment.weekdaysShort()[day] : moment.weekdays()[day]; | ||
} | ||
// Use Element dataset values to override options | ||
const elementConfig = this.element.dataset ? Object.keys(this.element.dataset) | ||
.filter(key => Object.keys(defaultOptions).includes(key)) | ||
.reduce((obj, key) => { | ||
return { | ||
...obj, | ||
[key]: this.element.dataset[key] | ||
}; | ||
}, {}) : {}; | ||
this.options = { | ||
...this.options, | ||
...elementConfig | ||
}; | ||
_renderDay(day, month, year, isSelected, isToday, isDisabled, isEmpty, isBetween, isSelectedIn, isSelectedOut) { | ||
const date = moment({ | ||
year: year, | ||
month: month, | ||
day: day | ||
}).format(this.dateFormat).toString(); | ||
return ` | ||
<div data-date="${`${date}`}" class="calendar-date${isDisabled ? ' is-disabled' : ''}${isBetween ? ' calendar-range' : ''}${isSelectedIn ? ' calendar-range-start' : ''}${isSelectedOut ? ' calendar-range-end' : ''}"> | ||
<button class="date-item${isToday ? ' is-today' : ''}${isSelected ? ' is-active' : ''}">${day}</button> | ||
</div> | ||
`; | ||
this.lang = this.options.lang; | ||
this.dateFormat = this.options.dateFormat || 'MM/DD/YYYY'; | ||
this._date = { | ||
start: undefined, | ||
end: undefined | ||
}; | ||
this._open = false; | ||
if (this.options.displayMode !== 'inline' && window.matchMedia('screen and (max-width: 768px)').matches) { | ||
this.options.displayMode = 'dialog'; | ||
} | ||
this._initDates(); | ||
this._build(); | ||
this._bindEvents(); | ||
this.emit('ready', this); | ||
return this; | ||
} | ||
_renderDays() { | ||
const now = moment().hours(0).minutes(0).seconds(0).milliseconds(0); | ||
let days = ''; | ||
// Init dates used by datePicker core system | ||
_initDates() { | ||
// Transform start date according to dateFormat option | ||
this.minDate = this.options.minDate; | ||
this.maxDate = this.options.maxDate; | ||
let numberOfDays = this.date.daysInMonth(), | ||
before = moment().year(this.date.year()).month(this.date.month()).date(1).day(); | ||
const today = new Date(); | ||
const startDateToday = this._isValidDate(today, this.options.minDate, this.options.maxDate) ? today : this.options.minDate; | ||
this.startDate = this.options.startDate; | ||
this.endDate = this.options.isRange ? this.options.endDate : undefined; | ||
// Get start day from options | ||
// will try to use weekStart from options if provided, also verify if it's in the range 0 ~ 6 | ||
const startDay = typeof this.options.weekStart != 'number' && this.options.weekStart >= 0 && this.options.weekStart <= 6 ? this.options.weekStart : moment().startOf('week').day(); | ||
if (startDay > 0) { | ||
before -= startDay; | ||
if (before < 0) { | ||
before += 7; | ||
if (this.element.value) { | ||
if (this.options.isRange) { | ||
const dates = this.element.value.split(' - '); | ||
if (dates.length) { | ||
this.startDate = new Date(dates[0]); | ||
} | ||
if (dates.length === 2) { | ||
this.endDate = new Date(dates[1]); | ||
} | ||
} else { | ||
this.startDate = new Date(this.element.value); | ||
} | ||
} | ||
this._visibleDate = this._isValidDate(this.startDate) ? this.startDate : startDateToday; | ||
let cells = numberOfDays + before, | ||
after = cells; | ||
while (after > 7) { | ||
after -= 7; | ||
if (this.options.disabledDates) { | ||
if (!Array.isArray(this.options.disabledDates)) { | ||
this.options.disabledDates = [this.options.disabledDates]; | ||
} | ||
for (var i = 0; i < this.options.disabledDates.length; i++) { | ||
this.options.disabledDates[i] = dateFns.format(this.options.disabledDates[i], this.options.dateFormat, { | ||
locale: this.locale | ||
}); | ||
} | ||
} | ||
cells += 7 - after; | ||
for (var i = 0; i < cells; i++) { | ||
var day = moment().year(this.date.year()).month(this.date.month()).date(1 + (i - before)).hours(0).minutes(0).seconds(0).milliseconds(0), | ||
isBetween = false, | ||
isSelected = day.diff(this.date) == 0, | ||
isSelectedIn = false, | ||
isSelectedOut = false, | ||
isToday = day.diff(now) == 0, | ||
isEmpty = i < before || i >= (numberOfDays + before), | ||
isDisabled = false; | ||
this._snapshot(); | ||
} | ||
if (!isSelected) { | ||
isSelectedIn = false; | ||
isSelectedOut = false; | ||
} | ||
/** | ||
* Build datePicker HTML component and append it to the DOM | ||
* @method _build | ||
* @return {datePicker} Current plugin instance | ||
*/ | ||
_build() { | ||
// the 7 days of the week (Sun-Sat) | ||
const labels = new Array(7).fill(dateFns.startOfWeek(this._visibleDate)).map((d, i) => dateFns.format(dateFns.addDays(d, i + this.options.weekStart), 'ddd', { | ||
locale: this.locale | ||
})); | ||
// the 12 months of the year (Jan-SDecat) | ||
const months = new Array(12).fill(dateFns.startOfWeek(this._visibleDate)).map((d, i) => dateFns.format(dateFns.addMonths(d, i), 'MM', { | ||
locale: this.locale | ||
})); | ||
// the 7 days of the week (Sun-Sat) | ||
const years = new Array(100).fill(dateFns.subYears(this._visibleDate, 50)).map((d, i) => dateFns.format(dateFns.addYears(d, i), 'YYYY', { | ||
locale: this.locale | ||
})); | ||
if (day.month() !== this.date.month() || (this.minDate && day.unix() < this.minDate.unix()) || (this.maxDate && day.unix() > this.maxDate.unix())) { | ||
isDisabled = true; | ||
} | ||
// Create datePicker HTML Fragment based on Template | ||
const datePickerFragment = document.createRange().createContextualFragment(templateCalendar({ | ||
...this.options, | ||
id: this.id, | ||
date: this.date, | ||
locale: this.locale, | ||
visibleDate: this._visibleDate, | ||
labels: { | ||
from: this.options.labelFrom, | ||
to: this.options.labelTo, | ||
weekdays: labels | ||
}, | ||
months: months, | ||
years: years, | ||
isRange: this.options.isRange, | ||
month: dateFns.format(this.month, 'MM', { | ||
locale: this.locale | ||
}) | ||
})); | ||
if (this.options.disabledDates) { | ||
for (let j = 0; j < this.options.disabledDates.length; j++) { | ||
if (day.unix() == this.options.disabledDates[j].unix()) { | ||
isDisabled = true; | ||
} | ||
} | ||
// Save pointer to each datePicker element for later use | ||
const container = datePickerFragment.querySelector('#' + this.id); | ||
this._ui = { | ||
container: container, | ||
calendar: container.querySelector('.calendar'), | ||
overlay: this.options.displayMode === 'dialog' ? { | ||
background: container.querySelector('.modal-background'), | ||
close: container.querySelector('.modal-close') | ||
} : undefined, | ||
header: { | ||
container: container.querySelector('.calendar-header'), | ||
start: { | ||
container: container.querySelector('.calendar-selection-start'), | ||
day: container.querySelector('.calendar-selection-start .calendar-selection-day'), | ||
month: container.querySelector('.calendar-selection-start .calendar-selection-month'), | ||
weekday: container.querySelector('.calendar-selection-start .calendar-selection-weekday'), | ||
empty: container.querySelector('.calendar-selection-start .empty') | ||
}, | ||
end: this.options.isRange ? { | ||
container: container.querySelector('.calendar-selection-end'), | ||
day: container.querySelector('.calendar-selection-end .calendar-selection-day'), | ||
month: container.querySelector('.calendar-selection-end .calendar-selection-month'), | ||
weekday: container.querySelector('.calendar-selection-end .calendar-selection-weekday'), | ||
empty: container.querySelector('.calendar-selection-start .empty') | ||
} : undefined | ||
}, | ||
navigation: { | ||
container: container.querySelector('.calendar-nav'), | ||
previous: container.querySelector('.calendar-nav-previous'), | ||
next: container.querySelector('.calendar-nav-next'), | ||
month: container.querySelector('.calendar-nav-month'), | ||
year: container.querySelector('.calendar-nav-year') | ||
}, | ||
footer: { | ||
container: container.querySelector('.calendar-footer'), | ||
validate: container.querySelector('.calendar-footer-validate'), | ||
today: container.querySelector('.calendar-footer-today'), | ||
clear: container.querySelector('.calendar-footer-clear'), | ||
cancel: container.querySelector('.calendar-footer-cancel'), | ||
}, | ||
body: { | ||
dates: container.querySelector('.calendar-dates'), | ||
days: container.querySelector('.calendar-days'), | ||
weekdays: container.querySelector('.calendar-weekdays'), | ||
months: container.querySelector('.calendar-months'), | ||
years: container.querySelector('.calendar-years') | ||
} | ||
}; | ||
days += this._renderDay(day.date(), day.month(), day.year(), isSelected, isToday, isDisabled, isEmpty, isBetween, isSelectedIn, isSelectedOut); | ||
if (!this.options.showHeader) { | ||
this._ui.header.container.classList.add('is-hidden'); | ||
} | ||
if (!this.options.showFooter) { | ||
this._ui.footer.container.classList.add('is-hidden'); | ||
} | ||
if (!this.options.todayButton) { | ||
this._ui.footer.todayB.classList.add('is-hidden'); | ||
} | ||
if (!this.options.clearButton) { | ||
this._ui.footer.clear.classList.add('is-hidden'); | ||
} | ||
if (this.options.displayMode === 'inline' && this._ui.footer.validate) { | ||
this._ui.footer.validate.classList.add('is-hidden'); | ||
} | ||
if (this.options.displayMode === 'inline' && this._ui.footer.cancel) { | ||
this._ui.footer.cancel.classList.add('is-hidden'); | ||
} | ||
if (this.options.closeOnSelect && this._ui.footer.validate) { | ||
this._ui.footer.validate.classList.add('is-hidden'); | ||
} | ||
this.emit('datepicker:rendered', this); | ||
// Add datepicker HTML element to Document Body | ||
if (this.options.displayMode === 'inline') { | ||
const wrapper = document.createElement('div'); | ||
this.element.parentNode.insertBefore(wrapper, this.element); | ||
wrapper.appendChild(this.element); | ||
this.element.classList.add('is-hidden'); | ||
wrapper.appendChild(datePickerFragment); | ||
container.classList.remove('datepicker'); | ||
this._refreshCalendar(); | ||
} else { | ||
document.body.appendChild(datePickerFragment); | ||
} | ||
this.elementCalendarBody.insertAdjacentHTML('beforeend', days); | ||
this.elementCalendarDays = this.elementCalendarBody.querySelectorAll('.calendar-date'); | ||
this._bindDaysEvents(); | ||
} | ||
/** | ||
* Navigate to the previous month and regenerate calendar | ||
* @method prevMonth | ||
* Bind all events | ||
* @method _bindEvents | ||
* @return {void} | ||
*/ | ||
prevMonth() { | ||
this.date.subtract(1, 'months'); | ||
this._refreshCalendar(); | ||
} | ||
_bindEvents() { | ||
// Bind event to element in order to display/hide datePicker on click | ||
// this._clickEvents.forEach(clickEvent => { | ||
// window.addEventListener(clickEvent, this[onDocumentClickDatePicker]); | ||
// }); | ||
window.addEventListener('scroll', () => { | ||
if (this.options.displayMode === 'default') { | ||
console('Scroll'); | ||
this._adjustPosition(); | ||
} | ||
}); | ||
_disablePrevMonth() { | ||
this.elementCalendarNavPreviousMonth.setAttribute('disabled', 'disabled'); | ||
} | ||
document.addEventListener('keydown', e => { | ||
if (this._focus) { | ||
switch (e.keyCode || e.which) { | ||
case 37: | ||
this[onPreviousDatePicker](e); | ||
break; | ||
case 39: | ||
this[onNextDatePicker](e); | ||
break; | ||
} | ||
} | ||
}); | ||
_enablePrevMonth() { | ||
this.elementCalendarNavPreviousMonth.removeAttribute('disabled'); | ||
} | ||
// Bind event to element in order to display/hide datePicker on click | ||
if (this.options.toggleOnInputClick === true) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this.element.addEventListener(clickEvent, this[onToggleDatePicker]); | ||
}); | ||
} | ||
/** | ||
* Navigate to the next month and regenerate calendar | ||
* @method nextMonth | ||
* @return {} | ||
*/ | ||
nextMonth() { | ||
this.date.add(1, 'months'); | ||
this._refreshCalendar(); | ||
} | ||
if (this.options.displayMode === 'dialog' && this._ui.overlay) { | ||
// Bind close event on Close button | ||
if (this._ui.overlay.close) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this.this._ui.overlay.close.addEventListener(clickEvent, this[onCloseDatePicker]); | ||
}); | ||
} | ||
// Bind close event on overlay based on options | ||
if (this.options.closeOnOverlayClick && this._ui.overlay.background) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.overlay.background.addEventListener(clickEvent, this[onCloseDatePicker]); | ||
}); | ||
} | ||
} | ||
_disableNextMonth() { | ||
this.elementCalendarNavNextMonth.setAttribute('disabled', 'disabled'); | ||
} | ||
// Bind year navigation events | ||
if (this._ui.navigation.previous) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.navigation.previous.addEventListener(clickEvent, this[onPreviousDatePicker]); | ||
}); | ||
} | ||
if (this._ui.navigation.next) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.navigation.next.addEventListener(clickEvent, this[onNextDatePicker]); | ||
}); | ||
} | ||
_enableNextMonth() { | ||
this.elementCalendarNavNextMonth.removeAttribute('disabled'); | ||
if (this._ui.navigation.month) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.navigation.month.addEventListener(clickEvent, this[onSelectMonthDatePicker]); | ||
}); | ||
} | ||
if (this._ui.navigation.year) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.navigation.year.addEventListener(clickEvent, this[onSelectYearDatePicker]); | ||
}); | ||
} | ||
const months = this._ui.body.months.querySelectorAll('.calendar-month') || []; | ||
months.forEach(month => { | ||
this._clickEvents.forEach(clickEvent => { | ||
month.addEventListener(clickEvent, this[onMonthClickDatePicker]); | ||
}); | ||
}); | ||
const years = this._ui.body.years.querySelectorAll('.calendar-year') || []; | ||
years.forEach(year => { | ||
this._clickEvents.forEach(clickEvent => { | ||
year.addEventListener(clickEvent, this[onYearClickDatePicker]); | ||
}); | ||
}); | ||
if (this._ui.footer.validate) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.footer.validate.addEventListener(clickEvent, this[onValidateClickDatePicker]); | ||
}); | ||
} | ||
if (this._ui.footer.today) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.footer.today.addEventListener(clickEvent, this[onTodayClickDatePicker]); | ||
}); | ||
} | ||
if (this._ui.footer.clear) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.footer.clear.addEventListener(clickEvent, this[onClearClickDatePicker]); | ||
}); | ||
} | ||
if (this._ui.footer.cancel) { | ||
this._clickEvents.forEach(clickEvent => { | ||
this._ui.footer.cancel.addEventListener(clickEvent, this[onCancelClickDatePicker]); | ||
}); | ||
} | ||
} | ||
/** | ||
* Navigate to the previous year and regenerate calendar | ||
* @method prevYear | ||
* Bind events on each Day item | ||
* @method _bindDaysEvents | ||
* @return {void} | ||
*/ | ||
prevYear() { | ||
this.date.subtract(1, 'y'); | ||
this._refreshCalendar(); | ||
} | ||
_bindDaysEvents() { | ||
[].forEach.call(this._ui.days, (day) => { | ||
this._clickEvents.forEach(clickEvent => { | ||
// if not in range, no click action | ||
// if in this month, select the date | ||
// if out of this month, jump to the date | ||
const onClick = !this._isValidDate(new Date(day.dataset.date), this.minDate, this.maxDate) ? null : this[onDateClickDatePicker]; | ||
day.addEventListener(clickEvent, onClick); | ||
}); | ||
_disablePrevYear() { | ||
this.elementCalendarNavPreviousYear.setAttribute('disabled', 'disabled'); | ||
day.addEventListener('hover', e => { | ||
e.preventDEfault(); | ||
}); | ||
}); | ||
} | ||
_enablePrevYear() { | ||
this.elementCalendarNavPreviousYear.removeAttribute('disabled'); | ||
} | ||
_renderDays() { | ||
// first day of current month view | ||
const start = dateFns.startOfWeek(dateFns.startOfMonth(this._visibleDate)); | ||
// last day of current month view | ||
const end = dateFns.endOfWeek(dateFns.endOfMonth(this._visibleDate)); | ||
/** | ||
* Navigate to the previous year and regenerate calendar | ||
* @method nextYear | ||
* @return {} | ||
*/ | ||
nextYear() { | ||
this.date.add(1, 'y'); | ||
this._refreshCalendar(); | ||
} | ||
// get all days and whether they are within the current month and range | ||
const days = new Array(dateFns.differenceInDays(end, start) + 1) | ||
.fill(start) | ||
.map((s, i) => { | ||
const theDate = dateFns.addDays(s, i + this.options.weekStart); | ||
const isThisMonth = dateFns.isSameMonth(this._visibleDate, theDate); | ||
const isInRange = this.options.isRange && dateFns.isWithinRange(theDate, this.startDate, this.endDate); | ||
let isDisabled = this.maxDate ? dateFns.isAfter(theDate, this.maxDate) : false; | ||
isDisabled = this.minDate ? dateFns.isBefore(theDate, this.minDate) : isDisabled; | ||
_disableNextYear() { | ||
this.elementCalendarNavNextYear.setAttribute('disabled', 'disabled'); | ||
if (this.options.disabledDates) { | ||
for (let j = 0; j < this.options.disabledDates.length; j++) { | ||
if (dateFns.getTime(theDate) == dateFns.getTime(this.options.disabledDates[j])) { | ||
isDisabled = true; | ||
} | ||
} | ||
} | ||
if (this.options.disabledWeekDays) { | ||
const disabledWeekDays = types.isString(this.options.disabledWeekDays) ? this.options.disabledWeekDays.split(',') : this.options.disabledWeekDays; | ||
disabledWeekDays.forEach(day => { | ||
if (dateFns.getDay(theDate) == day) { | ||
isDisabled = true; | ||
} | ||
}); | ||
} | ||
return { | ||
date: theDate, | ||
isRange: this.options.isRange, | ||
isToday: dateFns.isToday(theDate), | ||
isStartDate: dateFns.isEqual(this.startDate, theDate), | ||
isEndDate: dateFns.isEqual(this.endDate, theDate), | ||
isDisabled: isDisabled, | ||
isThisMonth, | ||
isInRange | ||
}; | ||
}); | ||
this._ui.body.days.appendChild(document.createRange().createContextualFragment(templateDays(days))); | ||
this._ui.days = this._ui.body.days.querySelectorAll('.calendar-date'); | ||
this._bindDaysEvents(); | ||
this.emit('rendered', this); | ||
} | ||
_enableNextYear() { | ||
this.elementCalendarNavNextYear.removeAttribute('disabled'); | ||
_togglePreviousButton(active = true) { | ||
if (!active) { | ||
this._ui.navigation.previous.setAttribute('disabled', 'disabled'); | ||
} else { | ||
this._ui.navigation.previous.removeAttribute('disabled'); | ||
} | ||
} | ||
/** | ||
* Returns true if calendar picker is open, otherwise false. | ||
* @method isOpen | ||
* @return {boolean} | ||
*/ | ||
isOpen() { | ||
return this._open; | ||
_toggleNextButton(active = true) { | ||
if (!active) { | ||
this._ui.navigation.next.setAttribute('disabled', 'disabled'); | ||
} else { | ||
this._ui.navigation.next.removeAttribute('disabled'); | ||
} | ||
} | ||
/** | ||
* Show datePicker HTML Component | ||
* @method show | ||
* @return {void} | ||
*/ | ||
show() { | ||
// Set the selectedDate to the input value | ||
if (this.element.value) { | ||
if (this.element.getAttribute('type').toLowerCase() === 'date') { | ||
this.date = moment(this.element.value, 'YYYY-MM-DD'); | ||
_setStartAndEnd(date) { | ||
this._snapshot(); | ||
if (this.options.isRange && (!this._isValidDate(this.startDate) || (this._isValidDate(this.startDate) && this._isValidDate(this.endDate)))) { | ||
this.startDate = new Date(date); | ||
this.endDate = undefined; | ||
this.emit('startDate:selected', this.date, this); | ||
} else if (this.options.isRange && !this._isValidDate(this.endDate)) { | ||
if (dateFns.isBefore(date, this.startDate)) { | ||
this.endDate = this.startDate; | ||
this.startDate = new Date(date); | ||
this.emit('startDate:selected', this.date, this); | ||
this.emit('endDate:selected', this.date, this); | ||
} else if (dateFns.isAfter(date, this.startDate)) { | ||
this.endDate = new Date(date); | ||
this.emit('endDate:selected', this.date, this); | ||
} else { | ||
this.date = moment(this.element.value); | ||
this.startDate = new Date(date); | ||
this.endDate = undefined; | ||
} | ||
} else { | ||
this.startDate = new Date(date); | ||
this.endDate = undefined; | ||
} | ||
this._refreshCalendar(); | ||
this.emit('datepicker:show', this); | ||
this.elementContainer.classList.add('is-active'); | ||
if (!this.options.overlay) { | ||
this._adjustPosition(); | ||
if (this.options.isRange && this._isValidDate(this.startDate) && this._isValidDate(this.endDate)) { | ||
new Array(dateFns.differenceInDays(this.endDate, this.startDate) + 1) | ||
.fill(this.startDate) | ||
.map((s, i) => { | ||
const theDate = dateFns.addDays(s, i); | ||
const dateElement = this._ui.body.dates.querySelector(`.calendar-date[data-date="${theDate.toString()}"]`); | ||
if (dateElement) { | ||
if (dateFns.isEqual(this.startDate, theDate)) { | ||
dateElement.classList.add('calendar-range-start'); | ||
} | ||
if (dateFns.isEqual(this.endDate, theDate)) { | ||
dateElement.classList.add('calendar-range-end'); | ||
} | ||
dateElement.classList.add('calendar-range'); | ||
} | ||
}); | ||
} | ||
this._open = true; | ||
} | ||
/** | ||
* Hide datePicker HTML Component | ||
* @method hide | ||
* @return {void} | ||
*/ | ||
hide() { | ||
this._open = false; | ||
this.emit('datepicker:hide', this); | ||
this.elementContainer.classList.remove('is-active'); | ||
_clear() { | ||
this.startDate = undefined; | ||
this.endDate = undefined; | ||
this.element.value = this.value(); | ||
if (this.options.displayMode !== 'inline' && this._open) { | ||
this.hide(); | ||
} | ||
this._refreshCalendar(); | ||
} | ||
@@ -576,57 +953,76 @@ | ||
_refreshCalendar() { | ||
if (this.date.month < 0) { | ||
this.date.year -= Math.ceil(Math.abs(this.date.month()) / 12); | ||
this.date.month += 12; | ||
} | ||
if (this.date.month > 11) { | ||
this.date.year += Math.floor(Math.abs(this.date.month()) / 12); | ||
this.date.month -= 12; | ||
} | ||
this.elementCalendarNavMonth.innerHTML = moment.months()[this.date.month()]; | ||
this.elementCalendarNavYear.innerHTML = this.date.year(); | ||
this.elementCalendarNavDay.innerHTML = this.date.date(); | ||
this.elementCalendarBody.innerHTML = ''; | ||
// this.elementCalendarNavDay.innerHTML = this.date.date(); | ||
this._ui.body.days.innerHTML = ''; | ||
let minMonth = 0, | ||
minYear = 0, | ||
maxMonth = 12, | ||
maxYear = 9999; | ||
if (this.minDate) { | ||
minMonth = this.minDate.month(); | ||
minYear = this.minDate.year(); | ||
} | ||
if (this.maxDate) { | ||
maxMonth = this.maxDate.month(); | ||
maxYear = this.maxDate.year(); | ||
} | ||
if (this.date.year() <= minYear) { | ||
this._disablePrevYear(); | ||
if (this.minDate && dateFns.differenceInMonths(this._visibleDate, this.minDate) === 0) { | ||
this._togglePreviousButton(false); | ||
} else { | ||
this._enablePrevYear(); | ||
this._togglePreviousButton(); | ||
} | ||
if (this.date.year() >= maxYear) { | ||
this._disableNextYear(); | ||
if (this.maxDate && dateFns.differenceInMonths(this._visibleDate, this.maxDate) === 0) { | ||
this._toggleNextButton(false); | ||
} else { | ||
this._enableNextYear(); | ||
this._toggleNextButton(); | ||
} | ||
if (this.date.year() <= minYear && this.date.month() <= minMonth) { | ||
this._disablePrevMonth(); | ||
} else { | ||
this._enablePrevMonth(); | ||
} | ||
this._refreshCalendarHeader(); | ||
if (this.date.year() >= maxYear && this.date.month() >= maxMonth) { | ||
this._disableNextMonth(); | ||
} else { | ||
this._enableNextMonth(); | ||
} | ||
this._ui.navigation.month.innerHTML = dateFns.format(this._visibleDate, 'MMMM', { | ||
locale: this.locale | ||
}); | ||
this._ui.navigation.year.innerHTML = dateFns.format(this._visibleDate, 'YYYY', { | ||
locale: this.locale | ||
}); | ||
const months = this._ui.body.months.querySelectorAll('.calendar-month') || []; | ||
months.forEach(month => { | ||
month.classList.remove('is-active'); | ||
if (month.dataset.month === dateFns.format(this._visibleDate, 'MM', { | ||
locale: this.locale | ||
})) { | ||
month.classList.add('is-active'); | ||
} | ||
}); | ||
const years = this._ui.body.years.querySelectorAll('.calendar-year') || []; | ||
years.forEach(year => { | ||
year.classList.remove('is-active'); | ||
if (year.dataset.year === dateFns.format(this._visibleDate, 'YYYY', { | ||
locale: this.locale | ||
})) { | ||
year.classList.add('is-active'); | ||
} | ||
}); | ||
this._renderDays(); | ||
this._ui.body.dates.classList.add('is-active'); | ||
this._ui.body.months.classList.remove('is-active'); | ||
this._ui.body.years.classList.remove('is-active'); | ||
this._ui.navigation.previous.removeAttribute('disabled'); | ||
this._ui.navigation.next.removeAttribute('disabled'); | ||
return this; | ||
} | ||
_refreshCalendarHeader() { | ||
this._ui.header.start.day.innerHTML = this._isValidDate(this.startDate) ? dateFns.getDate(this.startDate) : ' '; | ||
this._ui.header.start.weekday.innerHTML = this._isValidDate(this.startDate) ? dateFns.format(this.startDate, 'dddd', { | ||
locale: this.locale | ||
}) : ' '; | ||
this._ui.header.start.month.innerHTML = this._isValidDate(this.startDate) ? dateFns.format(this.startDate, 'MMMM YYYY', { | ||
locale: this.locale | ||
}) : ' '; | ||
if (this._ui.header.end) { | ||
this._ui.header.end.day.innerHTML = (this.options.isRange && this._isValidDate(this.endDate)) ? dateFns.getDate(this.endDate) : ' '; | ||
this._ui.header.end.weekday.innerHTML = (this.options.isRange && this._isValidDate(this.endDate)) ? dateFns.format(this.endDate, 'dddd', { | ||
locale: this.locale | ||
}) : ' '; | ||
this._ui.header.end.month.innerHTML = (this.options.isRange && this._isValidDate(this.endDate)) ? dateFns.format(this.endDate, 'MMMM YYYY', { | ||
locale: this.locale | ||
}) : ' '; | ||
} | ||
} | ||
/** | ||
@@ -658,15 +1054,36 @@ * Recalculate calendar position | ||
this.elementCalendar.style.position = 'absolute'; | ||
this.elementCalendar.style.left = left + 'px'; | ||
this.elementCalendar.style.top = top + 'px'; | ||
this._ui.container.style.position = 'absolute'; | ||
this._ui.container.style.left = left + 'px'; | ||
this._ui.container.style.top = top + 'px'; | ||
} | ||
/** | ||
* Destroy datePicker | ||
* @method destroy | ||
* @return {[type]} [description] | ||
*/ | ||
destroy() { | ||
this.elementCalendar.remove(); | ||
_isValidDate(date, minDate, maxDate) { | ||
try { | ||
if (!date) { | ||
return false; | ||
} | ||
if (dateFns.isValid(date)) { | ||
if (!minDate && !maxDate) { | ||
return true; | ||
} | ||
if (minDate && maxDate) { | ||
return dateFns.isWithinRange(date, minDate, maxDate); | ||
} | ||
if (maxDate) { | ||
return dateFns.isBefore(date, maxDate) || dateFns.isEqual(date, maxDate); | ||
} | ||
return dateFns.isAfter(date, minDate) || dateFns.isEqual(date, minDate); | ||
} else { | ||
return false; | ||
} | ||
} catch (e) { | ||
return false; | ||
} | ||
} | ||
} | ||
_snapshot() { | ||
this._snapshots.push({ | ||
...this._date | ||
}); | ||
} | ||
} |
@@ -6,3 +6,3 @@ { | ||
"style": "./dist/css/bulma-extensions.moin.css", | ||
"version": "2.2.2", | ||
"version": "3.0.0", | ||
"scripts": { | ||
@@ -9,0 +9,0 @@ "build": "gulp", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
3014552
181
54518
1
5