diff --git a/amd/build/js-year-calendar.min.js b/amd/build/js-year-calendar.min.js new file mode 100644 index 0000000..f2a3a20 --- /dev/null +++ b/amd/build/js-year-calendar.min.js @@ -0,0 +1 @@ +!function(e,t){if("function"==typeof define&&define.amd)define(["exports"],t);else if("undefined"!=typeof exports)t(exports);else{var n={};t(n),e.jsYearCalendar=n}}(this,function(e){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function a(e,t){for(var n=0;nnew Date(this.options.startYear-1,11,31)&&n.classList.add("disabled");var a=document.createElement("span");a.innerHTML="‹",n.appendChild(a),t.appendChild(n);var i=document.createElement("th");i.classList.add("year-title"),i.classList.add("year-neighbor2"),i.textContent=(this.options.startYear-2).toString(),null!=this.options.minDate&&this.options.minDate>new Date(this.options.startYear-2,11,31)&&i.classList.add("disabled"),t.appendChild(i);var s=document.createElement("th");s.classList.add("year-title"),s.classList.add("year-neighbor"),s.textContent=(this.options.startYear-1).toString(),null!=this.options.minDate&&this.options.minDate>new Date(this.options.startYear-1,11,31)&&s.classList.add("disabled"),t.appendChild(s);var o=document.createElement("th");o.classList.add("year-title"),o.textContent=this.options.startYear.toString(),t.appendChild(o);var r=document.createElement("th");r.classList.add("year-title"),r.classList.add("year-neighbor"),r.textContent=(this.options.startYear+1).toString(),null!=this.options.maxDate&&this.options.maxDater.options.minDate)&&(null==r.options.maxDate||t<=r.options.maxDate)){for(var o=[],a=0;a=n&&!(r._dataSource[a].endDate=r.options.minDate)&&(null==r.options.maxDate||t<=r.options.maxDate)){for(var i=0;i=t&&a.push(o[i]);0s._rangeStart?s._rangeEnd:s._rangeStart;s._triggerEvent("selectRange",{startDate:t,endDate:n,events:s.getEventsOnRange(t,new Date(n.getFullYear(),n.getMonth(),n.getDate()+1))})}}),this._responsiveInterval&&(clearInterval(this._responsiveInterval),this._responsiveInterval=null),this._responsiveInterval=setInterval(function(){if(null!=s.element.querySelector(".month")){var e=s.element.offsetWidth,t=s.element.querySelector(".month").offsetWidth+10;s._nbCols=null,s._nbCols=6*tthis._rangeStart?this._rangeEnd:this._rangeStart;this.element.querySelectorAll(".month-container").forEach(function(e){var t=parseInt(e.dataset.monthId);a.getMonth()<=t&&i.getMonth()>=t&&e.querySelectorAll("td.day:not(.old):not(.new)").forEach(function(e){var t=n._getDate(e);a<=t&&t<=i&&(e.classList.add("range"),t.getTime()==a.getTime()&&e.classList.add("range-start"),t.getTime()==i.getTime()&&e.classList.add("range-end"))})})}}},{key:"_getElementPosition",value:function(e){for(var t=0,n=0;t+=e.offsetTop||0,n+=e.offsetLeft||0,e=e.offsetParent;);return{top:t,left:n}}},{key:"_openContextMenu",value:function(e){var t=document.querySelector(".calendar-context-menu");if(null!==t)for(t.style.display="none";t.firstChild;)t.removeChild(t.firstChild);else(t=document.createElement("div")).classList.add("calendar-context-menu"),document.body.appendChild(t);for(var n=this._getDate(e),a=this.getEvents(n),i=0;ithis.options.maxDate)return!0;if(0=e&&n.push(this._dataSource[a]);return n}},{key:"isThereFreeSlot",value:function(t){var n=this,e=1t}):!1===e?!a.some(function(e){return!n.options.alwaysHalfDay&&!e.startHalfDay||e.startDate 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, Calendar); + + _defineProperty(this, "element", void 0); + + _defineProperty(this, "options", 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); + + 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); + + this.setYear(this.options.startYear); + } + + _createClass(Calendar, [{ + key: "_initializeOptions", + value: function _initializeOptions(opt) { + if (opt == null) { + opt = {}; + } + + this.options = { + startYear: !isNaN(parseInt(opt.startYear)) ? parseInt(opt.startYear) : new Date().getFullYear(), + 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.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; + + if (getDataSource.length == 2) { + // 2 parameters, means callback method + getDataSource(this.options.startYear, callback); + } else { + // 1 parameter, means synchronous or promise method + var result = getDataSource(this.options.startYear); + + if (result instanceof Array) { + callback(result); + } else { + 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 = 'block'; + months.style.transition = 'opacity 0.5s'; + setTimeout(function () { + months.style.opacity = '1'; + setTimeout(function () { + return months.style.transition = ''; + }, 500); + }, 0); + + this._triggerEvent('renderEnd', { + currentYear: this.options.startYear + }); + } + } + }, { + key: "_renderHeader", + value: function _renderHeader() { + var header = document.createElement('div'); + header.classList.add('calendar-header'); + var headerTable = document.createElement('table'); + var prevDiv = document.createElement('th'); + prevDiv.classList.add('prev'); + + if (this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 1, 11, 31)) { + prevDiv.classList.add('disabled'); + } + + var prevIcon = document.createElement('span'); + prevIcon.innerHTML = "‹"; + prevDiv.appendChild(prevIcon); + headerTable.appendChild(prevDiv); + var prev2YearDiv = document.createElement('th'); + prev2YearDiv.classList.add('year-title'); + prev2YearDiv.classList.add('year-neighbor2'); + prev2YearDiv.textContent = (this.options.startYear - 2).toString(); + + if (this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 2, 11, 31)) { + prev2YearDiv.classList.add('disabled'); + } + + headerTable.appendChild(prev2YearDiv); + var prevYearDiv = document.createElement('th'); + prevYearDiv.classList.add('year-title'); + prevYearDiv.classList.add('year-neighbor'); + prevYearDiv.textContent = (this.options.startYear - 1).toString(); + + if (this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 1, 11, 31)) { + prevYearDiv.classList.add('disabled'); + } + + headerTable.appendChild(prevYearDiv); + var yearDiv = document.createElement('th'); + yearDiv.classList.add('year-title'); + yearDiv.textContent = this.options.startYear.toString(); + headerTable.appendChild(yearDiv); + var nextYearDiv = document.createElement('th'); + nextYearDiv.classList.add('year-title'); + nextYearDiv.classList.add('year-neighbor'); + nextYearDiv.textContent = (this.options.startYear + 1).toString(); + + if (this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 1, 0, 1)) { + nextYearDiv.classList.add('disabled'); + } + + headerTable.appendChild(nextYearDiv); + var next2YearDiv = document.createElement('th'); + next2YearDiv.classList.add('year-title'); + next2YearDiv.classList.add('year-neighbor2'); + next2YearDiv.textContent = (this.options.startYear + 2).toString(); + + if (this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 2, 0, 1)) { + next2YearDiv.classList.add('disabled'); + } + + headerTable.appendChild(next2YearDiv); + var nextDiv = document.createElement('th'); + nextDiv.classList.add('next'); + + if (this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 1, 0, 1)) { + nextDiv.classList.add('disabled'); + } + + var nextIcon = document.createElement('span'); + nextIcon.innerHTML = "›"; + 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'); + + for (var m = 0; m < 12; 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 firstDate = new Date(this.options.startYear, m, 1); + 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[m]; + 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.options.weekStart ? this.options.weekStart : Calendar.locales[this.options.language].weekStart; + 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(firstDate.getTime()); + var lastDate = new Date(this.options.startYear, m + 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 < firstDate) { + 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); + } + + 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 firstDate = new Date(_this.options.startYear, monthId, 1); + var lastDate = new Date(_this.options.startYear, monthId + 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(_this.options.startYear, monthId, parseInt(day.textContent)); + var nextDate = new Date(_this.options.startYear, monthId, 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.setYear(_this2.options.startYear - 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.setYear(_this2.options.startYear + 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._nbCols = 2; + } else if (monthSize * 4 < calendarSize) { + _this2._nbCols = 3; + } else if (monthSize * 3 < calendarSize) { + _this2._nbCols = 4; + } else if (monthSize * 2 < calendarSize) { + _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); + + if (minDate.getMonth() <= monthId && maxDate.getMonth() >= monthId) { + 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 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.borderLeft = "4px solid ".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 = "›"; + 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.top = position.top + 25 + 'px'; + contextMenu.style.display = 'block'; + window.addEventListener('click', function (e) { + if (!contextMenu.contains(e.target)) { + contextMenu.style.display = 'none'; + } + }, { + once: true + }); + } + } + }, { + 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 = "›"; + menuItemContent.appendChild(icon); + + this._renderContextMenuItems(menuItem, items[i].items, evt); + } + + subMenu.appendChild(menuItem); + } + + if (subMenu.children.length > 0) { + parent.appendChild(subMenu); + } + } + }, { + key: "_getDate", + value: function _getDate(elt) { + var day = elt.querySelector('.day-content').textContent; + var month = elt.closest('.month-container').dataset.monthId; + var year = this.options.startYear; + return new Date(year, month, 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; + } + /** + * 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. + * + * @param date The specified day. + */ + + }, { + key: "getEvents", + value: function getEvents(date) { + return this.getEventsOnRange(date, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)); + } + /** + * Gets the data source elements for a specified range of days. + * + * @param startDate The beginning of the day range (inclusive). + * @param endDate The end of the day range (non inclusive). + */ + + }, { + key: "getEventsOnRange", + value: function getEventsOnRange(startDate, endDate) { + var events = []; + + if (this._dataSource && startDate && endDate) { + for (var i = 0; i < this._dataSource.length; i++) { + if (this._dataSource[i].startDate < endDate && this._dataSource[i].endDate >= startDate) { + events.push(this._dataSource[i]); + } + } + } + + return events; + } + /** + * Check if there is no event on the first part, last part or on the whole specified day. + * + * @param date The specified day. + * @param after Whether to check for a free slot on the first part (if `false`) or the last part (if `true`) of the day. If `null`, this will check on the whole day. + * + * Usefull only if using the `alwaysHalfDay` option of the calendar, or the `startHalfDay` or `endHalfDay` option of the datasource. + */ + + }, { + key: "isThereFreeSlot", + value: function isThereFreeSlot(date) { + var _this4 = this; + + var after = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var events = this.getEvents(date); + + if (after === true) { + return !events.some(function (evt) { + return !_this4.options.alwaysHalfDay && !evt.endHalfDay || evt.endDate > date; + }); + } else if (after === false) { + return !events.some(function (evt) { + return !_this4.options.alwaysHalfDay && !evt.startHalfDay || evt.startDate < date; + }); + } else { + return this.isThereFreeSlot(date, false) || this.isThereFreeSlot(date, true); + } + } + /** + * Gets the year displayed on the calendar. + */ + + }, { + key: "getYear", + value: function getYear() { + return this.options.startYear; + } + /** + * Sets the year displayed on the calendar. + * + * @param year The year to displayed on the calendar. + */ + + }, { + key: "setYear", + value: function setYear(year) { + var _this5 = this; + + var parsedYear = parseInt(year); + + if (!isNaN(parsedYear)) { + this.options.startYear = parsedYear; // Clear the calendar (faster method) + + while (this.element.firstChild) { + this.element.removeChild(this.element.firstChild); + } + + if (this.options.displayHeader) { + this._renderHeader(); + } + + var eventResult = this._triggerEvent('yearChanged', { + currentYear: this.options.startYear, + preventRendering: false + }); + + if (typeof this.options.dataSource === "function") { + this.render(true); + + this._fetchDataSource(function (dataSource) { + _this5._dataSource = dataSource; + + _this5._initializeDatasourceColors(); + + _this5.render(false); + }); + } else { + if (!eventResult.preventRendering) { + this.render(); + } + } + } + } + /** + * Gets the minimum date of the calendar. + */ + + }, { + key: "getMinDate", + value: function getMinDate() { + return this.options.minDate; + } + /** + * Sets the minimum date of the calendar. + * + * This method causes a refresh of the calendar. + * + * @param minDate The minimum date to set. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setMinDate", + value: function setMinDate(date) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (date instanceof Date || date === null) { + this.options.minDate = date; + + if (!preventRendering) { + this.render(); + } + } + } + /** + * Gets the maximum date of the calendar. + */ + + }, { + key: "getMaxDate", + value: function getMaxDate() { + return this.options.maxDate; + } + /** + * Sets the maximum date of the calendar. + * + * This method causes a refresh of the calendar. + * + * @param maxDate The maximum date to set. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setMaxDate", + value: function setMaxDate(date) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (date instanceof Date || date === null) { + this.options.maxDate = date; + + if (!preventRendering) { + this.render(); + } + } + } + /** + * Gets the current style used for displaying data source. + */ + + }, { + key: "getStyle", + value: function getStyle() { + return this.options.style; + } + /** + * Sets the style to use for displaying data source. + * + * This method causes a refresh of the calendar. + * + * @param style The style to use for displaying data source ("background", "border" or "custom"). + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setStyle", + value: function setStyle(style) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.style = style == 'background' || style == 'border' || style == 'custom' ? style : 'border'; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets a value indicating whether the user can select a range which overlapping an other element present in the datasource. + */ + + }, { + key: "getAllowOverlap", + value: function getAllowOverlap() { + return this.options.allowOverlap; + } + /** + * Sets a value indicating whether the user can select a range which overlapping an other element present in the datasource. + * + * @param allowOverlap Indicates whether the user can select a range which overlapping an other element present in the datasource. + */ + + }, { + key: "setAllowOverlap", + value: function setAllowOverlap(allowOverlap) { + this.options.allowOverlap = allowOverlap; + } + /** + * Gets a value indicating whether the weeks number are displayed. + */ + + }, { + key: "getDisplayWeekNumber", + value: function getDisplayWeekNumber() { + return this.options.displayWeekNumber; + } + /** + * Sets a value indicating whether the weeks number are displayed. + * + * This method causes a refresh of the calendar. + * + * @param displayWeekNumber Indicates whether the weeks number are displayed. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setDisplayWeekNumber", + value: function setDisplayWeekNumber(displayWeekNumber) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.displayWeekNumber = displayWeekNumber; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets a value indicating whether the calendar header is displayed. + */ + + }, { + key: "getDisplayHeader", + value: function getDisplayHeader() { + return this.options.displayHeader; + } + /** + * Sets a value indicating whether the calendar header is displayed. + * + * This method causes a refresh of the calendar. + * + * @param displayHeader Indicates whether the calendar header is displayed. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setDisplayHeader", + value: function setDisplayHeader(displayHeader) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.displayHeader = displayHeader; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets a value indicating whether the data source must be rendered on disabled days. + */ + + }, { + key: "getDisplayDisabledDataSource", + value: function getDisplayDisabledDataSource() { + return this.options.displayDisabledDataSource; + } + /** + * Sets a value indicating whether the data source must be rendered on disabled days. + * + * This method causes a refresh of the calendar. + * + * @param displayDisabledDataSource Indicates whether the data source must be rendered on disabled days. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setDisplayDisabledDataSource", + value: function setDisplayDisabledDataSource(displayDisabledDataSource) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.displayDisabledDataSource = displayDisabledDataSource; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets a value indicating whether the beginning and the end of each range should be displayed as half selected day. + */ + + }, { + key: "getAlwaysHalfDay", + value: function getAlwaysHalfDay() { + return this.options.alwaysHalfDay; + } + /** + * Sets a value indicating whether the beginning and the end of each range should be displayed as half selected day. + * + * This method causes a refresh of the calendar. + * + * @param alwaysHalfDay Indicates whether the beginning and the end of each range should be displayed as half selected day. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setAlwaysHalfDay", + value: function setAlwaysHalfDay(alwaysHalfDay) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.alwaysHalfDay = alwaysHalfDay; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets a value indicating whether the user can make range selection. + */ + + }, { + key: "getEnableRangeSelection", + value: function getEnableRangeSelection() { + return this.options.enableRangeSelection; + } + /** + * Sets a value indicating whether the user can make range selection. + * + * This method causes a refresh of the calendar. + * + * @param enableRangeSelection Indicates whether the user can make range selection. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setEnableRangeSelection", + value: function setEnableRangeSelection(enableRangeSelection) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.enableRangeSelection = enableRangeSelection; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets the disabled days. + */ + + }, { + key: "getDisabledDays", + value: function getDisabledDays() { + return this.options.disabledDays; + } + /** + * Sets the disabled days. + * + * This method causes a refresh of the calendar. + * + * @param disableDays The disabled days to set. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setDisabledDays", + value: function setDisabledDays(disabledDays) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.disabledDays = disabledDays instanceof Array ? disabledDays : []; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets the disabled days of the week. + */ + + }, { + key: "getDisabledWeekDays", + value: function getDisabledWeekDays() { + return this.options.disabledWeekDays; + } + /** + * Sets the disabled days of the week. + * + * This method causes a refresh of the calendar. + * + * @param disabledWeekDays The disabled days of the week to set. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setDisabledWeekDays", + value: function setDisabledWeekDays(disabledWeekDays) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.disabledWeekDays = disabledWeekDays instanceof Array ? disabledWeekDays : []; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets the hidden days of the week. + */ + + }, { + key: "getHiddenWeekDays", + value: function getHiddenWeekDays() { + return this.options.hiddenWeekDays; + } + /** + * Sets the hidden days of the week. + * + * This method causes a refresh of the calendar. + * + * @param hiddenWeekDays The hidden days of the week to set. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setHiddenWeekDays", + value: function setHiddenWeekDays(hiddenWeekDays) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.hiddenWeekDays = hiddenWeekDays instanceof Array ? hiddenWeekDays : []; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets a value indicating whether the beginning and the end of each range should be displayed as rounded cells. + */ + + }, { + key: "getRoundRangeLimits", + value: function getRoundRangeLimits() { + return this.options.roundRangeLimits; + } + /** + * Sets a value indicating whether the beginning and the end of each range should be displayed as rounded cells. + * + * This method causes a refresh of the calendar. + * + * @param roundRangeLimits Indicates whether the beginning and the end of each range should be displayed as rounded cells. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setRoundRangeLimits", + value: function setRoundRangeLimits(roundRangeLimits) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.roundRangeLimits = roundRangeLimits; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets a value indicating whether the default context menu must be displayed when right clicking on a day. + */ + + }, { + key: "getEnableContextMenu", + value: function getEnableContextMenu() { + return this.options.enableContextMenu; + } + /** + * Sets a value indicating whether the default context menu must be displayed when right clicking on a day. + * + * This method causes a refresh of the calendar. + * + * @param enableContextMenu Indicates whether the default context menu must be displayed when right clicking on a day. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setEnableContextMenu", + value: function setEnableContextMenu(enableContextMenu) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.enableContextMenu = enableContextMenu; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets the context menu items. + */ + + }, { + key: "getContextMenuItems", + value: function getContextMenuItems() { + return this.options.contextMenuItems; + } + /** + * Sets new context menu items. + * + * This method causes a refresh of the calendar. + * + * @param contextMenuItems The new context menu items. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setContextMenuItems", + value: function setContextMenuItems(contextMenuItems) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.contextMenuItems = contextMenuItems instanceof Array ? contextMenuItems : []; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets the custom day renderer. + */ + + }, { + key: "getCustomDayRenderer", + value: function getCustomDayRenderer() { + return this.options.customDayRenderer; + } + /** + * Sets the custom day renderer. + * + * This method causes a refresh of the calendar. + * + * @param handler The function used to render the days. This function is called during render for each day. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setCustomDayRenderer", + value: function setCustomDayRenderer(customDayRenderer) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.customDayRenderer = typeof customDayRenderer === "function" ? customDayRenderer : null; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets the custom data source renderer. + */ + + }, { + key: "getCustomDataSourceRenderer", + value: function getCustomDataSourceRenderer() { + return this.options.customDataSourceRenderer; + } + /** + * Sets the custom data source renderer. Works only with the style set to "custom". + * + * This method causes a refresh of the calendar. + * + * @param handler The function used to render the data source. This function is called during render for each day containing at least one event. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setCustomDataSourceRenderer", + value: function setCustomDataSourceRenderer(customDataSourceRenderer) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.customDataSourceRenderer = typeof customDataSourceRenderer === "function" ? customDataSourceRenderer : null; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets the language used for calendar rendering. + */ + + }, { + key: "getLanguage", + value: function getLanguage() { + return this.options.language; + } + /** + * Sets the language used for calendar rendering. + * + * This method causes a refresh of the calendar. + * + * @param language The language to use for calendar redering. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setLanguage", + value: function setLanguage(language) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (language != null && Calendar.locales[language] != null) { + this.options.language = language; + + if (!preventRendering) { + this.render(); + } + } + } + /** + * Gets the current data source. + */ + + }, { + key: "getDataSource", + value: function getDataSource() { + return this.options.dataSource; + } + /** + * Sets a new data source. + * + * This method causes a refresh of the calendar. + * + * @param dataSource The new data source. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setDataSource", + value: function setDataSource(dataSource) { + var _this6 = this; + + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.dataSource = dataSource instanceof Array || typeof dataSource === "function" ? dataSource : []; + + if (typeof this.options.dataSource === "function") { + this.render(true); + + this._fetchDataSource(function (dataSource) { + _this6._dataSource = dataSource; + + _this6._initializeDatasourceColors(); + + _this6.render(false); + }); + } else { + this._dataSource = this.options.dataSource; + + this._initializeDatasourceColors(); + + if (!preventRendering) { + this.render(); + } + } + } + /** + * Gets the starting day of the week. + */ + + }, { + key: "getWeekStart", + value: function getWeekStart() { + return this.options.weekStart ? this.options.weekStart : Calendar.locales[this.options.language].weekStart; + } + /** + * Sets the starting day of the week. + * + * This method causes a refresh of the calendar. + * + * @param weekStart The starting day of the week. This option overrides the parameter define in the language file. + * @param preventRedering Indicates whether the rendering should be prevented after the property update. + */ + + }, { + key: "setWeekStart", + value: function setWeekStart(weekStart) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + this.options.weekStart = !isNaN(parseInt(weekStart)) ? parseInt(weekStart) : null; + + if (!preventRendering) { + this.render(); + } + } + /** + * Gets the loading template. + */ + + }, { + key: "getLoadingTemplate", + value: function getLoadingTemplate() { + return this.options.loadingTemplate; + } + /** + * Sets the loading template. + * + * @param loadingTemplate The loading template. + */ + + }, { + key: "setLoadingTemplate", + value: function setLoadingTemplate(loadingTemplate) { + this.options.loadingTemplate = typeof loadingTemplate === "string" || loadingTemplate instanceof HTMLElement ? loadingTemplate : null; + } + /** + * + * Add a new element to the data source. + * + * This method causes a refresh of the calendar. + * + * @param element The element to add. + * @param preventRendering Indicates whether the calendar shouldn't be refreshed once the event added. + */ + + }, { + key: "addEvent", + value: function addEvent(evt) { + var preventRendering = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + this._dataSource.push(evt); + + if (!preventRendering) { + this.render(); + } + } + }]); + + return Calendar; + }(); + + _exports.default = Calendar; + + _defineProperty(Calendar, "locales", { + en: { + days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], + months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + weekShort: 'W', + weekStart: 0 + } + }); + + _defineProperty(Calendar, "colors", ['#2C8FC9', '#9CB703', '#F5BB00', '#FF4A32', '#B56CE2', '#45A597']); + + if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object") { + window.Calendar = Calendar; + document.addEventListener("DOMContentLoaded", function () { + document.querySelectorAll('[data-provide="calendar"]').forEach(function (element) { + return new Calendar(element); + }); + }); + } +}); \ No newline at end of file diff --git a/amd/src/teste.js b/amd/src/teste.js new file mode 100644 index 0000000..73e6047 --- /dev/null +++ b/amd/src/teste.js @@ -0,0 +1,28 @@ +define(['jquery', 'enrol_apply/js-year-calendar', 'core/log', +], function($, calendar, log) { + + "use strict"; // jshint ;_; + log.debug('TesteMGBF inicializado'); + + return { + init: function() { + //$("
").insertAfter("div.generalbox"); + Calendar.locales.pt = { + days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"], + daysShort: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"], + daysMin: ["Do", "Se", "Te", "Qu", "Qu", "Se", "Sa"], + months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"], + monthsShort: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"], + weekShort: 'S', + weekStart:0 + }; + var calendar = new Calendar("#calendar", { + language: 'pt', + style: 'border' + }); + let dataSource = []; + calendar.setDataSource(dataSource); + + } + } +}); \ No newline at end of file diff --git a/apply_form.php b/apply_form.php index 0cb21a3..6c9f0df 100644 --- a/apply_form.php +++ b/apply_form.php @@ -24,6 +24,8 @@ defined('MOODLE_INTERNAL') || die(); +//require_once('./lib.php'); + require_once($CFG->libdir.'/formslib.php'); require_once($CFG->dirroot.'/user/editlib.php'); require_once($CFG->dirroot.'/user/profile/lib.php'); @@ -41,6 +43,52 @@ class enrol_apply_apply_form extends moodleform { return $formid; } + public function montaStringCurso($mform) { + // // INICIO MGBF + // $strInfoCurso = 'Um texto qualquer'; + + // $campo = obtemCampoCustomizadoCurso($instance->courseid, 'sf_restringir_matricula'); + // $strInfoCurso .= $campo . $USER->profile['sf_cargo_chefia']; + + // profile_load_custom_fields($USER); + // $mform->addElement('html', '

' . $strInfoCurso . '

'); + + // global $PAGE; + // $PAGE->requires->css('/enrol/apply/css/js-year-calendar.min.css', true); + // $PAGE->requires->js_call_amd('enrol_apply/teste', 'init'); + // $mform->addElement('html', "
"); + // // FIM MGBF + + $resultado = ''; + + // Verifica se o curso é restrito a setores do Senado. + if(true) { // restrito + $mform->addElement('html', '
Curso restrito
'); + } else { + $mform->addElement('html', '
'.$count.' '.get_string('maxenrolled_tip_1', 'enrol_apply').' '.$instance->customint3.' '.get_string('maxenrolled_tip_2', 'enrol_apply').'
'); + } + + // Verifica se o curso é determinadas funções do Senado. + if(true) { // restrito + $mform->addElement('html', '
Curso restrito
'); + } else { + $mform->addElement('html', '
'.$count.' '.get_string('maxenrolled_tip_1', 'enrol_apply').' '.$instance->customint3.' '.get_string('maxenrolled_tip_2', 'enrol_apply').'
'); + } + + // Verifica se o curso é determinados tipos de vínculo do Senado. + if(true) { // restrito + $mform->addElement('html', '
Curso restrito
'); + } else { + $mform->addElement('html', '
'.$count.' '.get_string('maxenrolled_tip_1', 'enrol_apply').' '.$instance->customint3.' '.get_string('maxenrolled_tip_2', 'enrol_apply').'
'); + } + + // Informa valor do custo por aluno + + // Informa que servidor terá que assinar termo de responsabilidade + + return true; + } + public function definition() { global $USER, $DB; @@ -59,6 +107,9 @@ class enrol_apply_apply_form extends moodleform { } } + // Monta mensagens de acordo com atributos do curso e/ou aluno + $this->montaStringCurso($mform); + $mform->addElement('html', '

'.$instance->customtext1.'

'); $comment_title = get_string('comment', 'enrol_apply'); if($instance->customtext2 != ''){ @@ -91,4 +142,5 @@ class enrol_apply_apply_form extends moodleform { $mform->setDefault('instance', $instance->id); } + } diff --git a/css/js-year-calendar.min.css b/css/js-year-calendar.min.css new file mode 100644 index 0000000..0200317 --- /dev/null +++ b/css/js-year-calendar.min.css @@ -0,0 +1 @@ +.calendar{padding:4px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;direction:ltr;overflow-x:hidden;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.calendar:after{clear:both;content:"";display:block}.calendar .calendar-rtl{direction:rtl}.calendar .calendar-rtl .calendar-rtl table tr td span{float:right}.calendar table{margin:auto;border-spacing:0}.calendar table td,.calendar table th{text-align:center;width:20px;height:20px;border:none;padding:4px 5px;font-size:12px}.calendar .calendar-header{width:100%;margin-bottom:20px;border:1px solid #ddd}.calendar .calendar-header table{width:100%}.calendar .calendar-header table th{font-size:22px;padding:5px 10px;cursor:pointer}.calendar .calendar-header table th:hover{background:#eee}.calendar .calendar-header table th.disabled,.calendar .calendar-header table th.disabled:hover{background:0 0;cursor:default;color:#fff}.calendar .calendar-header table th.next,.calendar .calendar-header table th.prev{width:20px}.calendar .calendar-header .year-title{font-weight:700;text-align:center;height:20px;width:auto}.calendar .calendar-header .year-neighbor{opacity:.4}@media (max-width:991px){.calendar .calendar-header .year-neighbor{display:none}}.calendar .calendar-header .year-neighbor2{opacity:.2}@media (max-width:767px){.calendar .calendar-header .year-neighbor2{display:none}}.calendar .months-container{width:100%;display:none}.calendar .months-container .month-container{float:left;text-align:center;height:200px;padding:0}.calendar .months-container .month-container.month-2{width:16.66666667%}.calendar .months-container .month-container.month-3{width:25%}.calendar .months-container .month-container.month-4{width:33.33333333%}.calendar .months-container .month-container.month-6{width:50%}.calendar .months-container .month-container.month-12{width:100%}.calendar table.month th.month-title{font-size:16px;padding-bottom:5px}.calendar table.month th.day-header{font-size:14px}.calendar table.month tr td,.calendar table.month tr th{padding:0}.calendar table.month tr td.hidden,.calendar table.month tr th.hidden{display:none}.calendar table.month td.week-number{cursor:default;font-weight:700;border-right:1px solid #eee;padding:5px}.calendar table.month td.day.round-left{-webkit-border-radius:8px 0 0 8px;-moz-border-radius:8px 0 0 8px;border-radius:8px 0 0 8px}.calendar table.month td.day.round-right{webkit-border-radius:0 8px 8px 0;-moz-border-radius:0 8px 8px 0;border-radius:0 8px 8px 0}.calendar table.month td.day .day-content{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;padding:5px 6px}.calendar table.month td.new,.calendar table.month td.new:hover,.calendar table.month td.old,.calendar table.month td.old:hover{background:0 0;cursor:default}.calendar table.month td.disabled,.calendar table.month td.disabled:hover{color:#ddd}.calendar table.month td.disabled .day-content:hover,.calendar table.month td.disabled:hover .day-content:hover{background:0 0;cursor:default}.calendar table.month td.range .day-content{background:rgba(0,0,0,.2);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.calendar table.month td.range.range-start .day-content{border-top-left-radius:4px;border-bottom-left-radius:4px}.calendar table.month td.range.range-end .day-content{border-top-right-radius:4px;border-bottom-right-radius:4px}.calendar .calendar-loading-container{position:relative;text-align:center;min-height:200px}.calendar .calendar-loading-container .calendar-loading{position:absolute;top:50%;left:50%;transform:translateX(-50%) translateY(-50%)}.calendar .calendar-spinner{margin:20px auto;width:80px;text-align:center}.calendar .calendar-spinner>div{width:16px;height:16px;margin:5px;background-color:#333;border-radius:100%;display:inline-block;-webkit-animation:sk-bouncedelay 1s infinite ease-in-out both;animation:sk-bouncedelay 1s infinite ease-in-out both}.calendar .calendar-spinner>div.bounce1{-webkit-animation-delay:-.32s;animation-delay:-.32s}.calendar .calendar-spinner>div.bounce2{-webkit-animation-delay:-.16s;animation-delay:-.16s}.calendar-context-menu,.calendar-context-menu .submenu{border:1px solid #ddd;background-color:#fff;box-shadow:2px 2px 5px rgba(0,0,0,.2);-webkit-box-shadow:2px 2px 5px rgba(0,0,0,.2);position:absolute;display:none}.calendar-context-menu .item{position:relative}.calendar-context-menu .item .content{padding:5px 10px;cursor:pointer;display:table;width:100%;white-space:nowrap}.calendar-context-menu .item .content:hover{background:#eee}.calendar-context-menu .item .content .text{display:table-cell}.calendar-context-menu .item .content .arrow{display:table-cell;padding-left:10px;text-align:right}.calendar-context-menu .item .submenu{left:100%;top:-1px}.calendar-context-menu .item:hover>.submenu{display:block}.table-striped .calendar table.month tr td,.table-striped .calendar table.month tr th{background-color:transparent}table.month td.day .day-content:hover{background:rgba(0,0,0,.2);cursor:pointer}@-webkit-keyframes sk-bouncedelay{0%,100%,80%{-webkit-transform:scale(0)}40%{-webkit-transform:scale(1)}}@keyframes sk-bouncedelay{0%,100%,80%{-webkit-transform:scale(0);transform:scale(0)}40%{-webkit-transform:scale(1);transform:scale(1)}} \ No newline at end of file diff --git a/lib.php b/lib.php index fe8b2a4..9f56966 100644 --- a/lib.php +++ b/lib.php @@ -25,6 +25,7 @@ /** The user is put onto a waiting list and therefore the enrolment not active (used in user_enrolments->status) */ define('ENROL_APPLY_USER_WAIT', 2); + class enrol_apply_plugin extends enrol_plugin { /** @@ -128,6 +129,8 @@ class enrol_apply_plugin extends enrol_plugin { // retorna true se inseriu ou se já tinha, ou falso em caso de erro ou timeout } + // Chamado quando usuário solicita inscrição em um curso + // e também depois da confirmação da inscrição public function enrol_page_hook(stdClass $instance) { global $CFG, $OUTPUT, $SESSION, $USER, $DB; @@ -136,12 +139,33 @@ class enrol_apply_plugin extends enrol_plugin { return null; } + // Assegura que método de inscrição está ativo $allowapply = $this->allow_apply($instance); if ($allowapply !== true) { return '
' . $allowapply . '
'; } + // Testa se foi chamado após a inscrição if ($DB->record_exists('user_enrolments', array('userid' => $USER->id, 'enrolid' => $instance->id))) { + + // Já está inserido na tabela + // Devo pegar quantitativo do curso e posição real, dentre os já aprovados + // Se estiver entre as vagas, já marca como matriculado e envia e-mail + // Senão, informa que está na fila e envia e-mail + + /* + PROC insere assinatura sigad + + Você foi pre-matriculado no curso XXXX. + A partir de agora, você tem 48 horas para assinar o termo de responsabilidade + no SIGAD, de modo a assegurar sua vaga. + + + + Caso não faça a assinatura dentro desse período, perderá direito a vaga, que + poderá ser ocupada por outro interessado. + */ + // TODO: incluir aqui chamada para WS que atribui assinatura a documento no SIGAD // analisar resultado: se timeout ou erro, assinatura deve ser inserida manualmente // DO contrário já mostra link para usuário assinar. @@ -157,6 +181,8 @@ class enrol_apply_plugin extends enrol_plugin { return $textoassinatura . ' '. $OUTPUT->notification(get_string('notification', 'enrol_apply'), 'notifysuccess'); } + // Se deseja se inscrever, verifica se já não atingiu limite de inscritos + // FIXME evidenciar que é pré-inscrição, ver como tratar esse limite! if ($instance->customint3 > 0) { // Max enrol limit specified. $count = $DB->count_records('user_enrolments', array('enrolid' => $instance->id)); @@ -166,13 +192,15 @@ class enrol_apply_plugin extends enrol_plugin { } } - - - + // Exibe formulário para matrícula require_once("$CFG->dirroot/enrol/apply/apply_form.php"); $form = new enrol_apply_apply_form(null, $instance); + // Se formulário foi submetido, efetiva a matrícula e + // redireciona para página do curso + // FIXME não redirecionar ainda + // FIXME definir datas de enrol if ($data = $form->get_data()) { // Only process when form submission is for this instance (multi instance support). if ($data->instance == $instance->id) { @@ -192,20 +220,25 @@ class enrol_apply_plugin extends enrol_plugin { $applicationinfo->comment = $data->applydescription; $DB->insert_record('enrol_apply_applicationinfo', $applicationinfo, false); + // FIXME verificar se essa notificação é apropriada $this->send_application_notification($instance, $USER->id, $data); + // FIXME verificar redirecionamento redirect("$CFG->wwwroot/course/view.php?id=$instance->courseid"); } } + // Exibe informações sobre público alvo do curso + // e botões para matrícula + // Em caso de mais de uma instância, todas aparecem aqui + // FIXME definir formato $output = $form->render(); - profile_load_custom_fields($USER); - $campo = obtemCampoCustomizadoCurso($instance->courseid, 'sf_restringir_matricula'); - - return $OUTPUT->box('Teste ' . $campo . $USER->profile['sf_cargo_chefia']) . $OUTPUT->box($output); + return $OUTPUT->box($OUTPUT->box($output)); } + // Monta os botões de ação que serão exibidos para este método de inscrição + // na página de métodos de inscrição do curso (/enrol/instances.php?id=IDCURSO) public function get_action_icons(stdClass $instance) { global $OUTPUT; @@ -215,7 +248,7 @@ class enrol_apply_plugin extends enrol_plugin { $context = context_course::instance($instance->courseid); $icons = array(); - + if (has_capability('enrol/apply:config', $context)) { $editlink = new moodle_url("/enrol/apply/edit.php", array('courseid' => $instance->courseid, 'id' => $instance->id)); $icons[] = $OUTPUT->action_icon($editlink, new pix_icon( @@ -286,11 +319,12 @@ class enrol_apply_plugin extends enrol_plugin { public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) { $actions = array(); + //return $actions; $context = $manager->get_context(); $instance = $ue->enrolmentinstance; $params = $manager->get_moodlepage()->url->params(); $params['ue'] = $ue->id; - if ($this->allow_unenrol_user($instance, $ue) && has_capability("enrol/apply:unenrol", $context)) { + if ( ($this->allow_unenrol_user($instance, $ue)) && has_capability("enrol/apply:unenrol", $context)) { $url = new moodle_url('/enrol/unenroluser.php', $params); $actions[] = new user_enrolment_action( new pix_icon('t/delete', ''), diff --git a/manage_table.php b/manage_table.php index 9e5eecc..c48b74e 100644 --- a/manage_table.php +++ b/manage_table.php @@ -86,6 +86,6 @@ class enrol_apply_manage_table extends table_sql { } public function col_applydate($row) { - return date("Y-m-d", $row->applydate); + return date("d/m/Y H:i:s", $row->applydate); } }