paulo@103: /* ========================================================= paulo@103: * Bootstrap year calendar v1.1.0 paulo@103: * Repo: https://github.com/Paul-DS/bootstrap-year-calendar paulo@103: * ========================================================= paulo@103: * Created by Paul David-Sivelle paulo@103: * paulo@103: * Licensed under the Apache License, Version 2.0 (the "License"); paulo@103: * you may not use this file except in compliance with the License. paulo@103: * You may obtain a copy of the License at paulo@103: * paulo@103: * http://www.apache.org/licenses/LICENSE-2.0 paulo@103: * paulo@103: * Unless required by applicable law or agreed to in writing, software paulo@103: * distributed under the License is distributed on an "AS IS" BASIS, paulo@103: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. paulo@103: * See the License for the specific language governing permissions and paulo@103: * limitations under the License. paulo@103: * ========================================================= */ paulo@103: paulo@103: (function($) { paulo@103: var Calendar = function(element, options) { paulo@103: this.element = element; paulo@103: this.element.addClass('calendar'); paulo@103: paulo@103: this._initializeEvents(options); paulo@103: this._initializeOptions(options); paulo@103: this._render(); paulo@103: }; paulo@103: paulo@103: Calendar.prototype = { paulo@103: constructor: Calendar, paulo@103: _initializeOptions: function(opt) { paulo@103: if(opt == null) { paulo@103: opt = []; paulo@103: } paulo@103: paulo@103: this.options = { paulo@103: startYear: !isNaN(parseInt(opt.startYear)) ? parseInt(opt.startYear) : new Date().getFullYear(), paulo@103: minDate: opt.minDate instanceof Date ? opt.minDate : null, paulo@103: maxDate: opt.maxDate instanceof Date ? opt.maxDate : null, paulo@103: language: (opt.language != null && dates[opt.language] != null) ? opt.language : 'en', paulo@103: allowOverlap: opt.allowOverlap != null ? opt.allowOverlap : true, paulo@103: displayWeekNumber: opt.displayWeekNumber != null ? opt.displayWeekNumber : false, paulo@103: alwaysHalfDay: opt.alwaysHalfDay != null ? opt.alwaysHalfDay : false, paulo@103: enableRangeSelection: opt.enableRangeSelection != null ? opt.enableRangeSelection : false, paulo@103: disabledDays: opt.disabledDays instanceof Array ? opt.disabledDays : [], paulo@103: roundRangeLimits: opt.roundRangeLimits != null ? opt.roundRangeLimits : false, paulo@103: dataSource: opt.dataSource instanceof Array != null ? opt.dataSource : [], paulo@103: style: opt.style == 'background' || opt.style == 'border' || opt.style == 'custom' ? opt.style : 'border', paulo@103: enableContextMenu: opt.enableContextMenu != null ? opt.enableContextMenu : false, paulo@103: contextMenuItems: opt.contextMenuItems instanceof Array ? opt.contextMenuItems : [], paulo@103: customDayRenderer : $.isFunction(opt.customDayRenderer) ? opt.customDayRenderer : null, paulo@103: customDataSourceRenderer : $.isFunction(opt.customDataSourceRenderer) ? opt.customDataSourceRenderer : null paulo@103: }; paulo@103: paulo@103: this._initializeDatasourceColors(); paulo@103: }, paulo@103: _initializeEvents: function(opt) { paulo@103: if(opt == null) { paulo@103: opt = []; paulo@103: } paulo@103: paulo@103: if(opt.renderEnd) { this.element.bind('renderEnd', opt.renderEnd); } paulo@103: if(opt.clickDay) { this.element.bind('clickDay', opt.clickDay); } paulo@103: if(opt.dayContextMenu) { this.element.bind('dayContextMenu', opt.dayContextMenu); } paulo@103: if(opt.selectRange) { this.element.bind('selectRange', opt.selectRange); } paulo@103: if(opt.mouseOnDay) { this.element.bind('mouseOnDay', opt.mouseOnDay); } paulo@103: if(opt.mouseOutDay) { this.element.bind('mouseOutDay', opt.mouseOutDay); } paulo@103: }, paulo@103: _initializeDatasourceColors: function() { paulo@103: for(var i in this.options.dataSource) { paulo@103: if(this.options.dataSource[i].color == null) { paulo@103: this.options.dataSource[i].color = colors[i % colors.length]; paulo@103: } paulo@103: } paulo@103: }, paulo@103: _render: function() { paulo@103: this.element.empty(); paulo@103: paulo@103: this._renderHeader(); paulo@103: this._renderBody(); paulo@103: this._renderDataSource(); paulo@103: paulo@103: this._applyEvents(); paulo@103: this.element.find('.months-container').fadeIn(500); paulo@103: paulo@103: this._triggerEvent('renderEnd', { currentYear: this.options.startYear }); paulo@103: }, paulo@103: _renderHeader: function() { paulo@103: var header = $(document.createElement('div')); paulo@103: header.addClass('calendar-header panel panel-default'); paulo@103: paulo@103: var headerTable = $(document.createElement('table')); paulo@103: paulo@103: var prevDiv = $(document.createElement('th')); paulo@103: prevDiv.addClass('prev'); paulo@103: paulo@103: if(this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 1, 11, 31)) { paulo@103: prevDiv.addClass('disabled'); paulo@103: } paulo@103: paulo@103: var prevIcon = $(document.createElement('span')); paulo@103: prevIcon.addClass('glyphicon glyphicon-chevron-left'); paulo@103: paulo@103: prevDiv.append(prevIcon); paulo@103: paulo@103: headerTable.append(prevDiv); paulo@103: paulo@103: var prev2YearDiv = $(document.createElement('th')); paulo@103: prev2YearDiv.addClass('year-title year-neighbor2 hidden-sm hidden-xs'); paulo@103: prev2YearDiv.text(this.options.startYear - 2); paulo@103: paulo@103: if(this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 2, 11, 31)) { paulo@103: prev2YearDiv.addClass('disabled'); paulo@103: } paulo@103: paulo@103: headerTable.append(prev2YearDiv); paulo@103: paulo@103: var prevYearDiv = $(document.createElement('th')); paulo@103: prevYearDiv.addClass('year-title year-neighbor hidden-xs'); paulo@103: prevYearDiv.text(this.options.startYear - 1); paulo@103: paulo@103: if(this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 1, 11, 31)) { paulo@103: prevYearDiv.addClass('disabled'); paulo@103: } paulo@103: paulo@103: headerTable.append(prevYearDiv); paulo@103: paulo@103: var yearDiv = $(document.createElement('th')); paulo@103: yearDiv.addClass('year-title'); paulo@103: yearDiv.text(this.options.startYear); paulo@103: paulo@103: headerTable.append(yearDiv); paulo@103: paulo@103: var nextYearDiv = $(document.createElement('th')); paulo@103: nextYearDiv.addClass('year-title year-neighbor hidden-xs'); paulo@103: nextYearDiv.text(this.options.startYear + 1); paulo@103: paulo@103: if(this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 1, 0, 1)) { paulo@103: nextYearDiv.addClass('disabled'); paulo@103: } paulo@103: paulo@103: headerTable.append(nextYearDiv); paulo@103: paulo@103: var next2YearDiv = $(document.createElement('th')); paulo@103: next2YearDiv.addClass('year-title year-neighbor2 hidden-sm hidden-xs'); paulo@103: next2YearDiv.text(this.options.startYear + 2); paulo@103: paulo@103: if(this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 2, 0, 1)) { paulo@103: next2YearDiv.addClass('disabled'); paulo@103: } paulo@103: paulo@103: headerTable.append(next2YearDiv); paulo@103: paulo@103: var nextDiv = $(document.createElement('th')); paulo@103: nextDiv.addClass('next'); paulo@103: paulo@103: if(this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 1, 0, 1)) { paulo@103: nextDiv.addClass('disabled'); paulo@103: } paulo@103: paulo@103: var nextIcon = $(document.createElement('span')); paulo@103: nextIcon.addClass('glyphicon glyphicon-chevron-right'); paulo@103: paulo@103: nextDiv.append(nextIcon); paulo@103: paulo@103: headerTable.append(nextDiv); paulo@103: paulo@103: header.append(headerTable); paulo@103: paulo@103: this.element.append(header); paulo@103: }, paulo@103: _renderBody: function() { paulo@103: var monthsDiv = $(document.createElement('div')); paulo@103: monthsDiv.addClass('months-container'); paulo@103: paulo@103: for(var m = 0; m < 12; m++) { paulo@103: /* Container */ paulo@103: var monthDiv = $(document.createElement('div')); paulo@103: monthDiv.addClass('month-container'); paulo@103: monthDiv.data('month-id', m); paulo@103: paulo@103: var firstDate = new Date(this.options.startYear, m, 1); paulo@103: paulo@103: var table = $(document.createElement('table')); paulo@103: table.addClass('month'); paulo@103: paulo@103: /* Month header */ paulo@103: var thead = $(document.createElement('thead')); paulo@103: paulo@103: var titleRow = $(document.createElement('tr')); paulo@103: paulo@103: var titleCell = $(document.createElement('th')); paulo@103: titleCell.addClass('month-title'); paulo@103: titleCell.attr('colspan', this.options.displayWeekNumber ? 8 : 7); paulo@103: titleCell.text(dates[this.options.language].months[m]); paulo@103: paulo@103: titleRow.append(titleCell); paulo@103: thead.append(titleRow); paulo@103: paulo@103: var headerRow = $(document.createElement('tr')); paulo@103: paulo@103: if(this.options.displayWeekNumber) { paulo@103: var weekNumberCell = $(document.createElement('th')); paulo@103: weekNumberCell.addClass('week-number'); paulo@103: weekNumberCell.text(dates[this.options.language].weekShort); paulo@103: headerRow.append(weekNumberCell); paulo@103: } paulo@103: paulo@103: var d = dates[this.options.language].weekStart; paulo@103: do paulo@103: { paulo@103: var headerCell = $(document.createElement('th')); paulo@103: headerCell.addClass('day-header'); paulo@103: headerCell.text(dates[this.options.language].daysMin[d]); paulo@103: paulo@103: headerRow.append(headerCell); paulo@103: paulo@103: d++; paulo@103: if(d >= 7) paulo@103: d = 0; paulo@103: } paulo@103: while(d != dates[this.options.language].weekStart) paulo@103: paulo@103: thead.append(headerRow); paulo@103: table.append(thead); paulo@103: paulo@103: /* Days */ paulo@103: var currentDate = new Date(firstDate.getTime()); paulo@103: var lastDate = new Date(this.options.startYear, m + 1, 0); paulo@103: paulo@103: var weekStart = dates[this.options.language].weekStart paulo@103: paulo@103: while(currentDate.getDay() != weekStart) paulo@103: { paulo@103: currentDate.setDate(currentDate.getDate() - 1); paulo@103: } paulo@103: paulo@103: while(currentDate <= lastDate) paulo@103: { paulo@103: var row = $(document.createElement('tr')); paulo@103: paulo@103: if(this.options.displayWeekNumber) { paulo@103: var weekNumberCell = $(document.createElement('td')); paulo@103: weekNumberCell.addClass('week-number'); paulo@103: weekNumberCell.text(this.getWeekNumber(currentDate)); paulo@103: row.append(weekNumberCell); paulo@103: } paulo@103: paulo@103: do paulo@103: { paulo@103: var cell = $(document.createElement('td')); paulo@103: cell.addClass('day'); paulo@103: paulo@103: if(currentDate < firstDate) { paulo@103: cell.addClass('old'); paulo@103: } paulo@103: else if(currentDate > lastDate) { paulo@103: cell.addClass('new'); paulo@103: } paulo@103: else { paulo@103: if((this.options.minDate != null && currentDate < this.options.minDate) || (this.options.maxDate != null && currentDate > this.options.maxDate)) paulo@103: { paulo@103: cell.addClass('disabled'); paulo@103: } paulo@103: else if(this.options.disabledDays.length > 0) { paulo@103: for(var d in this.options.disabledDays){ paulo@103: if(currentDate.getTime() == this.options.disabledDays[d].getTime()) { paulo@103: cell.addClass('disabled'); paulo@103: break; paulo@103: } paulo@103: } paulo@103: } paulo@103: paulo@103: var cellContent = $(document.createElement('div')); paulo@103: cellContent.addClass('day-content'); paulo@103: cellContent.text(currentDate.getDate()); paulo@103: cell.append(cellContent); paulo@103: paulo@103: if(this.options.customDayRenderer) { paulo@103: this.options.customDayRenderer(cellContent, currentDate); paulo@103: } paulo@103: } paulo@103: paulo@103: row.append(cell); paulo@103: paulo@103: currentDate.setDate(currentDate.getDate() + 1); paulo@103: } paulo@103: while(currentDate.getDay() != weekStart) paulo@103: paulo@103: table.append(row); paulo@103: } paulo@103: paulo@103: monthDiv.append(table); paulo@103: paulo@103: monthsDiv.append(monthDiv); paulo@103: } paulo@103: paulo@103: this.element.append(monthsDiv); paulo@103: }, paulo@103: _renderDataSource: function() { paulo@103: var _this = this; paulo@103: if(this.options.dataSource != null && this.options.dataSource.length > 0) { paulo@103: this.element.find('.month-container').each(function() { paulo@103: var month = $(this).data('month-id'); paulo@103: paulo@103: var firstDate = new Date(_this.options.startYear, month, 1); paulo@103: var lastDate = new Date(_this.options.startYear, month + 1, 0); paulo@103: paulo@103: if((_this.options.minDate == null || lastDate >= _this.options.minDate) && (_this.options.maxDate == null || firstDate <= _this.options.maxDate)) paulo@103: { paulo@103: var monthData = []; paulo@103: paulo@103: for(var i in _this.options.dataSource) { paulo@103: if(!(_this.options.dataSource[i].startDate > lastDate) || (_this.options.dataSource[i].endDate < firstDate)) { paulo@103: monthData.push(_this.options.dataSource[i]); paulo@103: } paulo@103: } paulo@103: paulo@103: if(monthData.length > 0) { paulo@103: $(this).find('.day-content').each(function() { paulo@103: var currentDate = new Date(_this.options.startYear, month, $(this).text()); paulo@103: paulo@103: var dayData = []; paulo@103: paulo@103: if((_this.options.minDate == null || currentDate >= _this.options.minDate) && (_this.options.maxDate == null || currentDate <= _this.options.maxDate)) paulo@103: { paulo@103: for(var i in monthData) { paulo@103: if(monthData[i].startDate <= currentDate && monthData[i].endDate >= currentDate) { paulo@103: dayData.push(monthData[i]); paulo@103: } paulo@103: } paulo@103: paulo@103: if(dayData.length > 0) paulo@103: { paulo@103: _this._renderDataSourceDay($(this), currentDate, dayData); paulo@103: } paulo@103: } paulo@103: }); paulo@103: } paulo@103: } paulo@103: }); paulo@103: } paulo@103: }, paulo@103: _renderDataSourceDay: function(elt, currentDate, events) { paulo@103: switch(this.options.style) paulo@103: { paulo@103: case 'border': paulo@103: var weight = 0; paulo@103: paulo@103: if(events.length == 1) { paulo@103: weight = 4; paulo@103: } paulo@103: else if(events.length <= 3) { paulo@103: weight = 2; paulo@103: } paulo@103: else { paulo@103: elt.parent().css('box-shadow', 'inset 0 -4px 0 0 black'); paulo@103: } paulo@103: paulo@103: if(weight > 0) paulo@103: { paulo@103: var boxShadow = ''; paulo@103: paulo@103: for(var i in events) paulo@103: { paulo@103: if(boxShadow != '') { paulo@103: boxShadow += ","; paulo@103: } paulo@103: paulo@103: boxShadow += 'inset 0 -' + (parseInt(i) + 1) * weight + 'px 0 0 ' + events[i].color; paulo@103: } paulo@103: paulo@103: elt.parent().css('box-shadow', boxShadow); paulo@103: } paulo@103: break; paulo@103: paulo@103: case 'background': paulo@103: elt.parent().css('background-color', events[events.length - 1].color); paulo@103: paulo@103: var currentTime = currentDate.getTime(); paulo@103: paulo@103: if(events[events.length - 1].startDate.getTime() == currentTime) paulo@103: { paulo@103: elt.parent().addClass('day-start'); paulo@103: paulo@103: if(events[events.length - 1].startHalfDay || this.options.alwaysHalfDay) { paulo@103: elt.parent().addClass('day-half'); paulo@103: paulo@103: // Find color for other half paulo@103: var otherColor = 'transparent'; paulo@103: for(var i = events.length - 2; i >= 0; i--) { paulo@103: if(events[i].startDate.getTime() != currentTime || (!events[i].startHalfDay && !this.options.alwaysHalfDay)) { paulo@103: otherColor = events[i].color; paulo@103: break; paulo@103: } paulo@103: } paulo@103: paulo@103: elt.parent().css('background', 'linear-gradient(-45deg, ' + events[events.length - 1].color + ', ' + events[events.length - 1].color + ' 49%, ' + otherColor + ' 51%, ' + otherColor + ')'); paulo@103: } paulo@103: else if(this.options.roundRangeLimits) { paulo@103: elt.parent().addClass('round-left'); paulo@103: } paulo@103: } paulo@103: else if(events[events.length - 1].endDate.getTime() == currentTime) paulo@103: { paulo@103: elt.parent().addClass('day-end'); paulo@103: paulo@103: if(events[events.length - 1].endHalfDay || this.options.alwaysHalfDay) { paulo@103: elt.parent().addClass('day-half'); paulo@103: paulo@103: // Find color for other half paulo@103: var otherColor = 'transparent'; paulo@103: for(var i = events.length - 2; i >= 0; i--) { paulo@103: if(events[i].endDate.getTime() != currentTime || (!events[i].endHalfDay && !this.options.alwaysHalfDay)) { paulo@103: otherColor = events[i].color; paulo@103: break; paulo@103: } paulo@103: } paulo@103: paulo@103: elt.parent().css('background', 'linear-gradient(135deg, ' + events[events.length - 1].color + ', ' + events[events.length - 1].color + ' 49%, ' + otherColor + ' 51%, ' + otherColor + ')'); paulo@103: } paulo@103: else if(this.options.roundRangeLimits) { paulo@103: elt.parent().addClass('round-right'); paulo@103: } paulo@103: } paulo@103: break; paulo@103: paulo@103: case 'custom': paulo@103: if(this.options.customDataSourceRenderer) { paulo@103: this.options.customDataSourceRenderer.call(this, elt, currentDate, events); paulo@103: } paulo@103: break; paulo@103: } paulo@103: }, paulo@103: _applyEvents: function () { paulo@103: var _this = this; paulo@103: paulo@103: /* Header buttons */ paulo@103: this.element.find('.year-neighbor, .year-neighbor2').click(function() { paulo@103: if(!$(this).hasClass('disabled')) { paulo@103: _this.setYear(parseInt($(this).text())); paulo@103: } paulo@103: }); paulo@103: paulo@103: this.element.find('.calendar-header .prev').click(function() { paulo@103: if(!$(this).hasClass('disabled')) { paulo@103: _this.element.find('.months-container').animate({'margin-left':'100%'},100, function() { paulo@103: _this.element.find('.months-container').hide(); paulo@103: _this.element.find('.months-container').css('margin-left', '0'); paulo@103: setTimeout(function() { _this.setYear(_this.options.startYear - 1) }, 50); paulo@103: }); paulo@103: } paulo@103: }); paulo@103: paulo@103: this.element.find('.calendar-header .next').click(function() { paulo@103: if(!$(this).hasClass('disabled')) { paulo@103: _this.element.find('.months-container').animate({'margin-left':'-100%'},100, function() { paulo@103: _this.element.find('.months-container').hide(); paulo@103: _this.element.find('.months-container').css('margin-left', '0'); paulo@103: setTimeout(function() { _this.setYear(_this.options.startYear + 1) }, 50); paulo@103: }); paulo@103: } paulo@103: }); paulo@103: paulo@103: var cells = this.element.find('.day:not(.old, .new, .disabled)'); paulo@103: paulo@103: /* Click on date */ paulo@103: cells.click(function(e) { paulo@103: e.stopPropagation(); paulo@103: var date = _this._getDate($(this)); paulo@103: _this._triggerEvent('clickDay', { paulo@103: element: $(this), paulo@103: which: e.which, paulo@103: date: date, paulo@103: events: _this.getEvents(date) paulo@103: }); paulo@103: }); paulo@103: paulo@103: /* Click right on date */ paulo@103: paulo@103: cells.bind('contextmenu', function(e) { paulo@103: if(_this.options.enableContextMenu) paulo@103: { paulo@103: e.preventDefault(); paulo@103: if(_this.options.contextMenuItems.length > 0) paulo@103: { paulo@103: _this._openContextMenu($(this)); paulo@103: } paulo@103: } paulo@103: paulo@103: var date = _this._getDate($(this)); paulo@103: _this._triggerEvent('dayContextMenu', { paulo@103: element: $(this), paulo@103: date: date, paulo@103: events: _this.getEvents(date) paulo@103: }); paulo@103: }); paulo@103: paulo@103: /* Range selection */ paulo@103: if(this.options.enableRangeSelection) { paulo@103: cells.mousedown(function (e) { paulo@103: if(e.which == 1) { paulo@103: var currentDate = _this._getDate($(this)); paulo@103: paulo@103: if(_this.options.allowOverlap || _this.getEvents(currentDate).length == 0) paulo@103: { paulo@103: _this._mouseDown = true; paulo@103: _this._rangeStart = _this._rangeEnd = currentDate; paulo@103: _this._refreshRange(); paulo@103: } paulo@103: } paulo@103: }); paulo@103: paulo@103: cells.mouseenter(function (e) { paulo@103: if (_this._mouseDown) { paulo@103: var currentDate = _this._getDate($(this)); paulo@103: paulo@103: if(!_this.options.allowOverlap) paulo@103: { paulo@103: var newDate = new Date(_this._rangeStart.getTime()); paulo@103: paulo@103: if(newDate < currentDate) { paulo@103: var nextDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() + 1); paulo@103: while(newDate < currentDate) { paulo@103: if(_this.getEvents(nextDate).length > 0) paulo@103: { paulo@103: break; paulo@103: } paulo@103: paulo@103: newDate.setDate(newDate.getDate() + 1); paulo@103: nextDate.setDate(nextDate.getDate() + 1); paulo@103: } paulo@103: } paulo@103: else { paulo@103: var nextDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() - 1); paulo@103: while(newDate > currentDate) { paulo@103: if(_this.getEvents(nextDate).length > 0) paulo@103: { paulo@103: break; paulo@103: } paulo@103: paulo@103: newDate.setDate(newDate.getDate() - 1); paulo@103: nextDate.setDate(nextDate.getDate() - 1); paulo@103: } paulo@103: } paulo@103: paulo@103: currentDate = newDate; paulo@103: } paulo@103: paulo@103: var oldValue = _this._rangeEnd; paulo@103: _this._rangeEnd = currentDate; paulo@103: paulo@103: if (oldValue.getTime() != _this._rangeEnd.getTime()) { paulo@103: _this._refreshRange(); paulo@103: } paulo@103: } paulo@103: }); paulo@103: paulo@103: $(window).mouseup(function (e) { paulo@103: if (_this._mouseDown) { paulo@103: _this._mouseDown = false; paulo@103: _this._refreshRange(); paulo@103: paulo@103: var minDate = _this._rangeStart < _this._rangeEnd ? _this._rangeStart : _this._rangeEnd; paulo@103: var maxDate = _this._rangeEnd > _this._rangeStart ? _this._rangeEnd : _this._rangeStart; paulo@103: paulo@103: _this._triggerEvent('selectRange', { startDate: minDate, endDate: maxDate }); paulo@103: } paulo@103: }); paulo@103: } paulo@103: paulo@103: /* Hover date */ paulo@103: cells.mouseenter(function(e) { paulo@103: if(!_this._mouseDown) paulo@103: { paulo@103: var date = _this._getDate($(this)); paulo@103: _this._triggerEvent('mouseOnDay', { paulo@103: element: $(this), paulo@103: date: date, paulo@103: events: _this.getEvents(date) paulo@103: }); paulo@103: } paulo@103: }); paulo@103: paulo@103: cells.mouseleave(function(e) { paulo@103: var date = _this._getDate($(this)); paulo@103: _this._triggerEvent('mouseOutDay', { paulo@103: element: $(this), paulo@103: date: date, paulo@103: events: _this.getEvents(date) paulo@103: }); paulo@103: }); paulo@103: paulo@103: /* Responsive management */ paulo@103: paulo@103: setInterval(function() { paulo@103: var calendarSize = $(_this.element).width(); paulo@103: var monthSize = $(_this.element).find('.month').first().width() + 10; paulo@103: var monthContainerClass = 'month-container'; paulo@103: paulo@103: if(monthSize * 6 < calendarSize) { paulo@103: monthContainerClass += ' col-xs-2'; paulo@103: } paulo@103: else if(monthSize * 4 < calendarSize) { paulo@103: monthContainerClass += ' col-xs-3'; paulo@103: } paulo@103: else if(monthSize * 3 < calendarSize) { paulo@103: monthContainerClass += ' col-xs-4'; paulo@103: } paulo@103: else if(monthSize * 2 < calendarSize) { paulo@103: monthContainerClass += ' col-xs-6'; paulo@103: } paulo@103: else { paulo@103: monthContainerClass += ' col-xs-12'; paulo@103: } paulo@103: paulo@103: $(_this.element).find('.month-container').attr('class', monthContainerClass); paulo@103: }, 300); paulo@103: }, paulo@103: _refreshRange: function () { paulo@103: var _this = this; paulo@103: paulo@103: this.element.find('td.day.range').removeClass('range') paulo@103: this.element.find('td.day.range-start').removeClass('range-start'); paulo@103: this.element.find('td.day.range-end').removeClass('range-end'); paulo@103: paulo@103: if (this._mouseDown) { paulo@103: var beforeRange = true; paulo@103: var afterRange = false; paulo@103: var minDate = _this._rangeStart < _this._rangeEnd ? _this._rangeStart : _this._rangeEnd; paulo@103: var maxDate = _this._rangeEnd > _this._rangeStart ? _this._rangeEnd : _this._rangeStart; paulo@103: paulo@103: this.element.find('.month-container').each(function () { paulo@103: var monthId = $(this).data('month-id'); paulo@103: if (minDate.getMonth() <= monthId && maxDate.getMonth() >= monthId) { paulo@103: $(this).find('td.day:not(.old, .new)').each(function () { paulo@103: var date = _this._getDate($(this)); paulo@103: if (date >= minDate && date <= maxDate) { paulo@103: $(this).addClass('range'); paulo@103: paulo@103: if (date.getTime() == minDate.getTime()) { paulo@103: $(this).addClass('range-start'); paulo@103: } paulo@103: paulo@103: if (date.getTime() == maxDate.getTime()) { paulo@103: $(this).addClass('range-end'); paulo@103: } paulo@103: } paulo@103: }); paulo@103: } paulo@103: }); paulo@103: } paulo@103: }, paulo@103: _openContextMenu: function(elt) { paulo@103: var contextMenu = $('.calendar-context-menu'); paulo@103: paulo@103: if(contextMenu.length > 0) { paulo@103: contextMenu.hide(); paulo@103: contextMenu.empty(); paulo@103: } paulo@103: else { paulo@103: contextMenu = $(document.createElement('div')); paulo@103: contextMenu.addClass('calendar-context-menu'); paulo@103: $('body').append(contextMenu); paulo@103: } paulo@103: paulo@103: var date = this._getDate(elt); paulo@103: var events = this.getEvents(date); paulo@103: paulo@103: for(var i in events) { paulo@103: var eventItem = $(document.createElement('div')); paulo@103: eventItem.addClass('item'); paulo@103: eventItem.css('border-left', '4px solid ' + events[i].color); paulo@103: paulo@103: var eventItemContent = $(document.createElement('div')); paulo@103: eventItemContent.addClass('content'); paulo@103: eventItemContent.text(events[i].name); paulo@103: paulo@103: eventItem.append(eventItemContent); paulo@103: paulo@103: var icon = $(document.createElement('span')); paulo@103: icon.addClass('glyphicon glyphicon-chevron-right'); paulo@103: paulo@103: eventItem.append(icon); paulo@103: paulo@103: this._renderContextMenuItems(eventItem, this.options.contextMenuItems, events[i]); paulo@103: paulo@103: contextMenu.append(eventItem); paulo@103: } paulo@103: paulo@103: if(contextMenu.children().length > 0) paulo@103: { paulo@103: contextMenu.css('left', elt.offset().left + 25 + 'px'); paulo@103: contextMenu.css('top', elt.offset().top + 25 + 'px'); paulo@103: contextMenu.show(); paulo@103: paulo@103: $(window).one('mouseup', function() { paulo@103: contextMenu.hide(); paulo@103: }); paulo@103: } paulo@103: }, paulo@103: _renderContextMenuItems: function(parent, items, evt) { paulo@103: var subMenu = $(document.createElement('div')); paulo@103: subMenu.addClass('submenu'); paulo@103: paulo@103: for(var i in items) { paulo@103: if(!items[i].visible || items[i].visible(evt)) { paulo@103: var menuItem = $(document.createElement('div')); paulo@103: menuItem.addClass('item'); paulo@103: paulo@103: var menuItemContent = $(document.createElement('div')); paulo@103: menuItemContent.addClass('content'); paulo@103: menuItemContent.text(items[i].text); paulo@103: paulo@103: menuItem.append(menuItemContent); paulo@103: paulo@103: if(items[i].click) { paulo@103: (function(index) { paulo@103: menuItem.click(function() { paulo@103: items[index].click(evt); paulo@103: }); paulo@103: })(i); paulo@103: } paulo@103: paulo@103: var icon = $(document.createElement('span')); paulo@103: icon.addClass('glyphicon glyphicon-chevron-right'); paulo@103: paulo@103: menuItem.append(icon); paulo@103: paulo@103: if(items[i].items && items[i].items.length > 0) { paulo@103: this._renderContextMenuItems(menuItem, items[i].items, evt); paulo@103: } paulo@103: paulo@103: subMenu.append(menuItem); paulo@103: } paulo@103: } paulo@103: paulo@103: if(subMenu.children().length > 0) paulo@103: { paulo@103: parent.append(subMenu); paulo@103: } paulo@103: }, paulo@103: _getColor: function(colorString) { paulo@103: var div = $('
'); paulo@103: div.css('color', colorString); paulo@103: paulo@103: }, paulo@103: _getDate: function(elt) { paulo@103: var day = elt.children('.day-content').text(); paulo@103: var month = elt.closest('.month-container').data('month-id'); paulo@103: var year = this.options.startYear; paulo@103: paulo@103: return new Date(year, month, day); paulo@103: }, paulo@103: _triggerEvent: function(eventName, parameters) { paulo@103: var event = $.Event(eventName); paulo@103: paulo@103: for(var i in parameters) { paulo@103: event[i] = parameters[i]; paulo@103: } paulo@103: paulo@103: this.element.trigger(event); paulo@103: }, paulo@103: getWeekNumber: function(date) { paulo@103: var tempDate = new Date(date.getTime()); paulo@103: tempDate.setHours(0, 0, 0, 0); paulo@103: tempDate.setDate(tempDate.getDate() + 3 - (tempDate.getDay() + 6) % 7); paulo@103: var week1 = new Date(tempDate.getFullYear(), 0, 4); paulo@103: return 1 + Math.round(((tempDate.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7); paulo@103: }, paulo@103: getEvents: function(date) { paulo@103: var events = []; paulo@103: paulo@103: if(this.options.dataSource && date) { paulo@103: for(var i in this.options.dataSource) { paulo@103: if(this.options.dataSource[i].startDate <= date && this.options.dataSource[i].endDate >= date) { paulo@103: events.push(this.options.dataSource[i]); paulo@103: } paulo@103: } paulo@103: } paulo@103: paulo@103: return events; paulo@103: }, paulo@103: getYear: function() { paulo@103: return this.options.startYear; paulo@103: }, paulo@103: setYear: function(year) { paulo@103: var parsedYear = parseInt(year); paulo@103: if(!isNaN(parsedYear)) { paulo@103: this.options.startYear = parsedYear; paulo@103: this._render(); paulo@103: } paulo@103: }, paulo@103: getMinDate: function() { paulo@103: return this.options.minDate; paulo@103: }, paulo@103: setMinDate: function(date) { paulo@103: if(date instanceof Date) { paulo@103: this.options.minDate = date; paulo@103: this._render(); paulo@103: } paulo@103: }, paulo@103: getMaxDate: function() { paulo@103: return this.options.maxDate; paulo@103: }, paulo@103: setMaxDate: function(date) { paulo@103: if(date instanceof Date) { paulo@103: this.options.maxDate = date; paulo@103: this._render(); paulo@103: } paulo@103: }, paulo@103: getStyle: function() { paulo@103: return this.options.style; paulo@103: }, paulo@103: setStyle: function(style) { paulo@103: this.options.style = style == 'background' || style == 'border' || style == 'custom' ? style : 'border'; paulo@103: this._render(); paulo@103: }, paulo@103: getAllowOverlap: function() { paulo@103: return this.options.allowOverlap; paulo@103: }, paulo@103: setAllowOverlap: function(allowOverlap) { paulo@103: this.options.allowOverlap = allowOverlap; paulo@103: }, paulo@103: getDisplayWeekNumber: function() { paulo@103: return this.options.displayWeekNumber; paulo@103: }, paulo@103: setDisplayWeekNumber: function(displayWeekNumber) { paulo@103: this.options.displayWeekNumber = displayWeekNumber; paulo@103: this._render(); paulo@103: }, paulo@103: getAlwaysHalfDay: function() { paulo@103: return this.options.alwaysHalfDay; paulo@103: }, paulo@103: setAlwaysHalfDay: function(alwaysHalfDay) { paulo@103: this.options.alwaysHalfDay = alwaysHalfDay; paulo@103: this._render(); paulo@103: }, paulo@103: getEnableRangeSelection: function() { paulo@103: return this.options.enableRangeSelection; paulo@103: }, paulo@103: setEnableRangeSelection: function(enableRangeSelection) { paulo@103: this.options.enableRangeSelection = enableRangeSelection; paulo@103: this._render(); paulo@103: }, paulo@103: getDisabledDays: function() { paulo@103: return this.options.disabledDays; paulo@103: }, paulo@103: setDisabledDays: function(disabledDays) { paulo@103: this.options.disabledDays = disabledDays instanceof Array ? disabledDays : []; paulo@103: this._render(); paulo@103: }, paulo@103: getRoundRangeLimits: function() { paulo@103: return this.options.roundRangeLimits; paulo@103: }, paulo@103: setRoundRangeLimits: function(roundRangeLimits) { paulo@103: this.options.roundRangeLimits = roundRangeLimits; paulo@103: this._render(); paulo@103: }, paulo@103: getEnableContextMenu: function() { paulo@103: return this.options.enableContextMenu; paulo@103: }, paulo@103: setEnableContextMenu: function(enableContextMenu) { paulo@103: this.options.enableContextMenu = enableContextMenu; paulo@103: this._render(); paulo@103: }, paulo@103: getContextMenuItems: function() { paulo@103: return this.options.contextMenuItems; paulo@103: }, paulo@103: setContextMenuItems: function(contextMenuItems) { paulo@103: this.options.contextMenuItems = contextMenuItems instanceof Array ? contextMenuItems : []; paulo@103: this._render(); paulo@103: }, paulo@103: getCustomDayRenderer: function() { paulo@103: return this.options.customDayRenderer; paulo@103: }, paulo@103: setCustomDayRenderer: function(customDayRenderer) { paulo@103: this.options.customDayRenderer = $.isFunction(customDayRenderer) ? customDayRenderer : null; paulo@103: this._render(); paulo@103: }, paulo@103: getCustomDataSourceRenderer: function() { paulo@103: return this.options.customDataSourceRenderer; paulo@103: }, paulo@103: setCustomDataSourceRenderer: function(customDataSourceRenderer) { paulo@103: this.options.customDataSourceRenderer = $.isFunction(customDataSourceRenderer) ? customDataSourceRenderer : null; paulo@103: this._render(); paulo@103: }, paulo@103: getLanguage: function() { paulo@103: return this.options.language; paulo@103: }, paulo@103: setLanguage: function(language) { paulo@103: if(language != null && dates[language] != null) { paulo@103: this.options.language = language; paulo@103: this._render(); paulo@103: } paulo@103: }, paulo@103: getDataSource: function() { paulo@103: return this.options.dataSource; paulo@103: }, paulo@103: setDataSource: function(dataSource) { paulo@103: this.options.dataSource = dataSource instanceof Array ? dataSource : []; paulo@103: this._initializeDatasourceColors(); paulo@103: this._render(); paulo@103: }, paulo@103: addEvent: function(evt) { paulo@103: this.options.dataSource.push(evt); paulo@103: this._render(); paulo@103: } paulo@103: } paulo@103: paulo@103: $.fn.calendar = function (options) { paulo@103: var calendar = new Calendar($(this) ,options); paulo@103: $(this).data('calendar', calendar); paulo@103: return calendar; paulo@103: } paulo@103: paulo@103: /* Events binding management */ paulo@103: $.fn.renderEnd = function(fct) { $(this).bind('renderEnd', fct); } paulo@103: $.fn.clickDay = function(fct) { $(this).bind('clickDay', fct); } paulo@103: $.fn.dayContextMenu = function(fct) { $(this).bind('dayContextMenu', fct); } paulo@103: $.fn.selectRange = function(fct) { $(this).bind('selectRange', fct); } paulo@103: $.fn.mouseOnDay = function(fct) { $(this).bind('mouseOnDay', fct); } paulo@103: $.fn.mouseOutDay = function(fct) { $(this).bind('mouseOutDay', fct); } paulo@103: paulo@103: var dates = $.fn.calendar.dates = { paulo@103: en: { paulo@103: days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], paulo@103: daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], paulo@103: daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], paulo@103: months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], paulo@103: monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], paulo@103: weekShort: 'W', paulo@103: weekStart:0 paulo@103: } paulo@103: }; paulo@103: paulo@103: var colors = $.fn.calendar.colors = ['#2C8FC9', '#9CB703', '#F5BB00', '#FF4A32', '#B56CE2', '#45A597']; paulo@103: paulo@103: $(function(){ paulo@103: $('[data-provide="calendar"]').each(function() { paulo@103: $(this).calendar(); paulo@103: }); paulo@103: }); paulo@103: }(window.jQuery));