diff bootstrap-year-calendar/bootstrap-year-calendar.js @ 103:4043aaa41075

add bootstrap-year-calendar
author paulo
date Thu, 07 Mar 2019 00:52:02 -0800
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/bootstrap-year-calendar/bootstrap-year-calendar.js	Thu Mar 07 00:52:02 2019 -0800
     1.3 @@ -0,0 +1,945 @@
     1.4 +/* =========================================================
     1.5 + * Bootstrap year calendar v1.1.0
     1.6 + * Repo: https://github.com/Paul-DS/bootstrap-year-calendar
     1.7 + * =========================================================
     1.8 + * Created by Paul David-Sivelle
     1.9 + *
    1.10 + * Licensed under the Apache License, Version 2.0 (the "License");
    1.11 + * you may not use this file except in compliance with the License.
    1.12 + * You may obtain a copy of the License at
    1.13 + *
    1.14 + * http://www.apache.org/licenses/LICENSE-2.0
    1.15 + *
    1.16 + * Unless required by applicable law or agreed to in writing, software
    1.17 + * distributed under the License is distributed on an "AS IS" BASIS,
    1.18 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1.19 + * See the License for the specific language governing permissions and
    1.20 + * limitations under the License.
    1.21 + * ========================================================= */
    1.22 + 
    1.23 + (function($) {
    1.24 +	var Calendar = function(element, options) {
    1.25 +		this.element = element;
    1.26 +		this.element.addClass('calendar');
    1.27 +		
    1.28 +		this._initializeEvents(options);
    1.29 +		this._initializeOptions(options);
    1.30 +		this._render();
    1.31 +	};
    1.32 + 
    1.33 +	Calendar.prototype = {
    1.34 +		constructor: Calendar,
    1.35 +		_initializeOptions: function(opt) {
    1.36 +			if(opt == null) {
    1.37 +				opt = [];
    1.38 +			}
    1.39 +		
    1.40 +			this.options = {
    1.41 +				startYear: !isNaN(parseInt(opt.startYear)) ? parseInt(opt.startYear) : new Date().getFullYear(),
    1.42 +				minDate: opt.minDate instanceof Date ? opt.minDate : null,
    1.43 +				maxDate: opt.maxDate instanceof Date ? opt.maxDate : null,
    1.44 +				language: (opt.language != null && dates[opt.language] != null) ? opt.language : 'en',
    1.45 +				allowOverlap: opt.allowOverlap != null ? opt.allowOverlap : true,
    1.46 +				displayWeekNumber: opt.displayWeekNumber != null ? opt.displayWeekNumber : false,
    1.47 +				alwaysHalfDay: opt.alwaysHalfDay != null ? opt.alwaysHalfDay : false,
    1.48 +				enableRangeSelection: opt.enableRangeSelection != null ? opt.enableRangeSelection : false,
    1.49 +				disabledDays: opt.disabledDays instanceof Array ? opt.disabledDays : [],
    1.50 +				roundRangeLimits: opt.roundRangeLimits != null ? opt.roundRangeLimits : false,
    1.51 +				dataSource: opt.dataSource instanceof Array != null ? opt.dataSource : [],
    1.52 +				style: opt.style == 'background' || opt.style == 'border' || opt.style == 'custom' ? opt.style : 'border',
    1.53 +				enableContextMenu: opt.enableContextMenu != null ? opt.enableContextMenu : false,
    1.54 +				contextMenuItems: opt.contextMenuItems instanceof Array ? opt.contextMenuItems : [],
    1.55 +				customDayRenderer : $.isFunction(opt.customDayRenderer) ? opt.customDayRenderer : null,
    1.56 +				customDataSourceRenderer : $.isFunction(opt.customDataSourceRenderer) ? opt.customDataSourceRenderer : null
    1.57 +			};
    1.58 +			
    1.59 +			this._initializeDatasourceColors();
    1.60 +		},
    1.61 +		_initializeEvents: function(opt) {
    1.62 +			if(opt == null) {
    1.63 +				opt = [];
    1.64 +			}
    1.65 +		
    1.66 +			if(opt.renderEnd) { this.element.bind('renderEnd', opt.renderEnd); }
    1.67 +			if(opt.clickDay) { this.element.bind('clickDay', opt.clickDay); }
    1.68 +			if(opt.dayContextMenu) { this.element.bind('dayContextMenu', opt.dayContextMenu); }
    1.69 +			if(opt.selectRange) { this.element.bind('selectRange', opt.selectRange); }
    1.70 +			if(opt.mouseOnDay) { this.element.bind('mouseOnDay', opt.mouseOnDay); }
    1.71 +			if(opt.mouseOutDay) { this.element.bind('mouseOutDay', opt.mouseOutDay); }
    1.72 +		},
    1.73 +		_initializeDatasourceColors: function() {
    1.74 +			for(var i in this.options.dataSource) {
    1.75 +				if(this.options.dataSource[i].color == null) {
    1.76 +					this.options.dataSource[i].color = colors[i % colors.length];
    1.77 +				}
    1.78 +			}
    1.79 +		},
    1.80 +		_render: function() {
    1.81 +			this.element.empty();
    1.82 +			
    1.83 +			this._renderHeader();
    1.84 +			this._renderBody();
    1.85 +			this._renderDataSource();
    1.86 +			
    1.87 +			this._applyEvents();
    1.88 +			this.element.find('.months-container').fadeIn(500);
    1.89 +			
    1.90 +			this._triggerEvent('renderEnd', { currentYear: this.options.startYear });
    1.91 +		},
    1.92 +		_renderHeader: function() {
    1.93 +			var header = $(document.createElement('div'));
    1.94 +			header.addClass('calendar-header panel panel-default');
    1.95 +			
    1.96 +			var headerTable = $(document.createElement('table'));
    1.97 +			
    1.98 +			var prevDiv = $(document.createElement('th'));
    1.99 +			prevDiv.addClass('prev');
   1.100 +			
   1.101 +			if(this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 1, 11, 31)) {
   1.102 +				prevDiv.addClass('disabled');
   1.103 +			}
   1.104 +			
   1.105 +			var prevIcon = $(document.createElement('span'));
   1.106 +			prevIcon.addClass('glyphicon glyphicon-chevron-left');
   1.107 +			
   1.108 +			prevDiv.append(prevIcon);
   1.109 +			
   1.110 +			headerTable.append(prevDiv);
   1.111 +			
   1.112 +			var prev2YearDiv = $(document.createElement('th'));
   1.113 +			prev2YearDiv.addClass('year-title year-neighbor2 hidden-sm hidden-xs');
   1.114 +			prev2YearDiv.text(this.options.startYear - 2);
   1.115 +			
   1.116 +			if(this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 2, 11, 31)) {
   1.117 +				prev2YearDiv.addClass('disabled');
   1.118 +			}
   1.119 +			
   1.120 +			headerTable.append(prev2YearDiv);
   1.121 +			
   1.122 +			var prevYearDiv = $(document.createElement('th'));
   1.123 +			prevYearDiv.addClass('year-title year-neighbor hidden-xs');
   1.124 +			prevYearDiv.text(this.options.startYear - 1);
   1.125 +			
   1.126 +			if(this.options.minDate != null && this.options.minDate > new Date(this.options.startYear - 1, 11, 31)) {
   1.127 +				prevYearDiv.addClass('disabled');
   1.128 +			}
   1.129 +			
   1.130 +			headerTable.append(prevYearDiv);
   1.131 +			
   1.132 +			var yearDiv = $(document.createElement('th'));
   1.133 +			yearDiv.addClass('year-title');
   1.134 +			yearDiv.text(this.options.startYear);
   1.135 +			
   1.136 +			headerTable.append(yearDiv);
   1.137 +			
   1.138 +			var nextYearDiv = $(document.createElement('th'));
   1.139 +			nextYearDiv.addClass('year-title year-neighbor hidden-xs');
   1.140 +			nextYearDiv.text(this.options.startYear + 1);
   1.141 +			
   1.142 +			if(this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 1, 0, 1)) {
   1.143 +				nextYearDiv.addClass('disabled');
   1.144 +			}
   1.145 +			
   1.146 +			headerTable.append(nextYearDiv);
   1.147 +			
   1.148 +			var next2YearDiv = $(document.createElement('th'));
   1.149 +			next2YearDiv.addClass('year-title year-neighbor2 hidden-sm hidden-xs');
   1.150 +			next2YearDiv.text(this.options.startYear + 2);
   1.151 +			
   1.152 +			if(this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 2, 0, 1)) {
   1.153 +				next2YearDiv.addClass('disabled');
   1.154 +			}
   1.155 +			
   1.156 +			headerTable.append(next2YearDiv);
   1.157 +			
   1.158 +			var nextDiv = $(document.createElement('th'));
   1.159 +			nextDiv.addClass('next');
   1.160 +			
   1.161 +			if(this.options.maxDate != null && this.options.maxDate < new Date(this.options.startYear + 1, 0, 1)) {
   1.162 +				nextDiv.addClass('disabled');
   1.163 +			}
   1.164 +			
   1.165 +			var nextIcon = $(document.createElement('span'));
   1.166 +			nextIcon.addClass('glyphicon glyphicon-chevron-right');
   1.167 +			
   1.168 +			nextDiv.append(nextIcon);
   1.169 +			
   1.170 +			headerTable.append(nextDiv);
   1.171 +			
   1.172 +			header.append(headerTable);
   1.173 +			
   1.174 +			this.element.append(header);
   1.175 +		},
   1.176 +		_renderBody: function() {
   1.177 +			var monthsDiv = $(document.createElement('div'));
   1.178 +			monthsDiv.addClass('months-container');
   1.179 +			
   1.180 +			for(var m = 0; m < 12; m++) {
   1.181 +				/* Container */
   1.182 +				var monthDiv = $(document.createElement('div'));
   1.183 +				monthDiv.addClass('month-container');
   1.184 +				monthDiv.data('month-id', m);
   1.185 +				
   1.186 +				var firstDate = new Date(this.options.startYear, m, 1);
   1.187 +				
   1.188 +				var table = $(document.createElement('table'));
   1.189 +				table.addClass('month');
   1.190 +				
   1.191 +				/* Month header */
   1.192 +				var thead = $(document.createElement('thead'));
   1.193 +				
   1.194 +				var titleRow = $(document.createElement('tr'));
   1.195 +				
   1.196 +				var titleCell = $(document.createElement('th'));
   1.197 +				titleCell.addClass('month-title');
   1.198 +				titleCell.attr('colspan', this.options.displayWeekNumber ? 8 : 7);
   1.199 +				titleCell.text(dates[this.options.language].months[m]);
   1.200 +				
   1.201 +				titleRow.append(titleCell);
   1.202 +				thead.append(titleRow);
   1.203 +				
   1.204 +				var headerRow = $(document.createElement('tr'));
   1.205 +				
   1.206 +				if(this.options.displayWeekNumber) {
   1.207 +					var weekNumberCell = $(document.createElement('th'));
   1.208 +					weekNumberCell.addClass('week-number');
   1.209 +					weekNumberCell.text(dates[this.options.language].weekShort);
   1.210 +					headerRow.append(weekNumberCell);
   1.211 +				}
   1.212 +				
   1.213 +				var d = dates[this.options.language].weekStart;
   1.214 +				do
   1.215 +				{
   1.216 +					var headerCell = $(document.createElement('th'));
   1.217 +					headerCell.addClass('day-header');
   1.218 +					headerCell.text(dates[this.options.language].daysMin[d]);
   1.219 +					
   1.220 +					headerRow.append(headerCell);
   1.221 +					
   1.222 +					d++;
   1.223 +					if(d >= 7)
   1.224 +						d = 0;
   1.225 +				}
   1.226 +				while(d != dates[this.options.language].weekStart)
   1.227 +				
   1.228 +				thead.append(headerRow);
   1.229 +				table.append(thead);
   1.230 +				
   1.231 +				/* Days */
   1.232 +				var currentDate = new Date(firstDate.getTime());
   1.233 +				var lastDate = new Date(this.options.startYear, m + 1, 0);
   1.234 +				
   1.235 +				var weekStart = dates[this.options.language].weekStart
   1.236 +				
   1.237 +				while(currentDate.getDay() != weekStart)
   1.238 +				{
   1.239 +					currentDate.setDate(currentDate.getDate() - 1);
   1.240 +				}
   1.241 +				
   1.242 +				while(currentDate <= lastDate)
   1.243 +				{
   1.244 +					var row = $(document.createElement('tr'));
   1.245 +					
   1.246 +					if(this.options.displayWeekNumber) {
   1.247 +						var weekNumberCell = $(document.createElement('td'));
   1.248 +						weekNumberCell.addClass('week-number');
   1.249 +						weekNumberCell.text(this.getWeekNumber(currentDate));
   1.250 +						row.append(weekNumberCell);
   1.251 +					}
   1.252 +				
   1.253 +					do
   1.254 +					{
   1.255 +						var cell = $(document.createElement('td'));
   1.256 +						cell.addClass('day');
   1.257 +						
   1.258 +						if(currentDate < firstDate) {
   1.259 +							cell.addClass('old');
   1.260 +						}
   1.261 +						else if(currentDate > lastDate) {
   1.262 +							cell.addClass('new');
   1.263 +						}
   1.264 +						else {
   1.265 +							if((this.options.minDate != null && currentDate < this.options.minDate) || (this.options.maxDate != null && currentDate > this.options.maxDate))
   1.266 +							{
   1.267 +								cell.addClass('disabled');
   1.268 +							}
   1.269 +							else if(this.options.disabledDays.length > 0) {
   1.270 +								for(var d in this.options.disabledDays){
   1.271 +									if(currentDate.getTime() == this.options.disabledDays[d].getTime()) {
   1.272 +										cell.addClass('disabled');
   1.273 +										break;
   1.274 +									}
   1.275 +								}
   1.276 +							}
   1.277 +						
   1.278 +							var cellContent = $(document.createElement('div'));
   1.279 +							cellContent.addClass('day-content');
   1.280 +							cellContent.text(currentDate.getDate());
   1.281 +							cell.append(cellContent);
   1.282 +							
   1.283 +							if(this.options.customDayRenderer) {
   1.284 +								this.options.customDayRenderer(cellContent, currentDate);
   1.285 +							}
   1.286 +						}
   1.287 +						
   1.288 +						row.append(cell);
   1.289 +						
   1.290 +						currentDate.setDate(currentDate.getDate() + 1);
   1.291 +					}
   1.292 +					while(currentDate.getDay() != weekStart)
   1.293 +					
   1.294 +					table.append(row);
   1.295 +				}
   1.296 +				
   1.297 +				monthDiv.append(table);
   1.298 +				
   1.299 +				monthsDiv.append(monthDiv);
   1.300 +			}
   1.301 +			
   1.302 +			this.element.append(monthsDiv);
   1.303 +		},
   1.304 +		_renderDataSource: function() {
   1.305 +			var _this = this;
   1.306 +			if(this.options.dataSource != null && this.options.dataSource.length > 0) {
   1.307 +				this.element.find('.month-container').each(function() {
   1.308 +					var month = $(this).data('month-id');
   1.309 +					
   1.310 +					var firstDate = new Date(_this.options.startYear, month, 1);
   1.311 +					var lastDate = new Date(_this.options.startYear, month + 1, 0);
   1.312 +					
   1.313 +					if((_this.options.minDate == null || lastDate >= _this.options.minDate) && (_this.options.maxDate == null || firstDate <= _this.options.maxDate))
   1.314 +					{
   1.315 +						var monthData = [];
   1.316 +					
   1.317 +						for(var i in _this.options.dataSource) {
   1.318 +							if(!(_this.options.dataSource[i].startDate > lastDate) || (_this.options.dataSource[i].endDate < firstDate)) {
   1.319 +								monthData.push(_this.options.dataSource[i]);
   1.320 +							}
   1.321 +						}
   1.322 +						
   1.323 +						if(monthData.length > 0) {
   1.324 +							$(this).find('.day-content').each(function() {
   1.325 +								var currentDate = new Date(_this.options.startYear, month, $(this).text());
   1.326 +								
   1.327 +								var dayData = [];
   1.328 +								
   1.329 +								if((_this.options.minDate == null || currentDate >= _this.options.minDate) && (_this.options.maxDate == null || currentDate <= _this.options.maxDate))
   1.330 +								{
   1.331 +									for(var i in monthData) {
   1.332 +										if(monthData[i].startDate <= currentDate && monthData[i].endDate >= currentDate) {
   1.333 +											dayData.push(monthData[i]);
   1.334 +										}
   1.335 +									}
   1.336 +									
   1.337 +									if(dayData.length > 0)
   1.338 +									{
   1.339 +										_this._renderDataSourceDay($(this), currentDate, dayData);
   1.340 +									}
   1.341 +								}
   1.342 +							});
   1.343 +						}
   1.344 +					}
   1.345 +				});
   1.346 +			}
   1.347 +		},
   1.348 +		_renderDataSourceDay: function(elt, currentDate, events) {
   1.349 +			switch(this.options.style)
   1.350 +			{
   1.351 +				case 'border':
   1.352 +					var weight = 0;
   1.353 +			
   1.354 +					if(events.length == 1) {
   1.355 +						weight = 4;
   1.356 +					}
   1.357 +					else if(events.length <= 3) {
   1.358 +						weight = 2;
   1.359 +					}
   1.360 +					else {
   1.361 +						elt.parent().css('box-shadow', 'inset 0 -4px 0 0 black');
   1.362 +					}
   1.363 +					
   1.364 +					if(weight > 0)
   1.365 +					{
   1.366 +						var boxShadow = '';
   1.367 +					
   1.368 +						for(var i in events)
   1.369 +						{
   1.370 +							if(boxShadow != '') {
   1.371 +								boxShadow += ",";
   1.372 +							}
   1.373 +							
   1.374 +							boxShadow += 'inset 0 -' + (parseInt(i) + 1) * weight + 'px 0 0 ' + events[i].color;
   1.375 +						}
   1.376 +						
   1.377 +						elt.parent().css('box-shadow', boxShadow);
   1.378 +					}
   1.379 +					break;
   1.380 +			
   1.381 +				case 'background':
   1.382 +					elt.parent().css('background-color', events[events.length - 1].color);
   1.383 +					
   1.384 +					var currentTime = currentDate.getTime();
   1.385 +					
   1.386 +					if(events[events.length - 1].startDate.getTime() == currentTime)
   1.387 +					{
   1.388 +						elt.parent().addClass('day-start');
   1.389 +						
   1.390 +						if(events[events.length - 1].startHalfDay || this.options.alwaysHalfDay) {
   1.391 +							elt.parent().addClass('day-half');
   1.392 +							
   1.393 +							// Find color for other half
   1.394 +							var otherColor = 'transparent';
   1.395 +							for(var i = events.length - 2; i >= 0; i--) {
   1.396 +								if(events[i].startDate.getTime() != currentTime || (!events[i].startHalfDay && !this.options.alwaysHalfDay)) {
   1.397 +									otherColor = events[i].color;
   1.398 +									break;
   1.399 +								}
   1.400 +							}
   1.401 +							
   1.402 +							elt.parent().css('background', 'linear-gradient(-45deg, ' + events[events.length - 1].color + ', ' + events[events.length - 1].color + ' 49%, ' + otherColor + ' 51%, ' + otherColor + ')');
   1.403 +						}
   1.404 +						else if(this.options.roundRangeLimits) {
   1.405 +							elt.parent().addClass('round-left');
   1.406 +						}
   1.407 +					}
   1.408 +					else if(events[events.length - 1].endDate.getTime() == currentTime)
   1.409 +					{
   1.410 +						elt.parent().addClass('day-end');
   1.411 +						
   1.412 +						if(events[events.length - 1].endHalfDay || this.options.alwaysHalfDay) {
   1.413 +							elt.parent().addClass('day-half');
   1.414 +							
   1.415 +							// Find color for other half
   1.416 +							var otherColor = 'transparent';
   1.417 +							for(var i = events.length - 2; i >= 0; i--) {
   1.418 +								if(events[i].endDate.getTime() != currentTime || (!events[i].endHalfDay &&  !this.options.alwaysHalfDay)) {
   1.419 +									otherColor = events[i].color;
   1.420 +									break;
   1.421 +								}
   1.422 +							}
   1.423 +							
   1.424 +							elt.parent().css('background', 'linear-gradient(135deg, ' + events[events.length - 1].color + ', ' + events[events.length - 1].color + ' 49%, ' + otherColor + ' 51%, ' + otherColor + ')');
   1.425 +						}
   1.426 +						else if(this.options.roundRangeLimits) {
   1.427 +							elt.parent().addClass('round-right');
   1.428 +						}
   1.429 +					}
   1.430 +					break;
   1.431 +					
   1.432 +				case 'custom':
   1.433 +					if(this.options.customDataSourceRenderer) {
   1.434 +						this.options.customDataSourceRenderer.call(this, elt, currentDate, events);
   1.435 +					}
   1.436 +					break;
   1.437 +			}
   1.438 +		},
   1.439 +		_applyEvents: function () {
   1.440 +			var _this = this;
   1.441 +			
   1.442 +			/* Header buttons */
   1.443 +			this.element.find('.year-neighbor, .year-neighbor2').click(function() {
   1.444 +				if(!$(this).hasClass('disabled')) {
   1.445 +					_this.setYear(parseInt($(this).text()));
   1.446 +				}
   1.447 +			});
   1.448 +			
   1.449 +			this.element.find('.calendar-header .prev').click(function() {
   1.450 +				if(!$(this).hasClass('disabled')) {
   1.451 +					_this.element.find('.months-container').animate({'margin-left':'100%'},100, function() {
   1.452 +						_this.element.find('.months-container').hide();
   1.453 +						_this.element.find('.months-container').css('margin-left', '0');
   1.454 +						setTimeout(function() { _this.setYear(_this.options.startYear - 1) }, 50);
   1.455 +					});
   1.456 +				}
   1.457 +			});
   1.458 +			
   1.459 +			this.element.find('.calendar-header .next').click(function() {
   1.460 +				if(!$(this).hasClass('disabled')) {
   1.461 +					_this.element.find('.months-container').animate({'margin-left':'-100%'},100, function() {
   1.462 +						_this.element.find('.months-container').hide();
   1.463 +						_this.element.find('.months-container').css('margin-left', '0');
   1.464 +						setTimeout(function() { _this.setYear(_this.options.startYear + 1) }, 50);
   1.465 +					});
   1.466 +				}
   1.467 +			});
   1.468 +			
   1.469 +			var cells = this.element.find('.day:not(.old, .new, .disabled)');
   1.470 +			
   1.471 +			/* Click on date */
   1.472 +			cells.click(function(e) {
   1.473 +				e.stopPropagation();
   1.474 +				var date = _this._getDate($(this));
   1.475 +				_this._triggerEvent('clickDay', {
   1.476 +					element: $(this),
   1.477 +					which: e.which,
   1.478 +					date: date,
   1.479 +					events: _this.getEvents(date)
   1.480 +				});
   1.481 +			});
   1.482 +			
   1.483 +			/* Click right on date */
   1.484 +			
   1.485 +			cells.bind('contextmenu', function(e) {
   1.486 +				if(_this.options.enableContextMenu)
   1.487 +				{
   1.488 +					e.preventDefault();
   1.489 +					if(_this.options.contextMenuItems.length > 0)
   1.490 +					{
   1.491 +						_this._openContextMenu($(this));
   1.492 +					}
   1.493 +				}
   1.494 +					
   1.495 +				var date = _this._getDate($(this));
   1.496 +				_this._triggerEvent('dayContextMenu', {
   1.497 +					element: $(this),
   1.498 +					date: date,
   1.499 +					events: _this.getEvents(date)
   1.500 +				});
   1.501 +			});
   1.502 +			
   1.503 +			/* Range selection */
   1.504 +			if(this.options.enableRangeSelection) {
   1.505 +				cells.mousedown(function (e) {
   1.506 +					if(e.which == 1) {
   1.507 +						var currentDate = _this._getDate($(this));
   1.508 +					
   1.509 +						if(_this.options.allowOverlap || _this.getEvents(currentDate).length == 0)
   1.510 +						{
   1.511 +							_this._mouseDown = true;
   1.512 +							_this._rangeStart = _this._rangeEnd = currentDate;
   1.513 +							_this._refreshRange();
   1.514 +						}
   1.515 +					}
   1.516 +				});
   1.517 +
   1.518 +				cells.mouseenter(function (e) {
   1.519 +					if (_this._mouseDown) {
   1.520 +						var currentDate = _this._getDate($(this));
   1.521 +						
   1.522 +						if(!_this.options.allowOverlap)
   1.523 +						{
   1.524 +							var newDate =  new Date(_this._rangeStart.getTime());
   1.525 +							
   1.526 +							if(newDate < currentDate) {
   1.527 +								var nextDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() + 1);
   1.528 +								while(newDate < currentDate) {
   1.529 +									if(_this.getEvents(nextDate).length > 0)
   1.530 +									{
   1.531 +										break;
   1.532 +									}
   1.533 +								
   1.534 +									newDate.setDate(newDate.getDate() + 1);
   1.535 +									nextDate.setDate(nextDate.getDate() + 1);
   1.536 +								}
   1.537 +							}
   1.538 +							else {
   1.539 +								var nextDate = new Date(newDate.getFullYear(), newDate.getMonth(), newDate.getDate() - 1);
   1.540 +								while(newDate > currentDate) {
   1.541 +									if(_this.getEvents(nextDate).length > 0)
   1.542 +									{
   1.543 +										break;
   1.544 +									}
   1.545 +								
   1.546 +									newDate.setDate(newDate.getDate() - 1);
   1.547 +									nextDate.setDate(nextDate.getDate() - 1);
   1.548 +								}
   1.549 +							}
   1.550 +							
   1.551 +							currentDate = newDate;
   1.552 +						}
   1.553 +					
   1.554 +						var oldValue = _this._rangeEnd;
   1.555 +						_this._rangeEnd = currentDate;
   1.556 +
   1.557 +						if (oldValue.getTime() != _this._rangeEnd.getTime()) {
   1.558 +							_this._refreshRange();
   1.559 +						}
   1.560 +					}
   1.561 +				});
   1.562 +
   1.563 +				$(window).mouseup(function (e) {
   1.564 +					if (_this._mouseDown) {
   1.565 +						_this._mouseDown = false;
   1.566 +						_this._refreshRange();
   1.567 +
   1.568 +						var minDate = _this._rangeStart < _this._rangeEnd ? _this._rangeStart : _this._rangeEnd;
   1.569 +						var maxDate = _this._rangeEnd > _this._rangeStart ? _this._rangeEnd : _this._rangeStart;
   1.570 +
   1.571 +						_this._triggerEvent('selectRange', { startDate: minDate, endDate: maxDate });
   1.572 +					}
   1.573 +				});
   1.574 +			}
   1.575 +		
   1.576 +			/* Hover date */
   1.577 +			cells.mouseenter(function(e) {
   1.578 +				if(!_this._mouseDown)
   1.579 +				{
   1.580 +					var date = _this._getDate($(this));
   1.581 +					_this._triggerEvent('mouseOnDay', {
   1.582 +						element: $(this),
   1.583 +						date: date,
   1.584 +						events: _this.getEvents(date)
   1.585 +					});
   1.586 +				}
   1.587 +			});
   1.588 +			
   1.589 +			cells.mouseleave(function(e) {
   1.590 +				var date = _this._getDate($(this));
   1.591 +				_this._triggerEvent('mouseOutDay', {
   1.592 +					element: $(this),
   1.593 +					date: date,
   1.594 +					events: _this.getEvents(date)
   1.595 +				});
   1.596 +			});
   1.597 +			
   1.598 +			/* Responsive management */
   1.599 +			
   1.600 +			setInterval(function() {
   1.601 +				var calendarSize = $(_this.element).width();
   1.602 +				var monthSize = $(_this.element).find('.month').first().width() + 10;
   1.603 +				var monthContainerClass = 'month-container';
   1.604 +				
   1.605 +				if(monthSize * 6 < calendarSize) {
   1.606 +					monthContainerClass += ' col-xs-2';
   1.607 +				}
   1.608 +				else if(monthSize * 4 < calendarSize) {
   1.609 +					monthContainerClass += ' col-xs-3';
   1.610 +				}
   1.611 +				else if(monthSize * 3 < calendarSize) {
   1.612 +					monthContainerClass += ' col-xs-4';
   1.613 +				}
   1.614 +				else if(monthSize * 2 < calendarSize) {
   1.615 +					monthContainerClass += ' col-xs-6';
   1.616 +				}
   1.617 +				else {
   1.618 +					monthContainerClass += ' col-xs-12';
   1.619 +				}
   1.620 +				
   1.621 +				$(_this.element).find('.month-container').attr('class', monthContainerClass);
   1.622 +			}, 300);
   1.623 +		},
   1.624 +		_refreshRange: function () {
   1.625 +			var _this = this;
   1.626 +		
   1.627 +            this.element.find('td.day.range').removeClass('range')
   1.628 +            this.element.find('td.day.range-start').removeClass('range-start');
   1.629 +            this.element.find('td.day.range-end').removeClass('range-end');
   1.630 +
   1.631 +            if (this._mouseDown) {
   1.632 +                var beforeRange = true;
   1.633 +                var afterRange = false;
   1.634 +                var minDate = _this._rangeStart < _this._rangeEnd ? _this._rangeStart : _this._rangeEnd;
   1.635 +                var maxDate = _this._rangeEnd > _this._rangeStart ? _this._rangeEnd : _this._rangeStart;
   1.636 +
   1.637 +                this.element.find('.month-container').each(function () {
   1.638 +					var monthId = $(this).data('month-id');
   1.639 +                    if (minDate.getMonth() <= monthId && maxDate.getMonth() >= monthId) {
   1.640 +                        $(this).find('td.day:not(.old, .new)').each(function () {
   1.641 +                            var date = _this._getDate($(this));
   1.642 +                            if (date >= minDate && date <= maxDate) {
   1.643 +                                $(this).addClass('range');
   1.644 +
   1.645 +                                if (date.getTime() == minDate.getTime()) {
   1.646 +                                    $(this).addClass('range-start');
   1.647 +                                }
   1.648 +
   1.649 +                                if (date.getTime() == maxDate.getTime()) {
   1.650 +                                    $(this).addClass('range-end');
   1.651 +                                }
   1.652 +                            }
   1.653 +                        });
   1.654 +                    }
   1.655 +                });
   1.656 +            }
   1.657 +        },
   1.658 +		_openContextMenu: function(elt) {
   1.659 +			var contextMenu = $('.calendar-context-menu');
   1.660 +			
   1.661 +			if(contextMenu.length > 0) {
   1.662 +				contextMenu.hide();
   1.663 +				contextMenu.empty();
   1.664 +			}
   1.665 +			else {
   1.666 +				contextMenu = $(document.createElement('div'));
   1.667 +				contextMenu.addClass('calendar-context-menu');
   1.668 +				$('body').append(contextMenu);
   1.669 +			}
   1.670 +			
   1.671 +			var date = this._getDate(elt);
   1.672 +			var events = this.getEvents(date);
   1.673 +			
   1.674 +			for(var i in events) {
   1.675 +				var eventItem = $(document.createElement('div'));
   1.676 +				eventItem.addClass('item');
   1.677 +				eventItem.css('border-left', '4px solid ' + events[i].color);
   1.678 +				
   1.679 +				var eventItemContent = $(document.createElement('div'));
   1.680 +				eventItemContent.addClass('content');
   1.681 +				eventItemContent.text(events[i].name);
   1.682 +				
   1.683 +				eventItem.append(eventItemContent);
   1.684 +				
   1.685 +				var icon = $(document.createElement('span'));
   1.686 +				icon.addClass('glyphicon glyphicon-chevron-right');
   1.687 +				
   1.688 +				eventItem.append(icon);
   1.689 +				
   1.690 +				this._renderContextMenuItems(eventItem, this.options.contextMenuItems, events[i]);
   1.691 +				
   1.692 +				contextMenu.append(eventItem);
   1.693 +			}
   1.694 +			
   1.695 +			if(contextMenu.children().length > 0)
   1.696 +			{
   1.697 +				contextMenu.css('left', elt.offset().left + 25 + 'px');
   1.698 +				contextMenu.css('top', elt.offset().top + 25 + 'px');
   1.699 +				contextMenu.show();
   1.700 +				
   1.701 +				$(window).one('mouseup', function() {
   1.702 +					contextMenu.hide();
   1.703 +				});
   1.704 +			}
   1.705 +		},
   1.706 +		_renderContextMenuItems: function(parent, items, evt) {
   1.707 +			var subMenu = $(document.createElement('div'));
   1.708 +			subMenu.addClass('submenu');
   1.709 +			
   1.710 +			for(var i in items) {
   1.711 +				if(!items[i].visible || items[i].visible(evt)) {
   1.712 +					var menuItem = $(document.createElement('div'));
   1.713 +					menuItem.addClass('item');
   1.714 +					
   1.715 +					var menuItemContent = $(document.createElement('div'));
   1.716 +					menuItemContent.addClass('content');
   1.717 +					menuItemContent.text(items[i].text);
   1.718 +					
   1.719 +					menuItem.append(menuItemContent);
   1.720 +					
   1.721 +					if(items[i].click) {
   1.722 +						(function(index) {
   1.723 +							menuItem.click(function() {
   1.724 +								items[index].click(evt);
   1.725 +							});
   1.726 +						})(i);
   1.727 +					}
   1.728 +					
   1.729 +					var icon = $(document.createElement('span'));
   1.730 +					icon.addClass('glyphicon glyphicon-chevron-right');
   1.731 +					
   1.732 +					menuItem.append(icon);
   1.733 +					
   1.734 +					if(items[i].items && items[i].items.length > 0) {
   1.735 +						this._renderContextMenuItems(menuItem, items[i].items, evt);
   1.736 +					}
   1.737 +					
   1.738 +					subMenu.append(menuItem);
   1.739 +				}
   1.740 +			}
   1.741 +			
   1.742 +			if(subMenu.children().length > 0)
   1.743 +			{
   1.744 +				parent.append(subMenu);
   1.745 +			}
   1.746 +		},
   1.747 +		_getColor: function(colorString) {
   1.748 +			var div = $('<div />');
   1.749 +			div.css('color', colorString);
   1.750 +			
   1.751 +		},
   1.752 +		_getDate: function(elt) {
   1.753 +			var day = elt.children('.day-content').text();
   1.754 +			var month = elt.closest('.month-container').data('month-id');
   1.755 +			var year = this.options.startYear;
   1.756 +
   1.757 +			return new Date(year, month, day);
   1.758 +		},
   1.759 +		_triggerEvent: function(eventName, parameters) {
   1.760 +			var event = $.Event(eventName);
   1.761 +			
   1.762 +			for(var i in parameters) {
   1.763 +				event[i] = parameters[i];
   1.764 +			}
   1.765 +			
   1.766 +			this.element.trigger(event);
   1.767 +		},
   1.768 +		getWeekNumber: function(date) {
   1.769 +			var tempDate = new Date(date.getTime());
   1.770 +			tempDate.setHours(0, 0, 0, 0);
   1.771 +			tempDate.setDate(tempDate.getDate() + 3 - (tempDate.getDay() + 6) % 7);
   1.772 +			var week1 = new Date(tempDate.getFullYear(), 0, 4);
   1.773 +			return 1 + Math.round(((tempDate.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
   1.774 +		},
   1.775 +		getEvents: function(date) {
   1.776 +			var events = [];
   1.777 +			
   1.778 +			if(this.options.dataSource && date) {
   1.779 +				for(var i in this.options.dataSource) {
   1.780 +					if(this.options.dataSource[i].startDate <= date && this.options.dataSource[i].endDate >= date) {
   1.781 +						events.push(this.options.dataSource[i]);
   1.782 +					}
   1.783 +				}
   1.784 +			}
   1.785 +			
   1.786 +			return events;
   1.787 +		},
   1.788 +		getYear: function() {
   1.789 +			return this.options.startYear;
   1.790 +		},
   1.791 +		setYear: function(year) {
   1.792 +			var parsedYear = parseInt(year);
   1.793 +			if(!isNaN(parsedYear)) {
   1.794 +				this.options.startYear = parsedYear;
   1.795 +				this._render();
   1.796 +			}
   1.797 +		},
   1.798 +		getMinDate: function() {
   1.799 +			return this.options.minDate;
   1.800 +		},
   1.801 +		setMinDate: function(date) {
   1.802 +			if(date instanceof Date) {
   1.803 +				this.options.minDate = date;
   1.804 +				this._render();
   1.805 +			}
   1.806 +		},
   1.807 +		getMaxDate: function() {
   1.808 +			return this.options.maxDate;
   1.809 +		},
   1.810 +		setMaxDate: function(date) {
   1.811 +			if(date instanceof Date) {
   1.812 +				this.options.maxDate = date;
   1.813 +				this._render();
   1.814 +			}
   1.815 +		},
   1.816 +		getStyle: function() {
   1.817 +			return this.options.style;
   1.818 +		},
   1.819 +		setStyle: function(style) {
   1.820 +			this.options.style = style == 'background' || style == 'border' || style == 'custom' ? style : 'border';
   1.821 +			this._render();
   1.822 +		},
   1.823 +		getAllowOverlap: function() {
   1.824 +			return this.options.allowOverlap;
   1.825 +		},
   1.826 +		setAllowOverlap: function(allowOverlap) {
   1.827 +			this.options.allowOverlap = allowOverlap;
   1.828 +		},
   1.829 +		getDisplayWeekNumber: function() {
   1.830 +			return this.options.displayWeekNumber;
   1.831 +		},
   1.832 +		setDisplayWeekNumber: function(displayWeekNumber) {
   1.833 +			this.options.displayWeekNumber = displayWeekNumber;
   1.834 +			this._render();
   1.835 +		},
   1.836 +		getAlwaysHalfDay: function() {
   1.837 +			return this.options.alwaysHalfDay;
   1.838 +		},
   1.839 +		setAlwaysHalfDay: function(alwaysHalfDay) {
   1.840 +			this.options.alwaysHalfDay = alwaysHalfDay;
   1.841 +			this._render();
   1.842 +		},
   1.843 +		getEnableRangeSelection: function() {
   1.844 +			return this.options.enableRangeSelection;
   1.845 +		},
   1.846 +		setEnableRangeSelection: function(enableRangeSelection) {
   1.847 +			this.options.enableRangeSelection = enableRangeSelection;
   1.848 +			this._render();
   1.849 +		},
   1.850 +		getDisabledDays: function() {
   1.851 +			return this.options.disabledDays;
   1.852 +		},
   1.853 +		setDisabledDays: function(disabledDays) {
   1.854 +			this.options.disabledDays = disabledDays instanceof Array ? disabledDays : [];
   1.855 +			this._render();
   1.856 +		},
   1.857 +		getRoundRangeLimits: function() {
   1.858 +			return this.options.roundRangeLimits;
   1.859 +		},
   1.860 +		setRoundRangeLimits: function(roundRangeLimits) {
   1.861 +			this.options.roundRangeLimits = roundRangeLimits;
   1.862 +			this._render();
   1.863 +		},
   1.864 +		getEnableContextMenu: function() {
   1.865 +			return this.options.enableContextMenu;
   1.866 +		},
   1.867 +		setEnableContextMenu: function(enableContextMenu) {
   1.868 +			this.options.enableContextMenu = enableContextMenu;
   1.869 +			this._render();
   1.870 +		},
   1.871 +		getContextMenuItems: function() {
   1.872 +			return this.options.contextMenuItems;
   1.873 +		},
   1.874 +		setContextMenuItems: function(contextMenuItems) {
   1.875 +			this.options.contextMenuItems = contextMenuItems instanceof Array ? contextMenuItems : [];
   1.876 +			this._render();
   1.877 +		},
   1.878 +		getCustomDayRenderer: function() {
   1.879 +			return this.options.customDayRenderer;
   1.880 +		},
   1.881 +		setCustomDayRenderer: function(customDayRenderer) {
   1.882 +			this.options.customDayRenderer = $.isFunction(customDayRenderer) ? customDayRenderer : null;
   1.883 +			this._render();
   1.884 +		},
   1.885 +		getCustomDataSourceRenderer: function() {
   1.886 +			return this.options.customDataSourceRenderer;
   1.887 +		},
   1.888 +		setCustomDataSourceRenderer: function(customDataSourceRenderer) {
   1.889 +			this.options.customDataSourceRenderer = $.isFunction(customDataSourceRenderer) ? customDataSourceRenderer : null;
   1.890 +			this._render();
   1.891 +		},
   1.892 +		getLanguage: function() {
   1.893 +			return this.options.language;
   1.894 +		},
   1.895 +		setLanguage: function(language) {
   1.896 +			if(language != null && dates[language] != null) {
   1.897 +				this.options.language = language;
   1.898 +				this._render();
   1.899 +			}
   1.900 +		},
   1.901 +		getDataSource: function() {
   1.902 +			return this.options.dataSource;
   1.903 +		},
   1.904 +		setDataSource: function(dataSource) {
   1.905 +			this.options.dataSource = dataSource instanceof Array ? dataSource : [];
   1.906 +			this._initializeDatasourceColors();
   1.907 +			this._render();
   1.908 +		},
   1.909 +		addEvent: function(evt) {
   1.910 +			this.options.dataSource.push(evt);
   1.911 +			this._render();
   1.912 +		}
   1.913 +	}
   1.914 + 
   1.915 +	$.fn.calendar = function (options) {
   1.916 +		var calendar = new Calendar($(this) ,options);
   1.917 +		$(this).data('calendar', calendar);
   1.918 +		return calendar;
   1.919 +	}
   1.920 +	
   1.921 +	/* Events binding management */
   1.922 +	$.fn.renderEnd = function(fct) { $(this).bind('renderEnd', fct); }
   1.923 +	$.fn.clickDay = function(fct) { $(this).bind('clickDay', fct); }
   1.924 +	$.fn.dayContextMenu = function(fct) { $(this).bind('dayContextMenu', fct); }
   1.925 +	$.fn.selectRange = function(fct) { $(this).bind('selectRange', fct); }
   1.926 +	$.fn.mouseOnDay = function(fct) { $(this).bind('mouseOnDay', fct); }
   1.927 +	$.fn.mouseOutDay = function(fct) { $(this).bind('mouseOutDay', fct); }
   1.928 +	
   1.929 +	var dates = $.fn.calendar.dates = {
   1.930 +		en: {
   1.931 +			days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
   1.932 +			daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
   1.933 +			daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
   1.934 +			months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
   1.935 +			monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
   1.936 +			weekShort: 'W',
   1.937 +			weekStart:0
   1.938 +		}
   1.939 +	};
   1.940 +	
   1.941 +	var colors = $.fn.calendar.colors = ['#2C8FC9', '#9CB703', '#F5BB00', '#FF4A32', '#B56CE2', '#45A597'];
   1.942 +	
   1.943 +	$(function(){
   1.944 +		$('[data-provide="calendar"]').each(function() {
   1.945 +			$(this).calendar();
   1.946 +		});
   1.947 +	});
   1.948 + }(window.jQuery));
   1.949 \ No newline at end of file