PageSourceSearch

https://www.stoporganharvesting.org/wp-content/themes/philanthropy-parent/js/calendar/calendar.js?ver=7.1.2

js stoporganharvesting.org collected 2026-10-03 19:55:35 UTC 35,432 bytes, 1,194 lines download raw bytes

1/**
2 * Bootstrap based calendar full view.
3 *
4 * https://github.com/Serhioromano/bootstrap-calendar
5 *
6 * User: Sergey Romanov <[email protected]>
7 */
8"use strict";
9
10Date.prototype.getWeek = function() {
11	var onejan = new Date(this.getFullYear(), 0, 1);
12	return Math.ceil((((this.getTime() - onejan.getTime()) / 86400000) + onejan.getDay() + 1) / 7);
13};
14Date.prototype.getMonthFormatted = function() {
15	var month = this.getMonth() + 1;
16	return month < 10 ? '0' + month : month;
17};
18Date.prototype.getDateFormatted = function() {
19	var date = this.getDate();
20	return date < 10 ? '0' + date : date;
21};
22if(!String.prototype.format) {
23	String.prototype.format = function() {
24		var args = arguments;
25		return this.replace(/{(\d+)}/g, function(match, number) {
26			return typeof args[number] != 'undefined' ? args[number] : match;
27		});
28	};
29}
30if(!String.prototype.formatNum) {
31	String.prototype.formatNum = function(decimal) {
32		var r = "" + this;
33		while(r.length < decimal)
34			r = "0" + r;
35		return r;
36	};
37}
38
39
40(function($) {
41
42	var defaults = {
43		// Width of the calendar
44		width:              '100%',
45		// Initial view (can be 'month', 'week', 'day')
46		view:               'month',
47		// Initial date. No matter month, week or day this will be a starting point. Can be 'now' or a date in format 'yyyy-mm-dd'
48		day:                'now',
49		// Day Start time and end time with time intervals. Time split 10, 15 or 30.
50		time_start:         '06:00',
51		time_end:           '22:00',
52		time_split:         '30',
53		// Source of events data. It can be one of the following:
54		// - URL to return JSON list of events in special format.
55		//   {success:1, result: [....]} or for error {success:0, error:'Something terrible happened'}
56		//   events: [...] as described in events property description
57		//   The start and end variables will be sent to this url
58		// - A function that received the start and end date, and that
59		//   returns an array of events (as described in events property description)
60		// - An array containing the events
61		events_source:      '',
62		// Path to templates should end with slash /. It can be as relative
63		// /component/bootstrap-calendar/tmpls/
64		// or absolute
65		// http://localhost/component/bootstrap-calendar/tmpls/
66		tmpl_path:          'Calendar/tmpls/',
67		tmpl_cache:         true,
68		classes:            {
69			months: {
70				inmonth:  'cal-day-inmonth',
71				outmonth: 'cal-day-outmonth',
72				saturday: 'cal-day-weekend',
73				sunday:   'cal-day-weekend',
74				holidays: 'cal-day-holiday',
75				today:    'cal-day-today'
76			},
77			week:   {
78				workday:  'cal-day-workday',
79				saturday: 'cal-day-weekend',
80				sunday:   'cal-day-weekend',
81				holidays: 'cal-day-holiday',
82				today:    'cal-day-today'
83			}
84		},
85		// ID of the element of modal window. If set, events URLs will be opened in modal windows.
86		modal:              null,
87		//	modal handling setting, one of "iframe", "ajax" or "template"
88		modal_type:         "iframe",
89		//	function to set modal title, will be passed the event as a parameter
90		modal_title:        null,
91		views:              {
92			year:  {
93				slide_events: 1,
94				enable:       1
95			},
96			month: {
97				slide_events: 1,
98				enable:       1
99			},
100			week:  {
101				enable: 1
102			},
103			day:   {
104				enable: 1
105			}
106		},
107		merge_holidays:     false,
108		// ------------------------------------------------------------
109		// CALLBACKS. Events triggered by calendar class. You can use
110		// those to affect you UI
111		// ------------------------------------------------------------
112		onAfterEventsLoad:  function(events) {
113			// Inside this function 'this' is the calendar instance
114		},
115		onBeforeEventsLoad: function(next) {
116			// Inside this function 'this' is the calendar instance
117			next();
118		},
119		onAfterViewLoad:    function(view) {
120			// Inside this function 'this' is the calendar instance
121		},
122		onAfterModalShown:  function(events) {
123			// Inside this function 'this' is the calendar instance
124		},
125		onAfterModalHidden: function(events) {
126			// Inside this function 'this' is the calendar instance
127		},
128		// -------------------------------------------------------------
129		// INTERNAL USE ONLY. DO NOT ASSIGN IT WILL BE OVERRIDDEN ANYWAY
130		// -------------------------------------------------------------
131		events:             [],
132		templates:          {
133			year:  '',
134			month: '',
135			week:  '',
136			day:   ''
137		},
138		stop_cycling:       false
139	};
140
141	var defaults_extended = {
142		first_day: 2,
143		holidays:  {
144			// January 1
145			'01-01':  "New Year's Day",
146			// Third (+3*) Monday (1) in January (01)
147			'01+3*1': "Birthday of Dr. Martin Luther King, Jr.",
148			// Third (+3*) Monday (1) in February (02)
149			'02+3*1': "Washington's Birthday",
150			// Last (-1*) Monday (1) in May (05)
151			'05-1*1': "Memorial Day",
152			// July 4
153			'04-07':  "Independence Day",
154			// First (+1*) Monday (1) in September (09)
155			'09+1*1': "Labor Day",
156			// Second (+2*) Monday (1) in October (10)
157			'10+2*1': "Columbus Day",
158			// November 11
159			'11-11':  "Veterans Day",
160			// Fourth (+4*) Thursday (4) in November (11)
161			'11+4*4': "Thanksgiving Day",
162			// December 25
163			'25-12':  "Christmas"
164		}
165	};
166
167	var strings = {
168		error_noview:     'Calendar: View {0}
168 not found',
169		error_dateformat: 'Calendar: Wrong date format {0}. Should be either "now" or "yyyy-mm-dd"',
170		error_loadurl:    'Calendar: Event URL is not set',
171		error_where:      'Calendar: Wrong navigation direction {0}. Can be only "next" or "prev" or "today"',
172		error_timedevide: 'Calendar: Time split parameter should divide 60 without decimals. Something like 10, 15, 30',
173
174		no_events_in_day: 'No events in this day.',
175
176		title_year:  '{0}',
177		title_month: '{0} {1}',
178		title_week:  'week {0} of {1}',
179		title_day:   '{0} {1} {2}, {3}',
180
181		week:        'Week {0}',
182		all_day:     'All day',
183		time:        'Time',
184		events:      'Events',
185		before_time: 'Ends before timeline',
186		after_time:  'Starts after timeline',
187
188
189		m0:  'January',
190		m1:  'February',
191		m2:  'March',
192		m3:  'April',
193		m4:  'May',
194		m5:  'June',
195		m6:  'July',
196		m7:  'August',
197		m8:  'September',
198		m9:  'October',
199		m10: 'November',
200		m11: 'December',
201
202		ms0:  'Jan',
203		ms1:  'Feb',
204		ms2:  'Mar',
205		ms3:  'Apr',
206		ms4:  'May',
207		ms5:  'Jun',
208		ms6:  'Jul',
209		ms7:  'Aug',
210		ms8:  'Sep',
211		ms9:  'Oct',
212		ms10: 'Nov',
213		ms11: 'Dec',
214
215		d0: 'Sun',
216		d1: 'Mon',
217		d2: 'Tue',
218		d3: 'Wed',
219		d4: 'Thu',
220		d5: 'Fri',
221		d6: 'Sat'
222	};
223
224    var string = jQuery.extend(strings, tf_calendar.datepicker_opts);
225
226	var browser_timezone = '';
227	try {
228		if($.type(window.jstz) == 'object' && $.type(jstz.determine) == 'function') {
229			browser_timezone = jstz.determine().name();
230			if($.type(browser_timezone) !== 'string') {
231				browser_timezone = '';
232			}
233		}
234	}
235	catch(e) {
236	}
237
238	function buildEventsUrl(events_url, data) {
239		var separator, key, url;
240		url = events_url;
241		separator = (events_url.indexOf('?') < 0) ? '?' : '&';
242		for(key in data) {
243			url += separator + key + '=' + encodeURIComponent(data[key]);
244			separator = '&';
245		}
246		return url;
247	}
248
249	function getExtentedOption(cal, option_name) {
250		var fromOptions = (cal.options[option_name] != null) ? cal.options[option_name] : null;
251		var fromLanguage = (cal.locale[option_name] != null) ? cal.locale[option_name] : null;
252		if((option_name == 'holidays') && cal.options.merge_holidays) {
253			var holidays = {};
254			$.extend(true, holidays, fromLanguage ? fromLanguage : defaults_extended.holidays);
255			if(fromOptions) {
256				$.extend(true, holidays, fromOptions);
257			}
258			return holidays;
259		}
260		else {
261			if(fromOptions != null) {
262				return fromOptions;
263			}
264			if(fromLanguage != null) {
265				return fromLanguage;
266			}
267			return defaults_extended[option_name];
268		}
269	}
270
271	function getHolidays(cal, year) {
272		var hash = [];
273		var holidays_def = getExtentedOption(cal, 'holidays');
274		for(var k in holidays_def) {
275			hash.push(k + ':' + holidays_def[k]);
276		}
277		hash.push(year);
278		hash = hash.join('|');
279		if(hash in getHolidays.cache) {
280			return getHolidays.cache[hash];
281		}
282		var holidays = [];
283		$.each(holidays_def, function(key, name) {
284			var firstDay = null, lastDay = null, failed = false;
285			$.each(key.split('>'), function(i, chunk) {
286				var m, date = null;
287				if(m = /^(\d\d)-(\d\d)$/.exec(chunk)) {
288					date = new Date(year, parseInt(m[2], 10) - 1, parseInt(m[1], 10));
289				}
290				else if(m = /^(\d\d)-(\d\d)-(\d\d\d\d)$/.exec(chunk)) {
291					if(parseInt(m[3], 10) == year) {
292						date = new Date(year, parseInt(m[2], 10) - 1, parseInt(m[1], 10));
293					}
294				}
295				else if(m = /^easter(([+\-])(\d+))?$/.exec(chunk)) {
296					date = getEasterDate(year, m[1] ? parseInt(m[1], 10) : 0);
297				}
298				else if(m = /^(\d\d)([+\-])([1-5])\*([0-6])$/.exec(chunk)) {
299					var month = parseInt(m[1], 10) - 1;
300					var direction = m[2];
301					var offset = parseInt(m[3]);
302					var weekday = parseInt(m[4]);
303					switch(direction) {
304						case '+':
305							var d = new Date(year, month, 1 - 7);
306							while(d.getDay() != weekday) {
307								d = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1);
308							}
309							date = new Date(d.getFullYear(), d.getMonth(), d.getDate() + 7 * offset);
310							break;
311						case '-':
312							var d = new Date(year, month + 1, 0 + 7);
313							while(d.getDay() != weekday) {
314								d = new Date(d.getFullYear(), d.getMonth(), d.getDate() - 1);
315							}
316							date = new Date(d.getFullYear(), d.getMonth(), d.getDate() - 7 * offset);
317							break;
318					}
319				}
320				if(!date) {
321					warn('Unknown holiday: ' + key);
322					failed = true;
323					return false;
324				}
325				switch(i) {
326					case 0:
327						firstDay = date;
328						break;
329					case 1:
330						if(date.getTime() <= firstDay.getTime()) {
331							warn('Unknown holiday: ' + key);
332							failed = true;
333							return false;
334						}
335						lastDay = date;
336						break;
337					default:
338						warn('Unknown holiday: ' + key);
339						failed = true;
340						return false;
341				}
342			});
343			if(!failed) {
344				var days = [];
345				if(lastDay) {
346					for(var date = new Date(firstDay.getTime()); date.getTime() <= lastDay.getTime(); date.setDate(date.getDate() + 1)) {
347						days.push(new Date(date.getTime()));
348					}
349				}
350				else {
351					days.push(firstDay);
352				}
353				holidays.push({name: name, days: days});
354			}
355		});
356		getHolidays.cache[hash] = holidays;
357		return getHolidays.cache[hash];
358	}
359
360	getHolidays.cache = {};
361
362	function warn(message) {
363		if($.type(window.console) == 'object' && $.type(window.console.warn) == 'function') {
364			window.console.warn('[Bootstrap-Calendar] ' + message);
365		}
366	}
367
368	function Calendar(params, context) {
369		this.options = $.extend(true, {position: {start: new Date(), end: new Date()}}, defaults, params);
370		this.setLanguage(this.options.language);
371		this.context = context;
372
373		context.css('width', this.options.width).addClass('cal-context');
374
375		this.view();
376		return this;
377	}
378
379	Calendar.prototype.setOptions = function(object) {
380		$.extend(this.options, object);
381		if('language' in object) {
382			this.setLanguage(object.language);
383		}
384		if('modal' in object) {
385			this._update_modal();
386		}
387	}
388
389	Calendar.prototype.setLanguage = function(lang) {
390		if(window.calendar_languages && (lang in window.calendar_languages)
390) {
391			this.locale = $.extend(true, {}, strings, calendar_languages[lang]);
392			this.options.language = lang;
393		} else {
394			this.locale = strings;
395			delete this.options.language;
396		}
397	}
398
399	Calendar.prototype._render = function() {
400		this.context.html('');
401		this._loadTemplate(this.options.view);
402		this.stop_cycling = false;
403
404		var data = {};
405		data.cal = this;
406		data.day = 1;
407
408		// Getting list of days in a week in correct order. Works for month and week views
409		if(getExtentedOption(this, 'first_day') == 1) {
410			data.months = [this.locale.d1, this.locale.d2, this.locale.d3, this.locale.d4, this.locale.d5, this.locale.d6, this.locale.d0]
411		} else {
412			data.months = [this.locale.d0, this.locale.d1, this.locale.d2, this.locale.d3, this.locale.d4, this.locale.d5, this.locale.d6]
413		}
414
415		// Get all events between start and end
416		var start = parseInt(this.options.position.start.getTime());
417		var end = parseInt(this.options.position.end.getTime());
418
419		data.events = this.getEventsBetween(start, end);
420
421		switch(this.options.view) {
422			case 'month':
423				break;
424			case 'week':
425				this._calculate_hour_minutes(data);
426				break;
427			case 'day':
428				this._calculate_hour_minutes(data);
429				break;
430		}
431
432		data.start = new Date(this.options.position.start.getTime());
433		data.lang = this.locale;
434
435		this.context.append(this.options.templates[this.options.view](data));
436		this._update();
437	};
438
439	Calendar.prototype._calculate_hour_minutes = function(data) {
440		var $self = this;
441		data.in_hour = 60 / parseInt(this.options.time_split);
442		data.hour_split = parseInt(this.options.time_split);
443
444		if(!/^\d+$/.exec(data.in_hour) || this.options.time_split > 30) {
445			$.error(this.locale.error_timedevide);
446		}
447
448		var time_start = this.options.time_start.split(":");
449		var time_end = this.options.time_end.split(":");
450
451		data.hours = (parseInt(time_end[0]) - parseInt(time_start[0]));
452		var lines = data.hours * data.in_hour;
453		var ms_per_line = (60000 * parseInt(this.options.time_split));
454
455		var start = new Date(this.options.position.start.getTime());
456		start.setHours(time_start[0]);
457		start.setMinutes(time_start[1]);
458		var end = new Date(this.options.position.start.getTime());
459		end.setHours(time_end[0]);
460		end.setMinutes(time_end[1]);
461
462		data.all_day = [];
463		data.by_hour = [];
464		data.after_time = [];
465		data.before_time = [];
466		$.each(data.events, function(k, e) {
467			var s = new Date(parseInt(e.start));
468			var f = new Date(parseInt(e.end));
469
470			e.start_hour = s.getHours().toString().formatNum(2) + ':' + s.getMinutes().toString().formatNum(2);
471			e.end_hour = f.getHours().toString().formatNum(2) + ':' + f.getMinutes().toString().formatNum(2);
472
473			if(e.start < start.getTime()) {
474				warn(1);
475				e.start_hour = s.getDate() + ' ' + $self.locale['ms' + s.getMonth()] + ' ' + e.start_hour;
476			}
477
478			if(e.end > end.getTime()) {
479				warn(1);
480				e.end_hour = f.getDate() + ' ' + $self.locale['ms' + f.getMonth()] + ' ' + e.end_hour;
481			}
482
483			if(e.start < start.getTime() && e.end > end.getTime()) {
484				data.all_day.push(e);
485				return;
486			}
487
488			if(e.end < start.getTime()) {
489				data.before_time.push(e);
490				return;
491			}
492
493			if(e.start > end.getTime()) {
494				data.after_time.push(e);
495				return;
496			}
497
498			var event_start = start.getTime() - e.start;
499
500			if(event_start >= 0) {
501				e.top = 0;
502			} else {
503				e.top = Math.abs(event_start) / ms_per_line;
504			}
505
506			var lines_left = lines - e.top;
507			var lines_in_event = (e.end - e.start) / ms_per_line;
508			if(event_start >= 0) {
509				lines_in_event = (e.end - start.getTime()) / ms_per_line;
510			}
511
512
513			e.lines = lines_in_event;
514			if(lines_in_event > lines_left) {
515				e.lines = lines_left;
516			}
517
518			data.by_hour.push(e);
519		});
520
521		//var d = new Date('2013-03-14 13:20:00');
522		//warn(d.getTime());
523	};
524
525	Calendar.prototype._hour = function(hour, part) {
526		var time_start = this.options.time_start.split(":");
527
528		var hour = "" + (parseInt(time_start[0]) + hour);
529		var minute = "" + (this.options.time_split * part);
530
531		return hour.formatNum(2) + ":" + minute.formatNum(2);
532	}
533
534	Calendar.prototype._week = function(event) {
535		this._loadTemplate('week-days');
536
537		var t = {};
538		var start = parseInt(this.options.position.start.getTime());
539		var end = parseInt(this.options.position.end.getTime());
540		var events = [];
541		var self = this;
542		var first_day = getExtentedOption(this, 'first_day');
543
544		$.each(this.getEventsBetween(start, end), function(k, event) {
545			event.start_day = new Date(parseInt(event.start)).getDay();
546			if(first_day == 1) {
547				event.start_day = (event.start_day + 6) % 7;
548			}
549			if((event.end - event.start) <= 86400000) {
550				event.days = 1;
551			} else {
552				event.days = ((event.end - event.start) / 86400000);
553			}
554
555			if(event.start < start) {
556
557				event.days = event.days - ((start - event.start) / 86400000);
558				event.start_day = 0;
559			}
560
561			event.days = Math.ceil(event.days);
562
563			if(event.start_day + event.days > 7) {
564				event.days = 7 - (event.start_day);
565			}
566
567			events.push(event);
568		});
569		t.events = events;
570		t.cal = this;
571		return self.options.templates['week-days'](t);
572	}
573
574	Calendar.prototype._month = function(month) {
575		this._loadTemplate('year-month');
576
577		var t = {cal: this};
578		var newmonth = month + 1;
579		t.data_day = this.options.position.start.getFullYear() + '-' + (newmonth < 10 ? '0' + newmonth : newmonth) + '-' + '01';
580		t.month_name = this.locale['m' + month];
581
582		var curdate = new Date(this.options.position.start.getFullYear(), month, 1, 0, 0, 0);
583		t.start = parseInt(curdate.getTime());
584		t.end = parseInt(new Date(this.options.position.start.getFullYear(), month + 1, 1, 0, 0, 0).getTime());
585		t.events = this.getEventsBetween(t.start, t.end);
586		return this.options.templates['year-month'](t);
587	}
588
589	Calendar.prototype._day = function(week, day) {
590		this._loadTemplate('month-day');
591
592		var t = {tooltip: '', cal: this};
593		var cls = this.options.classes.months.outmonth;
594
595		var firstday = this.options.position.start.getDay();
596		if(getExtentedOption(this, 'first_day') == 2) {
597			firstday++;
598		} else {
599			firstday = (firstday == 0 ? 7 : firstday);
600		}
601
602		day = (day - firstday) + 1;
603		var curdate = new Date(this.options.position.start.getFullYear(), this.options.position.start.getMonth(), day, 0, 0, 0);
604
605		// if day of the current month
606		if(day > 0) {
607			cls = this.options.classes.months.inmonth;
608		}
609		// stop cycling table rows;
610		var daysinmonth = (new Date(this.options.position.end.getTime() - 1)).getDate();
611		if((day + 1) > daysinmonth) {
612			this.stop_cycling = true;
613		}
614		// if day of the next month
615		if(day > daysinmonth) {
616			day = day - daysinmonth;
617			cls = this.options.classes.months.outmonth;
618		}
619
620		cls = $.trim(cls + " " + this._getDayClass("months", curdate));
621
622		if(day <= 0) {
623			var daysinprevmonth = (new Date(this.options.position.start.getFullYear(), this.options.position.start.getMonth(), 0)).getDate();
624			day = daysinprevmonth - Math.abs(day);
625			cls += ' cal-month-first-row';
626		}
627
628		var holiday = this._getHoliday(curdate);
629		if(holiday !== false) {
630			t.tooltip = holiday;
631		}
632
633		t.data_day = curdate.getFullYear() + '-' + curdate.getMonthFormatted() + '-' + (day < 10 ? '0' + day : day);
634		t.cls = cls;
635		t.day = day;
636
637		t.start = parseInt(curdate.getTime());
638		t.end = parseInt(t.start + 86400000);
639		t.events = this.getEventsBetween(t.start, t.end);
640		return this.options.templates['month-day'](t);
641	}
642
643	Calendar.prototype._getHoliday = function(date) {
644		var result = false;
645		$.each(getHolidays(this, date.getFullYear()), function() {
646			var found = false;
647			$.each(this.days, function() {
648				if(this.toDateString() == date.toDateString()) {
649					found = true;
650					return false;
651				}
652			});
653			if(found) {
654				result = this.name;
655				return false;
656			}
657		});
658		return result;
659	};
660
661	Calendar.prototype._getHolidayName = function(date) {
662		var holiday = this._getHoliday(date);
663		return (holiday === false) ? "" : holiday;
664	};
665
666	Calendar.prototype._getDayClass = function(class_group, date) {
667		var self = this;
668		var addClass = function(which, to) {
669			var cls;
670			cls = (self.options.classes && (class_group in self.options.classes) && (which in self.options.classes[class_group])) ? self.options.classes[class_group][which] : "";
671			if((typeof(cls) == "string") && cls.length) {
672				to.push(cls);
673			}
674		};
675		var classes = [];
676		if(date.toDateString() == (new Date()).toDateString()) {
677			addClass("today", classes);
678		}
679		var holiday = this._getHoliday(date);
680		if(holiday !== false) {
681			addClass("holidays", classes);
682		}
683		switch(date.getDay()) {
684			case 0:
685				addClass("sunday", classes);
686				break;
687			case 6:
688				addClass("saturday", classes);
689				break;
690		}
691
692		addClass(date.toDateString(), classes);
693
694		return classes.join(" ");
695	};
696
697	Calendar.prototype.view = function(view) {
698		if(view) {
699			if(!this.options.views[view].enable) {
700				return;
701			}
702			this.options.view = view;
703		}
704
705
706		this._init_position();
707		this._loadEvents();
708		this._render();
709
710		this.options.onAfterViewLoad.call(this, this.options.view);
711	};
712
713	Calendar.prototype.navigate = function(where, next) {
714		var to = $.extend({}, this.options.position);
715		if(where == 'next') {
716			switch(this.options.view) {
717				case 'year':
718					to.start.setFullYear(this.options.position.start.getFullYear() + 1);
719					break;
720				case 'month':
721					to.start.setMonth(this.options.position.start.getMonth() + 1);
722					break;
723				case 'week':
724					to.start.setDate(this.options.position.start.getDate() + 7);
725					break;
726				case 'day':
727					to.start.setDate(this.options.position.start.getDate() + 1);
728					break;
729			}
730		} else if(where == 'prev') {
731			switch(this.options.view) {
732				case 'year':
733					to.start.setFullYear(this.options.position.start.getFullYear() - 1);
734					break;
735				case 'month':
736					to.start.setMonth(this.options.position.start.getMonth() - 1);
737					break;
738				case 'week':
739					to.start.setDate(this.options.position.start.getDate() - 7);
740					break;
741				case 'day':
742					to.start.setDate(this.options.position.start.getDate() - 1);
743					break;
744			}
745		} else if(where == 'today') {
746			to.start.setTime(new Date().getTime());
747		}
748		else {
749			$.error(this.locale.error_where.format(where))
750		}
751		this.options.day = to.start.getFullYear() + '-' + to.start.getMonthFormatted() + '-' + to.start.getDateFormatted();
752		this.view();
753		if(_.isFunction(next)) {
754			next();
755		}
756	};
757
758	Calendar.prototype._init_position = function() {
759		var year, month, day;
760
761		if(this.options.day == 'now') {
762			var date = new Date();
763			year = date.getFullYear();
764			month = date.getMonth();
765			day = date.getDate();
766		} else if(this.options.day.match(/^\d{4}-\d{2}-\d{2}$/g)) {
767			var list = this.options.day.split('-');
768			year = parseInt(list[0], 10);
769			month = parseInt(list[1], 10) - 1;
770			day = parseInt(list[2], 10);
771		}
772		else {
773			$.error(this.locale.error_dateformat.format(this.options.day));
774		}
775
776		switch(this.options.view) {
777			case 'year':
778				this.options.position.start.setTime(new Date(year, 0, 1).getTime());
779				this.options.position.end.setTime(new Date(year + 1, 0, 1).getTime());
780				break;
781			case 'month':
782				this.options.position.start.setTime(new Date(year, month, 1).getTime());
783				this.options.position.end.setTime(new Date(year, month + 1, 1).getTime());
784				break;
785			case 'day':
786				this.options.position.start.setTime(new Date(year, month, day).getTime());
787				this.options.position.end.setTime(new Date(year, month, day + 1).getTime());
788				break;
789			case 'week':
790				var curr = new Date(year, month, day);
791				var first;
792				if(getExtentedOption(this, 'first_day') == 1) {
793					first = curr.getDate() - ((curr.getDay() + 6) % 7);
794				}
795				else {
796					first = curr.getDate() - curr.getDay();
797				}
798				this.options.position.start.setTime(new Date(year, month, first).getTime());
799				this.options.position.end.setTime(new Date(year, month, first + 7).getTime());
800				break;
801			default:
802				$.error(this.locale.error_noview.format(this.options.view))
803		}
804		return this;
805	};
806
807	Calendar.prototype.getTitle = function() {
808		var p = this.options.position.start;
809		switch(this.options.view) {
810			case 'year':
811				return this.locale.title_year.format(p.getFullYear());
812				break;
813			case 'month':
814				return this.locale.title_month.format(this.locale['m' + p.getMonth()], p.getFullYear());
815				break;
816			case 'week':
817				return this.locale.title_week.format(p.getWeek(), p.getFullYear());
818				break;
819			case 'day':
820				return this.locale.title_day.format(this.locale['d' + p.getDay()], p.getDate(), this.locale['m' + p.getMonth()], p.getFullYear());
821				break;
822		}
823		return;
824	};
825
826	Calendar.prototype.isToday = function() {
827		var now = new Date().getTime();
828
829		return ((now > this.options.position.start) && (now < this.options.position.end));
830	}
831
832	Calendar.prototype.getStartDate = function() {
833		return this.options.position.start;
834	}
835
836	Calendar.prototype.getEndDate = function() {
837		return this.options.position.end;
838	}
839
840	Calendar.prototype._loadEvents = function() {
841		var self = this;
842		var source = null;
843		if('events_source' in this.options && this.options.events_source !== '') {
844			source = this.options.events_source;
845		}
846		else if('events_url' in this.options) {
847			source = this.options.events_url;
848			warn('The events_url option is DEPRECATED and it will be REMOVED in near future. Please use events_source instead.');
849		}
850		var loader;
851		switch($.type(source)) {
852			case 'function':
853				loader = function() {
854					return source(self.options.position.start, self.options.position.end, browser_timezone);
855				};
856				break;
857			case 'array':
858				loader = function() {
859					return [].concat(source);
860				};
861				break;
862			case 'string':
863				if(source.length) {
864					loader = function() {
865						var events = [];
866						var params = {from: self.options.position.start.getTime(), to: self.options.position.end.getTime()};
867						if(browser_timezone.length) {
868							params.browser_timezone = browser_timezone;
869						}
870						$.ajax({
871							url:      buildEventsUrl(source, params),
872							dataType: 'json',
873							type:     'GET',
874							async:    false
875						}).done(function(json) {
876							if(!json.success) {
877								$.error(json.error);
878							}
879							if(json.result) {
880								events = json.result;
881							}
882						});
883						return events;
884					};
885				}
886				break;
887		}
888		if(!loader) {
889			$.error(this.locale.error_loadurl);
890		}
891		this.options.onBeforeEventsLoad.call(this, function() {
892			self.options.events = loader();
893			self.options.events.sort(function(a, b) {
894				var delta;
895				delta = a.start - b.start;
896				if(delta == 0) {
897					delta = a.end - b.end;
898				}
899				return delta;
900			});
901			self.options.onAfterEventsLoad.call(self, self.options.events);
902		});
903	};
904
905	Calendar.prototype._templatePath = function(name) {
906		if(typeof this.options.tmpl_path == 'function') {
907			return this.options.tmpl_path(name)
908		}
909		else {
910			return this.options.tmpl_path + name + '.html';
911		}
912	};
913
914	Calendar.prototype._loadTemplate = function(name) {
915		if(this.options.templates[name]) {
916			return;
917		}
918		var self = this;
919		$.ajax({
920			url:      self._templatePath(name),
921			dataType: 'html',
922			type:     'GET',
923			async:    false,
924			cache:    this.options.tmpl_cache
925		}).done(function(html) {
926			self.options.templates[name] = _.template(html);
927		});
928	};
929
930	Calendar.prototype._update = function() {
931		var self = this;
932
933		$('*[data-toggle="tooltip"]').tooltip({container: 'body'});
934
935		/*$('*[data-cal-date]').click(function() {
936			var view = $(this).data('cal-view');
937			self.options.day = $(this).data('cal-date');
938			self.view(view);
939		});
940		$('.cal-cell').dblclick(function() {
941			var view = $('[data-cal-date]', this).data('cal-view');
942			self.options.day = $('[data-cal-date]', this).data('cal-date');
943			self.view(view);
944		});*/
945
946		this['_update_' + this.options.view]();
947
948		this._update_modal();
949
950	};
951
952	Calendar.prototype._update_modal = function() {
953		var self = this;
954
955		$('a[data-event-id]', this.context).unbind('click');
956
957		if(!self.options.modal) {
958			return;
959		}
960
961		var modal = $(self.options.modal);
962
963		if(!modal.length) {
964			return;
965		}
966
967		var ifrm = null;
968		if(self.options.modal_type == "iframe") {
969			ifrm = $(document.createElement("iframe"))
970				.attr({
971					width:       "100%",
972					frameborder: "0"
973				});
974		}
975
976
977		$('a[data-event-id]', this.context).on('click', function(event) {
978			event.preventDefault();
979			event.stopPropagation();
980
981			var url = $(this).attr('href');
982			var id = $(this).data("event-id");
983			var event = _.find(self.options.events, function(event) {
984				return event.id == id
985			});
986
987			if(self.options.modal_type == "iframe") {
988				ifrm.attr('src', url);
989				$('.modal-body', modal).html(ifrm);
990			}
991
992			if(!modal.data('handled.bootstrap-calendar') || (modal.data('handled.bootstrap-calendar') && modal.data('handled.event-id') != event.id)) {
993				modal
994					.on('show.bs.modal', function() {
995						var modal_body = $(this).find('.modal-body');
996						switch(self.options.modal_type) {
997							case "iframe" :
998								var height = modal_body.height() - parseInt(modal_body.css('padding-top'), 10) - parseInt(modal_body.css('padding-bottom'), 10);
999								$(this).find('iframe').height(Math.max(height, 50));
1000								break;
1001
1002							case "ajax":
1003								$.ajax({url: url, dataType: "html", async: false, success: function(data) {
1004									modal_body.html(data);
1005								}});
1006								break;
1007
1008							case "template":
1009								self._loadTemplate("modal");
1010								//	also serve calendar instance to underscore template to be able to access current language strings
1011								modal_body.html(self.options.templates["modal"]({"event": event, "calendar": self}))
1012								break;
1013						}
1014
1015						//	set the title of the bootstrap modal
1016						if(_.isFunction(self.options.modal_title)) {
1017							modal.find("h3").html(self.options.modal_title(event));
1018						}
1019					})
1020					.on('shown.bs.modal', function() {
1021						self.options.onAfterModalShown.call(self, self.options.events);
1022					})
1023					.on('hidden.bs.modal', function() {
1024						self.options.onAfterModalHidden.call(self, self.options.events);
1025					})
1026					.data('handled.bootstrap-calendar', true).data('handled.event-id', event.id);
1027			}
1028			modal.modal('show');
1029		});
1030	};
1031
1032	Calendar.prototype._update_day = function() {
1033		$('#cal-day-panel').height($('#cal-day-panel-hour').height());
1034	};
1035
1036	Calendar.prototype._update_week = function() {
1037	};
1038
1039	Calendar.prototype._update_year = function() {
1040		this._update_month_year();
1041	};
1042
1043	Calendar.prototype._update_month = function() {
1044		this._update_month_year();
1045
1046		var self = this;
1047
1048		var week = $(document.createElement('div')).attr('id', 'cal-week-box');
1049		var start = this.options.position.start.getFullYear() + '-' + this.options.position.start.getMonthFormatted() + '-';
1050		$('.cal-month-box .cal-row-fluid')
1051			.on('mouseenter', function() {
1052				var p = new Date(self.options.position.start);
1053				var child = $('.cal-cell1:first-child .cal-month-day', this);
1054				var day = (child.hasClass('cal-month-first-row') ? 1 : $('[data-cal-date]', child).text());
1055				p.setDate(parseInt(day));
1056				day = (day < 10 ? '0' + day : day);
1057				week.html(self.locale.week.format(p.getWeek()));
1058				week.attr('data-cal-week', start + day).show().appendTo(child);
1059			})
1060			.on('mouseleave', function() {
1061				week.hide();
1062			})
1063		;
1064
1065		week.click(function() {
1066			self.options.day = $(this).data('cal-week');
1067			self.view('week');
1068		});
1069
1070		$('a.event').mouseenter(function() {
1071			$('a[data-event-id="' + $(this).data('event-id') + '"]').closest('.cal-cell1').addClass('day-highlight dh-' + $(this).data('event-class'));
1072		});
1073		$('a.event').mouseleave(function() {
1074			$('div.cal-cell1').removeClass('day-highlight dh-' + $(this).data('event-class'));
1075		});
1076	};
1077
1078	Calendar.prototype._update_month_year = function() {
1079		if(!this.options.views[this.options.view].slide_events) {
1080			return;
1081		}
1082		var self = this;
1083		var activecell = 0;
1084		var downbox = $(document.createElement('div')).attr('id', 'cal-day-tick').html('<i class="icon-chevron-down glyphicon glyphicon-chevron-down"></i>');
1085
1086		$('.cal-month-day, .cal-year-box .span3')
1087			.on('mouseenter', function() {
1088				if($('.events-list', this).length == 0) return;
1089				if($(this).children('[data-cal-date]').text() == self.activecell) return;
1090				downbox.show().appendTo(this);
1091			})
1092			.on('mouseleave', function() {
1093				downbox.hide();
1094			})
1095			.on('click', function(event) {
1096				if($('.events-list', this).length == 0) return;
1097				if($(this).children('[data-cal-date]').text() == self.activecell) return;
1098				showEventsList(event, downbox, slider, self);
1099			})
1100		;
1101
1102		var slider = $(document.createElement('div')).attr('id', 'cal-slide-box');
1103		slider.hide().click(function(event) {
1104			event.stopPropagation();
1105		});
1106
1107		this._loadTemplate('events-list');
1108
1109		downbox.click(function(event) {
1110			showEventsList(event, $(this), slider, self);
1111		});
1112	};
1113
1114	Calendar.prototype.getEventsBetween = function(start, end) {
1115		var events = [];
1116		$.each(this.options.events, function() {
1117			if(this.start == null) {
1118				return true;
1119			}
1120			var event_end = this.end || this.start;
1121			if((parseInt(this.start) < end) && (parseInt(event_end) >= start)) {
1122				events.push(this);
1123			}
1124		});
1125		return events;
1126	};
1127
1128	function showEventsList(event, that, slider, self) {
1129
1130		event.stopPropagation();
1131
1132		var that = $(that);
1133		var cell = that.closest('.cal-cell');
1134		var row = cell.closest('.cal-before-eventlist');
1135		var tick_position = cell.data('cal-row');
1136
1137		that.fadeOut('fast');
1138
1139		slider.slideUp('fast', function() {
1140			var event_list = $('.events-list', cell);
1141			slider.html(self.options.templates['events-list']({
1142				cal:    self,
1143				events: self.getEventsBetween(parseInt(event_list.data('cal-start')), parseInt(event_list.data('cal-end')))
1144			}));
1145			row.after(slider);
1146			self.activecell = $('[data-cal-date]', cell).text();
1147			$('#cal-slide-tick').addClass('tick' + tick_position).show();
1148			slider.slideDown('fast', function() {
1149				$('body').one('click', function() {
1150					slider.slideUp('fast');
1151					self.activecell = 0;
1152				});
1153			});
1154		});
1155
1156		$('a.event-item').mouseenter(function() {
1157			$('a[data-event-id="' + $(this).data('event-id') + '"]').closest('.cal-cell1').addClass('day-highlight dh-' + $(this).data('event-class'));
1158		});
1159		$('a.event-item').mouseleave(function() {
1160			$('div.cal-cell1').removeClass('day-highlight dh-' + $(this).data('event-class'));
1161		});
1162
1163		// Wait 400ms before updating the modal (400ms is the time for the slider to fade out and slide up)
1164		setTimeout(function() {
1165			self._update_modal();
1166		}, 400);
1167	}
1168
1169	function getEasterDate(year, offsetDays) {
1170		var a = year % 19;
1171		var b = Math.floor(year / 100);
1172		var c = year % 100;
1173		var d = Math.floor(b / 4);
1174		var e = b % 4;
1175		var f = Math.floor((b + 8) / 25);
1176		var g = Math.floor((b - f + 1) / 3);
1177		var h = (19 * a + b - d - g + 15) % 30;
1178		var i = Math.floor(c / 4);
1179		var k = c % 4;
1180		var l = (32 + 2 * e + 2 * i - h - k) % 7;
1181		var m = Math.floor((a + 11 * h + 22 * l) / 451);
1182		var n0 = (h + l + 7 * m + 114)
1183		var n = Math.floor(n0 / 31) - 1;
1184		var p = n0 % 31 + 1;
1185		return new Date(year, n, p + (offsetDays ? offsetDays : 0), 0, 0, 0);
1186	}
1187
1188	$.fn.calendar = function(params) {
1189		return new Calendar(params, this);
1190	}
1191
1192
1193
1194}(jQuery));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.