UNPKG

js-year-calendar

Version:

A fully customizable year calendar widget

1,329 lines (1,097 loc) 79 kB
(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports"], factory); } else if (typeof exports !== "undefined") { factory(exports); } else { var mod = { exports: {} }; factory(mod.exports); global.jsYearCalendar = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports["default"] = void 0; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /* ========================================================= * JS year calendar v1.0.0 * Repo: https://github.com/year-calendar/js-year-calendar * ========================================================= * Created by Paul David-Sivelle * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ========================================================= */ // NodeList forEach() polyfill if (typeof NodeList !== "undefined" && !NodeList.prototype.forEach) { NodeList.prototype.forEach = function (callback, thisArg) { thisArg = thisArg || window; for (var i = 0; i < this.length; i++) { callback.call(thisArg, this[i], i, this); } }; } // Element closest() polyfill if (typeof Element !== "undefined" && !Element.prototype.matches) { var prototype = Element.prototype; Element.prototype.matches = prototype.msMatchesSelector || prototype.webkitMatchesSelector; } if (typeof Element !== "undefined" && !Element.prototype.closest) { Element.prototype.closest = function (s) { var el = this; if (!document.documentElement.contains(el)) return null; do { if (el.matches(s)) return el; el = el.parentElement || el.parentNode; } while (el !== null && el.nodeType == 1); return null; }; } /** * Calendar instance. */ var Calendar = /*#__PURE__*/function () { /** * Fired when a day is clicked. * @event * @example * ``` * * document.querySelector('.calendar').addEventListener('clickDay', function(e) { * console.log("Click on day: " + e.date + " (" + e.events.length + " events)"); * }) * ``` */ /** * Fired when a day is right clicked. * @event * @example * ``` * * document.querySelector('.calendar').addEventListener('clickDay', function(e) { * console.log("Right click on day: " + e.date + " (" + e.events.length + " events)"); * }) * ``` */ /** * Fired when the mouse enter in a day. * @event * @example * ``` * * document.querySelector('.calendar').addEventListener('mouseOnDay', function(e) { * console.log("Mouse enter in a day: " + e.date + " (" + e.events.length + " events)"); * }) * ``` */ /** * Fired when the mouse leave a day. * @event * @example * ``` * * document.querySelector('.calendar').addEventListener('mouseOutDay', function(e) { * console.log("Mouse leave a day: " + e.date + " (" + e.events.length + " events)"); * }) * ``` */ /** * Fired when the calendar rendering is ended. * @event * @example * ``` * * document.querySelector('.calendar').addEventListener('renderEnd', function(e) { * console.log("Render end for year: " + e.currentYear); * }) * ``` */ /** * Fired when a date range is selected. * * Don't forget to enable the `enableRangeSelection` option to be able to use the range selection functionality. * @event * @example * ``` * * document.querySelector('.calendar').addEventListener('selectRange', function(e) { * console.log("Select the range: " + e.startDate + " - " + e.endDate); * }) * ``` */ /** * Triggered after the changing the current year. * Works only if the calendar is used in a full year mode. Otherwise, use `periodChanged` event. * @event * @example * ``` * * document.querySelector('.calendar').addEventListener('yearChanged', function(e) { * console.log("New year selected: " + e.currentYear); * }) * ``` */ /** * Triggered after the changing the visible period. * @event * @example * ``` * * document.querySelector('.calendar').addEventListener('periodChanged', function(e) { * console.log(`New period selected: ${e.startDate} ${e.endDate}`); * }) * ``` */ /** * Create a new calendar. * @param element The element (or the selector to an element) in which the calendar should be created. * @param options [Optional] The options used to customize the calendar */ function Calendar(element) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; _classCallCheck(this, Calendar); _defineProperty(this, "element", void 0); _defineProperty(this, "options", void 0); _defineProperty(this, "_startDate", void 0); _defineProperty(this, "_dataSource", void 0); _defineProperty(this, "_mouseDown", void 0); _defineProperty(this, "_rangeStart", void 0); _defineProperty(this, "_rangeEnd", void 0); _defineProperty(this, "_responsiveInterval", void 0); _defineProperty(this, "_nbCols", void 0); _defineProperty(this, "clickDay", void 0); _defineProperty(this, "dayContextMenu", void 0); _defineProperty(this, "mouseOnDay", void 0); _defineProperty(this, "mouseOutDay", void 0); _defineProperty(this, "renderEnd", void 0); _defineProperty(this, "selectRange", void 0); _defineProperty(this, "yearChanged", void 0); _defineProperty(this, "periodChanged", void 0); if (element instanceof HTMLElement) { this.element = element; } else if (typeof element === "string") { this.element = document.querySelector(element); } else { throw new Error("The element parameter should be a DOM node or a selector"); } this.element.classList.add('calendar'); this._initializeEvents(options); this._initializeOptions(options); var startYear = new Date().getFullYear(); var startMonth = 0; if (this.options.startDate) { startYear = this.options.startDate.getFullYear(); startMonth = this.options.startDate.getMonth(); } else if (this.options.startYear) { startYear = this.options.startYear; } this.setStartDate(new Date(startYear, startMonth, 1)); } _createClass(Calendar, [{ key: "_initializeOptions", value: function _initializeOptions(opt) { if (opt == null) { opt = {}; } this.options = { startYear: !isNaN(parseInt(opt.startYear)) ? parseInt(opt.startYear) : null, startDate: opt.startDate instanceof Date ? opt.startDate : null, numberMonthsDisplayed: !isNaN(parseInt(opt.numberMonthsDisplayed)) && opt.numberMonthsDisplayed > 0 && opt.numberMonthsDisplayed <= 12 ? parseInt(opt.numberMonthsDisplayed) : 12, minDate: opt.minDate instanceof Date ? opt.minDate : null, maxDate: opt.maxDate instanceof Date ? opt.maxDate : null, language: opt.language != null && Calendar.locales[opt.language] != null ? opt.language : 'en', allowOverlap: opt.allowOverlap != null ? opt.allowOverlap : true, displayWeekNumber: opt.displayWeekNumber != null ? opt.displayWeekNumber : false, displayDisabledDataSource: opt.displayDisabledDataSource != null ? opt.displayDisabledDataSource : false, displayHeader: opt.displayHeader != null ? opt.displayHeader : true, alwaysHalfDay: opt.alwaysHalfDay != null ? opt.alwaysHalfDay : false, enableRangeSelection: opt.enableRangeSelection != null ? opt.enableRangeSelection : false, disabledDays: opt.disabledDays instanceof Array ? opt.disabledDays : [], disabledWeekDays: opt.disabledWeekDays instanceof Array ? opt.disabledWeekDays : [], hiddenWeekDays: opt.hiddenWeekDays instanceof Array ? opt.hiddenWeekDays : [], roundRangeLimits: opt.roundRangeLimits != null ? opt.roundRangeLimits : false, dataSource: opt.dataSource instanceof Array || typeof opt.dataSource === "function" ? opt.dataSource : [], style: opt.style == 'background' || opt.style == 'border' || opt.style == 'custom' ? opt.style : 'border', enableContextMenu: opt.enableContextMenu != null ? opt.enableContextMenu : false, contextMenuItems: opt.contextMenuItems instanceof Array ? opt.contextMenuItems : [], customDayRenderer: typeof opt.customDayRenderer === "function" ? opt.customDayRenderer : null, customDataSourceRenderer: typeof opt.customDataSourceRenderer === "function" ? opt.customDataSourceRenderer : null, weekStart: !isNaN(parseInt(opt.weekStart)) ? parseInt(opt.weekStart) : null, loadingTemplate: typeof opt.loadingTemplate === "string" || opt.loadingTemplate instanceof HTMLElement ? opt.loadingTemplate : null }; if (this.options.dataSource instanceof Array) { this._dataSource = this.options.dataSource; this._initializeDatasourceColors(); } } }, { key: "_initializeEvents", value: function _initializeEvents(opt) { if (opt == null) { opt = []; } if (opt.yearChanged) { this.element.addEventListener('yearChanged', opt.yearChanged); } if (opt.periodChanged) { this.element.addEventListener('periodChanged', opt.periodChanged); } if (opt.renderEnd) { this.element.addEventListener('renderEnd', opt.renderEnd); } if (opt.clickDay) { this.element.addEventListener('clickDay', opt.clickDay); } if (opt.dayContextMenu) { this.element.addEventListener('dayContextMenu', opt.dayContextMenu); } if (opt.selectRange) { this.element.addEventListener('selectRange', opt.selectRange); } if (opt.mouseOnDay) { this.element.addEventListener('mouseOnDay', opt.mouseOnDay); } if (opt.mouseOutDay) { this.element.addEventListener('mouseOutDay', opt.mouseOutDay); } } }, { key: "_fetchDataSource", value: function _fetchDataSource(callback) { if (typeof this.options.dataSource === "function") { var getDataSource = this.options.dataSource; var currentPeriod = this.getCurrentPeriod(); var fetchParameters = { year: currentPeriod.startDate.getFullYear(), startDate: currentPeriod.startDate, endDate: currentPeriod.endDate }; if (getDataSource.length == 2) { // 2 parameters, means callback method getDataSource(fetchParameters, callback); } else { // 1 parameter, means synchronous or promise method var result = getDataSource(fetchParameters); if (result instanceof Array) { callback(result); } if (result && result.then) { result.then(callback); } } } else { callback(this.options.dataSource); } } }, { key: "_initializeDatasourceColors", value: function _initializeDatasourceColors() { for (var i = 0; i < this._dataSource.length; i++) { if (this._dataSource[i].color == null) { this._dataSource[i].color = Calendar.colors[i % Calendar.colors.length]; } } } /** * Renders the calendar. */ }, { key: "render", value: function render() { var isLoading = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; // Clear the calendar (faster method) while (this.element.firstChild) { this.element.removeChild(this.element.firstChild); } if (this.options.displayHeader) { this._renderHeader(); } if (isLoading) { this._renderLoading(); } else { this._renderBody(); this._renderDataSource(); this._applyEvents(); // Fade animation var months = this.element.querySelector('.months-container'); months.style.opacity = '0'; months.style.display = 'flex'; months.style.transition = 'opacity 0.5s'; setTimeout(function () { months.style.opacity = '1'; setTimeout(function () { return months.style.transition = ''; }, 500); }, 0); var currentPeriod = this.getCurrentPeriod(); this._triggerEvent('renderEnd', { currentYear: currentPeriod.startDate.getFullYear(), startDate: currentPeriod.startDate, endDate: currentPeriod.endDate }); } } }, { key: "_renderHeader", value: function _renderHeader() { var header = document.createElement('div'); header.classList.add('calendar-header'); var headerTable = document.createElement('table'); var period = this.getCurrentPeriod(); // Left arrow var prevDiv = document.createElement('th'); prevDiv.classList.add('prev'); if (this.options.minDate != null && this.options.minDate >= period.startDate) { prevDiv.classList.add('disabled'); } var prevIcon = document.createElement('span'); prevIcon.innerHTML = "&lsaquo;"; prevDiv.appendChild(prevIcon); headerTable.appendChild(prevDiv); if (this._isFullYearMode()) { // Year N-2 var prev2YearDiv = document.createElement('th'); prev2YearDiv.classList.add('year-title'); prev2YearDiv.classList.add('year-neighbor2'); prev2YearDiv.textContent = (this._startDate.getFullYear() - 2).toString(); if (this.options.minDate != null && this.options.minDate > new Date(this._startDate.getFullYear() - 2, 11, 31)) { prev2YearDiv.classList.add('disabled'); } headerTable.appendChild(prev2YearDiv); // Year N-1 var prevYearDiv = document.createElement('th'); prevYearDiv.classList.add('year-title'); prevYearDiv.classList.add('year-neighbor'); prevYearDiv.textContent = (this._startDate.getFullYear() - 1).toString(); if (this.options.minDate != null && this.options.minDate > new Date(this._startDate.getFullYear() - 1, 11, 31)) { prevYearDiv.classList.add('disabled'); } headerTable.appendChild(prevYearDiv); } // Current year var yearDiv = document.createElement('th'); yearDiv.classList.add('year-title'); if (this._isFullYearMode()) { yearDiv.textContent = this._startDate.getFullYear().toString(); } else if (this.options.numberMonthsDisplayed == 12) { yearDiv.textContent = "".concat(period.startDate.getFullYear(), " - ").concat(period.endDate.getFullYear()); } else if (this.options.numberMonthsDisplayed > 1) { yearDiv.textContent = "".concat(Calendar.locales[this.options.language].months[period.startDate.getMonth()], " ").concat(period.startDate.getFullYear(), " - ").concat(Calendar.locales[this.options.language].months[period.endDate.getMonth()], " ").concat(period.endDate.getFullYear()); } else { yearDiv.textContent = "".concat(Calendar.locales[this.options.language].months[period.startDate.getMonth()], " ").concat(period.startDate.getFullYear()); } headerTable.appendChild(yearDiv); if (this._isFullYearMode()) { // Year N+1 var nextYearDiv = document.createElement('th'); nextYearDiv.classList.add('year-title'); nextYearDiv.classList.add('year-neighbor'); nextYearDiv.textContent = (this._startDate.getFullYear() + 1).toString(); if (this.options.maxDate != null && this.options.maxDate < new Date(this._startDate.getFullYear() + 1, 0, 1)) { nextYearDiv.classList.add('disabled'); } headerTable.appendChild(nextYearDiv); // Year N+2 var next2YearDiv = document.createElement('th'); next2YearDiv.classList.add('year-title'); next2YearDiv.classList.add('year-neighbor2'); next2YearDiv.textContent = (this._startDate.getFullYear() + 2).toString(); if (this.options.maxDate != null && this.options.maxDate < new Date(this._startDate.getFullYear() + 2, 0, 1)) { next2YearDiv.classList.add('disabled'); } headerTable.appendChild(next2YearDiv); } // Right arrow var nextDiv = document.createElement('th'); nextDiv.classList.add('next'); if (this.options.maxDate != null && this.options.maxDate <= period.endDate) { nextDiv.classList.add('disabled'); } var nextIcon = document.createElement('span'); nextIcon.innerHTML = "&rsaquo;"; nextDiv.appendChild(nextIcon); headerTable.appendChild(nextDiv); header.appendChild(headerTable); this.element.appendChild(header); } }, { key: "_renderBody", value: function _renderBody() { var monthsDiv = document.createElement('div'); monthsDiv.classList.add('months-container'); var monthStartDate = new Date(this._startDate.getTime()); for (var m = 0; m < this.options.numberMonthsDisplayed; m++) { /* Container */ var monthDiv = document.createElement('div'); monthDiv.classList.add('month-container'); monthDiv.dataset.monthId = m.toString(); if (this._nbCols) { monthDiv.classList.add("month-".concat(this._nbCols)); } var table = document.createElement('table'); table.classList.add('month'); /* Month header */ var thead = document.createElement('thead'); var titleRow = document.createElement('tr'); var titleCell = document.createElement('th'); titleCell.classList.add('month-title'); titleCell.setAttribute('colspan', this.options.displayWeekNumber ? '8' : '7'); titleCell.textContent = Calendar.locales[this.options.language].months[monthStartDate.getMonth()]; titleRow.appendChild(titleCell); thead.appendChild(titleRow); var headerRow = document.createElement('tr'); if (this.options.displayWeekNumber) { var weekNumberCell = document.createElement('th'); weekNumberCell.classList.add('week-number'); weekNumberCell.textContent = Calendar.locales[this.options.language].weekShort; headerRow.appendChild(weekNumberCell); } var weekStart = this.getWeekStart(); var d = weekStart; do { var headerCell = document.createElement('th'); headerCell.classList.add('day-header'); headerCell.textContent = Calendar.locales[this.options.language].daysMin[d]; if (this._isHidden(d)) { headerCell.classList.add('hidden'); } headerRow.appendChild(headerCell); d++; if (d >= 7) d = 0; } while (d != weekStart); thead.appendChild(headerRow); table.appendChild(thead); /* Days */ var currentDate = new Date(monthStartDate.getTime()); var lastDate = new Date(monthStartDate.getFullYear(), monthStartDate.getMonth() + 1, 0); while (currentDate.getDay() != weekStart) { currentDate.setDate(currentDate.getDate() - 1); } while (currentDate <= lastDate) { var row = document.createElement('tr'); if (this.options.displayWeekNumber) { var weekNumberCell = document.createElement('td'); var currentThursday = new Date(currentDate.getTime()); // Week number is computed based on the thursday currentThursday.setDate(currentThursday.getDate() - weekStart + 4); weekNumberCell.classList.add('week-number'); weekNumberCell.textContent = this.getWeekNumber(currentThursday).toString(); row.appendChild(weekNumberCell); } do { var cell = document.createElement('td'); cell.classList.add('day'); if (this._isHidden(currentDate.getDay())) { cell.classList.add('hidden'); } if (currentDate < monthStartDate) { cell.classList.add('old'); } else if (currentDate > lastDate) { cell.classList.add('new'); } else { if (this._isDisabled(currentDate)) { cell.classList.add('disabled'); } var cellContent = document.createElement('div'); cellContent.classList.add('day-content'); cellContent.textContent = currentDate.getDate().toString(); cell.appendChild(cellContent); if (this.options.customDayRenderer) { this.options.customDayRenderer(cellContent, currentDate); } } row.appendChild(cell); currentDate.setDate(currentDate.getDate() + 1); } while (currentDate.getDay() != weekStart); table.appendChild(row); } monthDiv.appendChild(table); monthsDiv.appendChild(monthDiv); monthStartDate.setMonth(monthStartDate.getMonth() + 1); } this.element.appendChild(monthsDiv); } }, { key: "_renderLoading", value: function _renderLoading() { var container = document.createElement('div'); container.classList.add('calendar-loading-container'); container.style.minHeight = this._nbCols * 200 + 'px'; var loading = document.createElement('div'); loading.classList.add('calendar-loading'); if (this.options.loadingTemplate) { if (typeof this.options.loadingTemplate === "string") { loading.innerHTML = this.options.loadingTemplate; } else if (this.options.loadingTemplate instanceof HTMLElement) { loading.appendChild(this.options.loadingTemplate); } } else { var spinner = document.createElement('div'); spinner.classList.add('calendar-spinner'); for (var i = 1; i <= 3; i++) { var bounce = document.createElement('div'); bounce.classList.add("bounce".concat(i)); spinner.appendChild(bounce); } loading.appendChild(spinner); } container.appendChild(loading); this.element.appendChild(container); } }, { key: "_renderDataSource", value: function _renderDataSource() { var _this = this; if (this._dataSource != null && this._dataSource.length > 0) { this.element.querySelectorAll('.month-container').forEach(function (month) { var monthId = parseInt(month.dataset.monthId); var currentYear = _this._startDate.getFullYear(); var currentMonth = _this._startDate.getMonth() + monthId; var firstDate = new Date(currentYear, currentMonth, 1); var lastDate = new Date(currentYear, currentMonth + 1, 1); if ((_this.options.minDate == null || lastDate > _this.options.minDate) && (_this.options.maxDate == null || firstDate <= _this.options.maxDate)) { var monthData = []; for (var i = 0; i < _this._dataSource.length; i++) { if (!(_this._dataSource[i].startDate >= lastDate) || _this._dataSource[i].endDate < firstDate) { monthData.push(_this._dataSource[i]); } } if (monthData.length > 0) { month.querySelectorAll('.day-content').forEach(function (day) { var currentDate = new Date(currentYear, currentMonth, parseInt(day.textContent)); var nextDate = new Date(currentYear, currentMonth, currentDate.getDate() + 1); var dayData = []; if ((_this.options.minDate == null || currentDate >= _this.options.minDate) && (_this.options.maxDate == null || currentDate <= _this.options.maxDate)) { for (var i = 0; i < monthData.length; i++) { if (monthData[i].startDate < nextDate && monthData[i].endDate >= currentDate) { dayData.push(monthData[i]); } } if (dayData.length > 0 && (_this.options.displayDisabledDataSource || !_this._isDisabled(currentDate))) { _this._renderDataSourceDay(day, currentDate, dayData); } } }); } } }); } } }, { key: "_renderDataSourceDay", value: function _renderDataSourceDay(elt, currentDate, events) { var parent = elt.parentElement; switch (this.options.style) { case 'border': var weight = 0; if (events.length == 1) { weight = 4; } else if (events.length <= 3) { weight = 2; } else { parent.style.boxShadow = 'inset 0 -4px 0 0 black'; } if (weight > 0) { var boxShadow = ''; for (var i = 0; i < events.length; i++) { if (boxShadow != '') { boxShadow += ","; } boxShadow += "inset 0 -".concat((i + 1) * weight, "px 0 0 ").concat(events[i].color); } parent.style.boxShadow = boxShadow; } break; case 'background': parent.style.backgroundColor = events[events.length - 1].color; var currentTime = currentDate.getTime(); if (events[events.length - 1].startDate.getTime() == currentTime) { parent.classList.add('day-start'); if (events[events.length - 1].startHalfDay || this.options.alwaysHalfDay) { parent.classList.add('day-half'); // Find color for other half var otherColor = 'transparent'; for (var i = events.length - 2; i >= 0; i--) { if (events[i].startDate.getTime() != currentTime || !events[i].startHalfDay && !this.options.alwaysHalfDay) { otherColor = events[i].color; break; } } parent.style.background = "linear-gradient(-45deg, ".concat(events[events.length - 1].color, ", ").concat(events[events.length - 1].color, " 49%, ").concat(otherColor, " 51%, ").concat(otherColor, ")"); } else if (this.options.roundRangeLimits) { parent.classList.add('round-left'); } } else if (events[events.length - 1].endDate.getTime() == currentTime) { parent.classList.add('day-end'); if (events[events.length - 1].endHalfDay || this.options.alwaysHalfDay) { parent.classList.add('day-half'); // Find color for other half var otherColor = 'transparent'; for (var i = events.length - 2; i >= 0; i--) { if (events[i].endDate.getTime() != currentTime || !events[i].endHalfDay && !this.options.alwaysHalfDay) { otherColor = events[i].color; break; } } parent.style.background = "linear-gradient(135deg, ".concat(events[events.length - 1].color, ", ").concat(events[events.length - 1].color, " 49%, ").concat(otherColor, " 51%, ").concat(otherColor, ")"); } else if (this.options.roundRangeLimits) { parent.classList.add('round-right'); } } break; case 'custom': if (this.options.customDataSourceRenderer) { this.options.customDataSourceRenderer.call(this, elt, currentDate, events); } break; } } }, { key: "_applyEvents", value: function _applyEvents() { var _this2 = this; if (this.options.displayHeader) { /* Header buttons */ this.element.querySelectorAll('.year-neighbor, .year-neighbor2').forEach(function (element) { element.addEventListener('click', function (e) { if (!e.currentTarget.classList.contains('disabled')) { _this2.setYear(parseInt(e.currentTarget.textContent)); } }); }); this.element.querySelector('.calendar-header .prev').addEventListener('click', function (e) { if (!e.currentTarget.classList.contains('disabled')) { var months = _this2.element.querySelector('.months-container'); months.style.transition = 'margin-left 0.1s'; months.style.marginLeft = '100%'; setTimeout(function () { months.style.visibility = 'hidden'; months.style.transition = ''; months.style.marginLeft = '0'; setTimeout(function () { _this2.setStartDate(new Date(_this2._startDate.getFullYear(), _this2._startDate.getMonth() - _this2.options.numberMonthsDisplayed, 1)); }, 50); }, 100); } }); this.element.querySelector('.calendar-header .next').addEventListener('click', function (e) { if (!e.currentTarget.classList.contains('disabled')) { var months = _this2.element.querySelector('.months-container'); months.style.transition = 'margin-left 0.1s'; months.style.marginLeft = '-100%'; setTimeout(function () { months.style.visibility = 'hidden'; months.style.transition = ''; months.style.marginLeft = '0'; setTimeout(function () { _this2.setStartDate(new Date(_this2._startDate.getFullYear(), _this2._startDate.getMonth() + _this2.options.numberMonthsDisplayed, 1)); }, 50); }, 100); } }); } var cells = this.element.querySelectorAll('.day:not(.old):not(.new):not(.disabled)'); cells.forEach(function (cell) { /* Click on date */ cell.addEventListener('click', function (e) { e.stopPropagation(); var date = _this2._getDate(e.currentTarget); _this2._triggerEvent('clickDay', { element: e.currentTarget, date: date, events: _this2.getEvents(date) }); }); /* Click right on date */ cell.addEventListener('contextmenu', function (e) { if (_this2.options.enableContextMenu) { e.preventDefault(); if (_this2.options.contextMenuItems.length > 0) { _this2._openContextMenu(e.currentTarget); } } var date = _this2._getDate(e.currentTarget); _this2._triggerEvent('dayContextMenu', { element: e.currentTarget, date: date, events: _this2.getEvents(date) }); }); /* Range selection */ if (_this2.options.enableRangeSelection) { cell.addEventListener('mousedown', function (e) { if (e.which == 1) { var currentDate = _this2._getDate(e.currentTarget); if (_this2.options.allowOverlap || _this2.isThereFreeSlot(currentDate)) { _this2._mouseDown = true; _this2._rangeStart = _this2._rangeEnd = currentDate; _this2._refreshRange(); } } }); cell.addEventListener('mouseenter', function (e) { if (_this2._mouseDown) { var currentDate = _this2._getDate(e.currentTarget); if (!_this2.options.allowOverlap) { var newDate = new Date(_this2._rangeStart.getTime()); if (newDate < currentDate) { var nextDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() + 1); while (newDate < currentDate) { if (!_this2.isThereFreeSlot(nextDate, false)) { break; } newDate.setDate(newDate.getDate() + 1); nextDate.setDate(nextDate.getDate() + 1); } } else { var nextDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() - 1); while (newDate > currentDate) { if (!_this2.isThereFreeSlot(nextDate, true)) { break; } newDate.setDate(newDate.getDate() - 1); nextDate.setDate(nextDate.getDate() - 1); } } currentDate = newDate; } var oldValue = _this2._rangeEnd; _this2._rangeEnd = currentDate; if (oldValue.getTime() != _this2._rangeEnd.getTime()) { _this2._refreshRange(); } } }); } /* Hover date */ cell.addEventListener('mouseenter', function (e) { if (!_this2._mouseDown) { var date = _this2._getDate(e.currentTarget); _this2._triggerEvent('mouseOnDay', { element: e.currentTarget, date: date, events: _this2.getEvents(date) }); } }); cell.addEventListener('mouseleave', function (e) { var date = _this2._getDate(e.currentTarget); _this2._triggerEvent('mouseOutDay', { element: e.currentTarget, date: date, events: _this2.getEvents(date) }); }); }); if (this.options.enableRangeSelection) { // Release range selection window.addEventListener('mouseup', function (e) { if (_this2._mouseDown) { _this2._mouseDown = false; _this2._refreshRange(); var minDate = _this2._rangeStart < _this2._rangeEnd ? _this2._rangeStart : _this2._rangeEnd; var maxDate = _this2._rangeEnd > _this2._rangeStart ? _this2._rangeEnd : _this2._rangeStart; _this2._triggerEvent('selectRange', { startDate: minDate, endDate: maxDate, events: _this2.getEventsOnRange(minDate, new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate() + 1)) }); } }); } /* Responsive management */ if (this._responsiveInterval) { clearInterval(this._responsiveInterval); this._responsiveInterval = null; } this._responsiveInterval = setInterval(function () { if (_this2.element.querySelector('.month') == null) { return; } var calendarSize = _this2.element.offsetWidth; var monthSize = _this2.element.querySelector('.month').offsetWidth + 10; _this2._nbCols = null; if (monthSize * 6 < calendarSize && _this2.options.numberMonthsDisplayed >= 6) { _this2._nbCols = 2; } else if (monthSize * 4 < calendarSize && _this2.options.numberMonthsDisplayed >= 4) { _this2._nbCols = 3; } else if (monthSize * 3 < calendarSize && _this2.options.numberMonthsDisplayed >= 3) { _this2._nbCols = 4; } else if (monthSize * 2 < calendarSize && _this2.options.numberMonthsDisplayed >= 2) { _this2._nbCols = 6; } else { _this2._nbCols = 12; } _this2.element.querySelectorAll('.month-container').forEach(function (month) { if (!month.classList.contains("month-".concat(_this2._nbCols))) { ['month-2', 'month-3', 'month-4', 'month-6', 'month-12'].forEach(function (className) { month.classList.remove(className); }); month.classList.add("month-".concat(_this2._nbCols)); } }); }, 300); } }, { key: "_refreshRange", value: function _refreshRange() { var _this3 = this; this.element.querySelectorAll('td.day.range').forEach(function (day) { return day.classList.remove('range'); }); this.element.querySelectorAll('td.day.range-start').forEach(function (day) { return day.classList.remove('range-start'); }); this.element.querySelectorAll('td.day.range-end').forEach(function (day) { return day.classList.remove('range-end'); }); if (this._mouseDown) { var minDate = this._rangeStart < this._rangeEnd ? this._rangeStart : this._rangeEnd; var maxDate = this._rangeEnd > this._rangeStart ? this._rangeEnd : this._rangeStart; this.element.querySelectorAll('.month-container').forEach(function (month) { var monthId = parseInt(month.dataset.monthId); var monthStartDate = new Date(_this3._startDate.getFullYear(), _this3._startDate.getMonth() + monthId, 1); var monthEndDate = new Date(_this3._startDate.getFullYear(), _this3._startDate.getMonth() + monthId + 1, 1); if (minDate.getTime() < monthEndDate.getTime() && maxDate.getTime() >= monthStartDate.getTime()) { month.querySelectorAll('td.day:not(.old):not(.new)').forEach(function (day) { var date = _this3._getDate(day); if (date >= minDate && date <= maxDate) { day.classList.add('range'); if (date.getTime() == minDate.getTime()) { day.classList.add('range-start'); } if (date.getTime() == maxDate.getTime()) { day.classList.add('range-end'); } } }); } }); } } }, { key: "_getElementPosition", value: function _getElementPosition(element) { var top = 0, left = 0; do { top += element.offsetTop || 0; left += element.offsetLeft || 0; element = element.offsetParent; } while (element); return { top: top, left: left }; } }, { key: "_openContextMenu", value: function _openContextMenu(elt) { var _this4 = this; var contextMenu = document.querySelector('.calendar-context-menu'); if (contextMenu !== null) { contextMenu.style.display = 'none'; // Clear the context menu (faster method) while (contextMenu.firstChild) { contextMenu.removeChild(contextMenu.firstChild); } } else { contextMenu = document.createElement('div'); contextMenu.classList.add('calendar-context-menu'); document.body.appendChild(contextMenu); } var date = this._getDate(elt); var events = this.getEvents(date); for (var i = 0; i < events.length; i++) { var eventItem = document.createElement('div'); eventItem.classList.add('item'); eventItem.style.paddingLeft = '4px'; eventItem.style.boxShadow = "inset 4px 0 0 0 ".concat(events[i].color); var eventItemContent = document.createElement('div'); eventItemContent.classList.add('content'); var text = document.createElement('span'); text.classList.add('text'); text.textContent = events[i].name; eventItemContent.appendChild(text); var icon = document.createElement('span'); icon.classList.add('arrow'); icon.innerHTML = "&rsaquo;"; eventItemContent.appendChild(icon); eventItem.appendChild(eventItemContent); this._renderContextMenuItems(eventItem, this.options.contextMenuItems, events[i]); contextMenu.appendChild(eventItem); } if (contextMenu.children.length > 0) { var position = this._getElementPosition(elt); contextMenu.style.left = position.left + 25 + 'px'; contextMenu.style.right = ''; contextMenu.style.top = position.top + 25 + 'px'; contextMenu.style.display = 'block'; if (contextMenu.getBoundingClientRect().right > document.body.offsetWidth) { contextMenu.style.left = ''; contextMenu.style.right = '0'; } // Launch the position check once the whole context menu tree will be rendered setTimeout(function () { return _this4._checkContextMenuItemsPosition(); }, 0); var closeContextMenu = function closeContextMenu(event) { if (event.type !== 'click' || !contextMenu.contains(event.target)) { contextMenu.style.display = 'none'; window.removeEventListener('click', closeContextMenu); window.removeEventListener('resize', closeContextMenu); window.removeEventListener('scroll', closeContextMenu); } }; window.addEventListener('click', closeContextMenu); window.addEventListener('resize', closeContextMenu); window.addEventListener('scroll', closeContextMenu); } } }, { key: "_renderContextMenuItems", value: function _renderContextMenuItems(parent, items, evt) { var subMenu = document.createElement('div'); subMenu.classList.add('submenu'); for (var i = 0; i < items.length; i++) { if (items[i].visible === false || typeof items[i].visible === "function" && !items[i].visible(evt)) { continue; } var menuItem = document.createElement('div'); menuItem.classList.add('item'); var menuItemContent = document.createElement('div'); menuItemContent.classList.add('content'); var text = document.createElement('span'); text.classList.add('text'); text.textContent = items[i].text; menuItemContent.appendChild(text); if (items[i].click) { (function (index) { menuItemContent.addEventListener('click', function () { document.querySelector('.calendar-context-menu').style.display = 'none'; items[index].click(evt); }); })(i); } menuItem.appendChild(menuItemContent); if (items[i].items && items[i].items.length > 0) { var icon = document.createElement('span'); icon.classList.add('arrow'); icon.innerHTML = "&rsaquo;"; menuItemContent.appendChild(icon); this._renderContextMenuItems(menuItem, items[i].items, evt); } subMenu.appendChild(menuItem); } if (subMenu.children.length > 0) { parent.appendChild(subMenu); } } }, { key: "_checkContextMenuItemsPosition", value: function _checkContextMenuItemsPosition() { var menus = document.querySelectorAll('.calendar-context-menu .submenu'); menus.forEach(function (menu) { var htmlMenu = menu; htmlMenu.style.display = 'block'; htmlMenu.style.visibility = 'hidden'; }); menus.forEach(function (menu) { var htmlMenu = menu; if (htmlMenu.getBoundingClientRect().right > document.body.offsetWidth) { htmlMenu.classList.add('open-left'); } else { htmlMenu.classList.remove('open-left'); } }); menus.forEach(function (menu) { var htmlMenu = menu; htmlMenu.style.display = ''; htmlMenu.style.visibility = ''; }); } }, { key: "_getDate", value: function _getDate(elt) { var day = elt.querySelector('.day-content').textContent; var monthId = parseInt(elt.closest('.month-container').dataset.monthId); return new Date(this._startDate.getFullYear(), this._startDate.getMonth() + monthId, day); } }, { key: "_triggerEvent", value: function _triggerEvent(eventName, parameters) { var event = null; if (typeof Event === "function") { event = new Event(eventName); } else { event = document.createEvent('Event'); event.initEvent(eventName, false, false); } event.calendar = this; for (var i in parameters) { event[i] = parameters[i]; } this.element.dispatchEvent(event); return event; } }, { key: "_isDisabled", value: function _isDisabled(date) { if (this.options.minDate != null && date < this.options.minDate || this.options.maxDate != null && date > this.options.maxDate) { return true; } if (this.options.disabledWeekDays.length > 0) { for (var d = 0; d < this.options.disabledWeekDays.length; d++) { if (date.getDay() == this.options.disabledWeekDays[d]) { return true; } } } if (this.options.disabledDays.length > 0) { for (var d = 0; d < this.options.disabledDays.length; d++) { if (date.getTime() == this.options.disabledDays[d].getTime()) { return true; } } } return false; } }, { key: "_isHidden", value: function _isHidden(day) { if (this.options.hiddenWeekDays.length > 0) { for (var d = 0; d < this.options.hiddenWeekDays.length; d++) { if (day == this.options.hiddenWeekDays[d]) { return true; } } } return false; } }, { key: "_isFullYearMode", value: function _isFullYearMode() { return this._startDate.getMonth() == 0 && this.options.numberMonthsDisplayed == 12; } /** * Gets the week number for a specified date. * * @param date The specified date. */ }, { key: "getWeekNumber", value: function getWeekNumber(date) { // Algorithm from https://weeknumber.net/how-to/javascript var workingDate = new Date(date.getTime()); workingDate.setHours(0, 0, 0, 0); // Thursday in current week decides the year. workingDate.setDate(workingDate.getDate() + 3 - (workingDate.getDay() + 6) % 7); // January 4 is always in week 1. var week1 = new Date(workingDate.getFullYear(), 0, 4); // Adjust to Thursday in week 1 and count number of weeks from date to week1. return 1 + Math.round(((workingDate.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7); } /** * Gets the data source elements for a specified day.