Subversion-Projekte lars-tiefland.cienc

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
5 lars 1
/* =========================================================
2
 * bootstrap-datetimepicker.js
3
 * =========================================================
4
 * Copyright 2012 Stefan Petre
5
 * Improvements by Andrew Rowls
6
 * Improvements by Sébastien Malot
7
 * Improvements by Yun Lai
8
 * Improved by Keenthemes for Bootstrap 3.0 Support
9
 
10
 * Project URL : http://www.malot.fr/bootstrap-datetimepicker
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 * ========================================================= */
24
 
25
!function( $ ) {
26
 
27
	function UTCDate(){
28
		return new Date(Date.UTC.apply(Date, arguments));
29
	}
30
	function UTCToday(){
31
		var today = new Date();
32
		return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), today.getUTCHours(), today.getUTCMinutes(), today.getUTCSeconds(), 0);
33
	}
34
 
35
	// Picker object
36
 
37
	var Datetimepicker = function(element, options) {
38
		var that = this;
39
 
40
		this.element = $(element);
41
		this.language = options.language || this.element.data('date-language') || "en";
42
		this.language = this.language in dates ? this.language : "en";
43
		this.isRTL = dates[this.language].rtl || ($('body').css("direction") == 'rtl');
44
		this.formatType = options.formatType || this.element.data('format-type') || 'standard';
45
		this.format = DPGlobal.parseFormat(options.format || this.element.data('date-format') || dates[this.language].format || DPGlobal.getDefaultFormat(this.formatType, 'input'), this.formatType);
46
		this.isInline = false;
47
		this.isVisible = false;
48
		this.isInput = this.element.is('input');
49
		this.component = this.element.is('.date') ? this.element.find('.date-set').parent() : false;
50
		this.componentReset = this.element.is('.date') ? this.element.find('.date-reset').parent() : false;
51
		this.hasInput = this.component && this.element.find('input').length;
52
		if (this.component && this.component.length === 0) {
53
			this.component = false;
54
		}
55
		this.linkField = options.linkField || this.element.data('link-field') || false;
56
		this.linkFormat = DPGlobal.parseFormat(options.linkFormat || this.element.data('link-format') || DPGlobal.getDefaultFormat(this.formatType, 'link'), this.formatType);
57
		this.minuteStep = options.minuteStep || this.element.data('minute-step') || 5;
58
		this.pickerPosition = options.pickerPosition || this.element.data('picker-position') || 'bottom-right';
59
				this.showMeridian = options.showMeridian || this.element.data('show-meridian') || false;
60
				this.initialDate = options.initialDate || new Date();
61
 
62
		this._attachEvents();
63
 
64
			this.formatViewType = "datetime";
65
			if ('formatViewType' in options) {
66
					this.formatViewType = options.formatViewType;
67
			} else if ('formatViewType' in this.element.data()) {
68
					this.formatViewType = this.element.data('formatViewType');
69
			}
70
 
71
		this.minView = 0;
72
		if ('minView' in options) {
73
			this.minView = options.minView;
74
		} else if ('minView' in this.element.data()) {
75
			this.minView = this.element.data('min-view');
76
		}
77
		this.minView = DPGlobal.convertViewMode(this.minView);
78
 
79
		this.maxView = DPGlobal.modes.length-1;
80
		if ('maxView' in options) {
81
			this.maxView = options.maxView;
82
		} else if ('maxView' in this.element.data()) {
83
			this.maxView = this.element.data('max-view');
84
		}
85
		this.maxView = DPGlobal.convertViewMode(this.maxView);
86
 
87
        this.wheelViewModeNavigation = false;
88
        if('wheelViewModeNavigation' in options){
89
            this.wheelViewModeNavigation = options.wheelViewModeNavigation;
90
        }else if('wheelViewModeNavigation' in this.element.data()){
91
            this.wheelViewModeNavigation = this.element.data('view-mode-wheel-navigation');
92
        }
93
 
94
        this.wheelViewModeNavigationInverseDirection = false;
95
 
96
        if('wheelViewModeNavigationInverseDirection' in options){
97
            this.wheelViewModeNavigationInverseDirection = options.wheelViewModeNavigationInverseDirection;
98
        }else if('wheelViewModeNavigationInverseDirection' in this.element.data()){
99
            this.wheelViewModeNavigationInverseDirection = this.element.data('view-mode-wheel-navigation-inverse-dir');
100
        }
101
 
102
        this.wheelViewModeNavigationDelay = 100;
103
        if('wheelViewModeNavigationDelay' in options){
104
            this.wheelViewModeNavigationDelay = options.wheelViewModeNavigationDelay;
105
        }else if('wheelViewModeNavigationDelay' in this.element.data()){
106
            this.wheelViewModeNavigationDelay = this.element.data('view-mode-wheel-navigation-delay');
107
        }
108
 
109
		this.startViewMode = 2;
110
		if ('startView' in options) {
111
			this.startViewMode = options.startView;
112
		} else if ('startView' in this.element.data()) {
113
			this.startViewMode = this.element.data('start-view');
114
		}
115
		this.startViewMode = DPGlobal.convertViewMode(this.startViewMode);
116
		this.viewMode = this.startViewMode;
117
 
118
				this.viewSelect = this.minView;
119
				if ('viewSelect' in options) {
120
						this.viewSelect = options.viewSelect;
121
				} else if ('viewSelect' in this.element.data()) {
122
						this.viewSelect = this.element.data('view-select');
123
				}
124
				this.viewSelect = DPGlobal.convertViewMode(this.viewSelect);
125
 
126
		this.forceParse = true;
127
		if ('forceParse' in options) {
128
			this.forceParse = options.forceParse;
129
		} else if ('dateForceParse' in this.element.data()) {
130
			this.forceParse = this.element.data('date-force-parse');
131
		}
132
 
133
		this.picker = $(DPGlobal.template)
134
							.appendTo(this.isInline ? this.element : 'body')
135
							.on({
136
								click: $.proxy(this.click, this),
137
								mousedown: $.proxy(this.mousedown, this)
138
							});
139
 
140
        if(this.wheelViewModeNavigation)
141
        {
142
            if($.fn.mousewheel)
143
            {
144
                this.picker.on({mousewheel: $.proxy(this.mousewheel,this)});
145
            }else
146
            {
147
                console.log("Mouse Wheel event is not supported. Please include the jQuery Mouse Wheel plugin before enabling this option");
148
            }
149
        }
150
 
151
		if (this.isInline) {
152
			this.picker.addClass('datetimepicker-inline');
153
		} else {
154
			this.picker.addClass('datetimepicker-dropdown-' + this.pickerPosition + ' dropdown-menu');
155
		}
156
		if (this.isRTL){
157
			this.picker.addClass('datetimepicker-rtl');
158
			this.picker.find('.prev i, .next i')
159
						.toggleClass('fa-arrow-left fa-arrow-right');
160
		}
161
		$(document).on('mousedown', function (e) {
162
			// Clicked outside the datetimepicker, hide it
163
			if ($(e.target).closest('.datetimepicker').length === 0) {
164
				that.hide();
165
			}
166
		});
167
 
168
		this.autoclose = false;
169
		if ('autoclose' in options) {
170
			this.autoclose = options.autoclose;
171
		} else if ('dateAutoclose' in this.element.data()) {
172
			this.autoclose = this.element.data('date-autoclose');
173
		}
174
 
175
		this.keyboardNavigation = true;
176
		if ('keyboardNavigation' in options) {
177
			this.keyboardNavigation = options.keyboardNavigation;
178
		} else if ('dateKeyboardNavigation' in this.element.data()) {
179
			this.keyboardNavigation = this.element.data('date-keyboard-navigation');
180
		}
181
 
182
		this.todayBtn = (options.todayBtn || this.element.data('date-today-btn') || false);
183
		this.todayHighlight = (options.todayHighlight || this.element.data('date-today-highlight') || false);
184
 
185
		this.weekStart = ((options.weekStart || this.element.data('date-weekstart') || dates[this.language].weekStart || 0) % 7);
186
		this.weekEnd = ((this.weekStart + 6) % 7);
187
		this.startDate = -Infinity;
188
		this.endDate = Infinity;
189
		this.daysOfWeekDisabled = [];
190
		this.setStartDate(options.startDate || this.element.data('date-startdate'));
191
		this.setEndDate(options.endDate || this.element.data('date-enddate'));
192
		this.setDaysOfWeekDisabled(options.daysOfWeekDisabled || this.element.data('date-days-of-week-disabled'));
193
		this.fillDow();
194
		this.fillMonths();
195
		this.update();
196
		this.showMode();
197
 
198
		if(this.isInline) {
199
			this.show();
200
		}
201
	};
202
 
203
	Datetimepicker.prototype = {
204
		constructor: Datetimepicker,
205
 
206
		_events: [],
207
		_attachEvents: function(){
208
			this._detachEvents();
209
			if (this.isInput) { // single input
210
				this._events = [
211
					[this.element, {
212
						focus: $.proxy(this.show, this),
213
						keyup: $.proxy(this.update, this),
214
						keydown: $.proxy(this.keydown, this)
215
					}]
216
				];
217
			}
218
			else if (this.component && this.hasInput){ // component: input + button
219
				this._events = [
220
					// For components that are not readonly, allow keyboard nav
221
					[this.element.find('input'), {
222
						focus: $.proxy(this.show, this),
223
						keyup: $.proxy(this.update, this),
224
						keydown: $.proxy(this.keydown, this)
225
					}],
226
					[this.component, {
227
						click: $.proxy(this.show, this)
228
					}]
229
				];
230
				if (this.componentReset) {
231
					this._events.push([
232
						this.componentReset,
233
						{click: $.proxy(this.reset, this)}
234
					]);
235
				}
236
			}
237
			else if (this.element.is('div')) {  // inline datetimepicker
238
				this.isInline = true;
239
			}
240
			else {
241
				this._events = [
242
					[this.element, {
243
						click: $.proxy(this.show, this)
244
					}]
245
				];
246
			}
247
			for (var i=0, el, ev; i<this._events.length; i++){
248
				el = this._events[i][0];
249
				ev = this._events[i][1];
250
				el.on(ev);
251
			}
252
		},
253
 
254
		_detachEvents: function(){
255
			for (var i=0, el, ev; i<this._events.length; i++){
256
				el = this._events[i][0];
257
				ev = this._events[i][1];
258
				el.off(ev);
259
			}
260
			this._events = [];
261
		},
262
 
263
		show: function(e) {
264
			this.picker.show();
265
			this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
266
			if (this.forceParse) {
267
				this.update();
268
			}
269
			this.place();
270
			$(window).on('resize', $.proxy(this.place, this));
271
			if (e) {
272
				e.stopPropagation();
273
				e.preventDefault();
274
			}
275
			this.isVisible = true;
276
			this.element.trigger({
277
				type: 'show',
278
				date: this.date
279
			});
280
		},
281
 
282
		hide: function(e){
283
			if(!this.isVisible) return;
284
			if(this.isInline) return;
285
			this.picker.hide();
286
			$(window).off('resize', this.place);
287
			this.viewMode = this.startViewMode;
288
			this.showMode();
289
			if (!this.isInput) {
290
				$(document).off('mousedown', this.hide);
291
			}
292
 
293
			if (
294
				this.forceParse &&
295
				(
296
					this.isInput && this.element.val()  ||
297
					this.hasInput && this.element.find('input').val()
298
				)
299
			)
300
				this.setValue();
301
			this.isVisible = false;
302
			this.element.trigger({
303
				type: 'hide',
304
				date: this.date
305
			});
306
		},
307
 
308
		remove: function() {
309
			this._detachEvents();
310
			this.picker.remove();
311
			delete this.picker;
312
			delete this.element.data().datetimepicker;
313
		},
314
 
315
		getDate: function() {
316
			var d = this.getUTCDate();
317
			return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
318
		},
319
 
320
		getUTCDate: function() {
321
			return this.date;
322
		},
323
 
324
		setDate: function(d) {
325
			this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
326
		},
327
 
328
		setUTCDate: function(d) {
329
			if (d >= this.startDate && d <= this.endDate) {
330
				this.date = d;
331
				this.setValue();
332
				this.viewDate = this.date;
333
				this.fill();
334
			} else {
335
				this.element.trigger({
336
					type: 'outOfRange',
337
					date: d,
338
					startDate: this.startDate,
339
					endDate: this.endDate
340
				});
341
			}
342
		},
343
 
344
        setFormat: function(format) {
345
            this.format = DPGlobal.parseFormat(format, this.formatType);
346
            var element;
347
            if (this.isInput) {
348
                element = this.element;
349
            } else if (this.component){
350
                element = this.element.find('input');
351
            }
352
            if (element && element.val()) {
353
                this.setValue();
354
            }
355
        },
356
 
357
		setValue: function() {
358
			var formatted = this.getFormattedDate();
359
			if (!this.isInput) {
360
				if (this.component){
361
					this.element.find('input').val(formatted);
362
				}
363
				this.element.data('date', formatted);
364
			} else {
365
				this.element.val(formatted);
366
			}
367
			if (this.linkField) {
368
				$('#' + this.linkField).val(this.getFormattedDate(this.linkFormat));
369
			}
370
		},
371
 
372
		getFormattedDate: function(format) {
373
			if(format == undefined) format = this.format;
374
			return DPGlobal.formatDate(this.date, format, this.language, this.formatType);
375
		},
376
 
377
		setStartDate: function(startDate){
378
			this.startDate = startDate || -Infinity;
379
			if (this.startDate !== -Infinity) {
380
				this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language, this.formatType);
381
			}
382
			this.update();
383
			this.updateNavArrows();
384
		},
385
 
386
		setEndDate: function(endDate){
387
			this.endDate = endDate || Infinity;
388
			if (this.endDate !== Infinity) {
389
				this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language, this.formatType);
390
			}
391
			this.update();
392
			this.updateNavArrows();
393
		},
394
 
395
		setDaysOfWeekDisabled: function(daysOfWeekDisabled){
396
			this.daysOfWeekDisabled = daysOfWeekDisabled || [];
397
			if (!$.isArray(this.daysOfWeekDisabled)) {
398
				this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
399
			}
400
			this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) {
401
				return parseInt(d, 10);
402
			});
403
			this.update();
404
			this.updateNavArrows();
405
		},
406
 
407
		place: function(){
408
			if(this.isInline) return;
409
			var zIndex = parseInt(this.element.parents().filter(function() {
410
				return $(this).css('z-index') != 'auto';
411
			}).first().css('z-index'))+10;
412
			var offset, top, left;
413
			if (this.component) {
414
				offset = this.component.offset();
415
				left = offset.left;
416
				if (this.pickerPosition == 'bottom-left' || this.pickerPosition == 'top-left') {
417
					left += this.component.outerWidth() - this.picker.outerWidth();
418
				}
419
			} else {
420
				offset = this.element.offset();
421
				left = offset.left;
422
			}
423
			if (this.pickerPosition == 'top-left' || this.pickerPosition == 'top-right') {
424
				top = offset.top - this.picker.outerHeight();
425
			} else {
426
				top = offset.top + this.height;
427
			}
428
			this.picker.css({
429
				top: top,
430
				left: left,
431
				zIndex: zIndex
432
			});
433
		},
434
 
435
		update: function(){
436
			var date, fromArgs = false;
437
			if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {
438
				date = arguments[0];
439
				fromArgs = true;
440
			} else {
441
                date = this.element.data('date') || (this.isInput ? this.element.val() : this.element.find('input').val()) || this.initialDate;
442
			}
443
 
444
			if (!date) {
445
				date = new Date();
446
				fromArgs = false;
447
			}
448
 
449
			this.date = DPGlobal.parseDate(date, this.format, this.language, this.formatType);
450
 
451
			if (fromArgs) this.setValue();
452
 
453
			if (this.date < this.startDate) {
454
				this.viewDate = new Date(this.startDate);
455
			} else if (this.date > this.endDate) {
456
				this.viewDate = new Date(this.endDate);
457
			} else {
458
				this.viewDate = new Date(this.date);
459
			}
460
			this.fill();
461
		},
462
 
463
		fillDow: function(){
464
			var dowCnt = this.weekStart,
465
			html = '<tr>';
466
			while (dowCnt < this.weekStart + 7) {
467
				html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>';
468
			}
469
			html += '</tr>';
470
			this.picker.find('.datetimepicker-days thead').append(html);
471
		},
472
 
473
		fillMonths: function(){
474
			var html = '',
475
			i = 0;
476
			while (i < 12) {
477
				html += '<span class="month">'+dates[this.language].monthsShort[i++]+'</span>';
478
			}
479
			this.picker.find('.datetimepicker-months td').html(html);
480
		},
481
 
482
		fill: function() {
483
			if (this.date == null || this.viewDate == null) {
484
				return;
485
			}
486
			var d = new Date(this.viewDate),
487
				year = d.getUTCFullYear(),
488
				month = d.getUTCMonth(),
489
				dayMonth = d.getUTCDate(),
490
				hours = d.getUTCHours(),
491
				minutes = d.getUTCMinutes(),
492
				startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
493
				startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
494
				endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
495
				endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
496
				currentDate = (new UTCDate(this.date.getUTCFullYear(), this.date.getUTCMonth(), this.date.getUTCDate())).valueOf(),
497
				today = new Date();
498
			this.picker.find('.datetimepicker-days thead th:eq(1)')
499
						.text(dates[this.language].months[month]+' '+year);
500
				if (this.formatViewType == "time") {
501
						var hourConverted = hours % 12 ? hours % 12 : 12;
502
						var hoursDisplay = (hourConverted < 10 ? '0' : '') + hourConverted;
503
						var minutesDisplay = (minutes < 10 ? '0' : '') + minutes;
504
						var meridianDisplay = dates[this.language].meridiem[hours < 12 ? 0 : 1];
505
						this.picker.find('.datetimepicker-hours thead th:eq(1)')
506
								.text(hoursDisplay + ':' + minutesDisplay + ' ' + meridianDisplay.toUpperCase());
507
						this.picker.find('.datetimepicker-minutes thead th:eq(1)')
508
								.text(hoursDisplay + ':' + minutesDisplay + ' ' + meridianDisplay.toUpperCase());
509
				} else {
510
						this.picker.find('.datetimepicker-hours thead th:eq(1)')
511
								.text(dayMonth + ' ' + dates[this.language].months[month] + ' ' + year);
512
						this.picker.find('.datetimepicker-minutes thead th:eq(1)')
513
								.text(dayMonth + ' ' + dates[this.language].months[month] + ' ' + year);
514
				}
515
				this.picker.find('tfoot th.today')
516
						.text(dates[this.language].today)
517
						.toggle(this.todayBtn !== false);
518
			this.updateNavArrows();
519
			this.fillMonths();
520
			/*var prevMonth = UTCDate(year, month, 0,0,0,0,0);
521
			prevMonth.setUTCDate(prevMonth.getDate() - (prevMonth.getUTCDay() - this.weekStart + 7)%7);*/
522
			var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),
523
								day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
524
				prevMonth.setUTCDate(day);
525
					prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
526
			var nextMonth = new Date(prevMonth);
527
			nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
528
			nextMonth = nextMonth.valueOf();
529
			var html = [];
530
			var clsName;
531
			while(prevMonth.valueOf() < nextMonth) {
532
				if (prevMonth.getUTCDay() == this.weekStart) {
533
					html.push('<tr>');
534
				}
535
				clsName = '';
536
				if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
537
					clsName += ' old';
538
				} else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
539
					clsName += ' new';
540
				}
541
				// Compare internal UTC date with local today, not UTC today
542
				if (this.todayHighlight &&
543
					prevMonth.getUTCFullYear() == today.getFullYear() &&
544
					prevMonth.getUTCMonth() == today.getMonth() &&
545
					prevMonth.getUTCDate() == today.getDate()) {
546
					clsName += ' today';
547
				}
548
				if (prevMonth.valueOf() == currentDate) {
549
					clsName += ' active';
550
				}
551
				if ((prevMonth.valueOf() + 86400000) <= this.startDate || prevMonth.valueOf() > this.endDate ||
552
					$.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) {
553
					clsName += ' disabled';
554
				}
555
				html.push('<td class="day'+clsName+'">'+prevMonth.getUTCDate() + '</td>');
556
				if (prevMonth.getUTCDay() == this.weekEnd) {
557
					html.push('</tr>');
558
				}
559
				prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
560
			}
561
			this.picker.find('.datetimepicker-days tbody').empty().append(html.join(''));
562
 
563
			html = [];
564
						var txt = '', meridian = '', meridianOld = '';
565
			for (var i=0;i<24;i++) {
566
				var actual = UTCDate(year, month, dayMonth, i);
567
				clsName = '';
568
				// We want the previous hour for the startDate
569
				if ((actual.valueOf() + 3600000) <= this.startDate || actual.valueOf() > this.endDate) {
570
					clsName += ' disabled';
571
				} else if (hours == i) {
572
					clsName += ' active';
573
				}
574
								if (this.showMeridian && dates[this.language].meridiem.length == 2) {
575
										meridian = (i<12?dates[this.language].meridiem[0]:dates[this.language].meridiem[1]);
576
										if (meridian != meridianOld) {
577
												if (meridianOld != '') {
578
														html.push('</fieldset>');
579
												}
580
												html.push('<fieldset class="hour"><legend>'+meridian.toUpperCase()+'</legend>');
581
										}
582
										meridianOld = meridian;
583
										txt = (i%12?i%12:12);
584
										html.push('<span class="hour'+clsName+' hour_'+(i<12?'am':'pm')+'">'+txt+'</span>');
585
										if (i == 23) {
586
												html.push('</fieldset>');
587
										}
588
								} else {
589
										txt = i+':00';
590
										html.push('<span class="hour'+clsName+'">'+txt+'</span>');
591
								}
592
			}
593
			this.picker.find('.datetimepicker-hours td').html(html.join(''));
594
 
595
			html = [];
596
						txt = '', meridian = '', meridianOld = '';
597
			for(var i=0;i<60;i+=this.minuteStep) {
598
				var actual = UTCDate(year, month, dayMonth, hours, i, 0);
599
				clsName = '';
600
				if (actual.valueOf() < this.startDate || actual.valueOf() > this.endDate) {
601
					clsName += ' disabled';
602
				} else if (Math.floor(minutes/this.minuteStep) == Math.floor(i/this.minuteStep)) {
603
					clsName += ' active';
604
				}
605
								if (this.showMeridian && dates[this.language].meridiem.length == 2) {
606
										meridian = (hours<12?dates[this.language].meridiem[0]:dates[this.language].meridiem[1]);
607
										if (meridian != meridianOld) {
608
												if (meridianOld != '') {
609
														html.push('</fieldset>');
610
												}
611
												html.push('<fieldset class="minute"><legend>'+meridian.toUpperCase()+'</legend>');
612
										}
613
										meridianOld = meridian;
614
										txt = (hours%12?hours%12:12);
615
										//html.push('<span class="minute'+clsName+' minute_'+(hours<12?'am':'pm')+'">'+txt+'</span>');
616
										html.push('<span class="minute'+clsName+'">'+txt+':'+(i<10?'0'+i:i)+'</span>');
617
										if (i == 59) {
618
												html.push('</fieldset>');
619
										}
620
								} else {
621
										txt = i+':00';
622
										//html.push('<span class="hour'+clsName+'">'+txt+'</span>');
623
										html.push('<span class="minute'+clsName+'">'+hours+':'+(i<10?'0'+i:i)+'</span>');
624
								}
625
			}
626
			this.picker.find('.datetimepicker-minutes td').html(html.join(''));
627
 
628
			var currentYear = this.date.getUTCFullYear();
629
			var months = this.picker.find('.datetimepicker-months')
630
						.find('th:eq(1)')
631
						.text(year)
632
						.end()
633
						.find('span').removeClass('active');
634
			if (currentYear == year) {
635
				months.eq(this.date.getUTCMonth()).addClass('active');
636
			}
637
			if (year < startYear || year > endYear) {
638
				months.addClass('disabled');
639
			}
640
			if (year == startYear) {
641
				months.slice(0, startMonth).addClass('disabled');
642
			}
643
			if (year == endYear) {
644
				months.slice(endMonth+1).addClass('disabled');
645
			}
646
 
647
			html = '';
648
			year = parseInt(year/10, 10) * 10;
649
			var yearCont = this.picker.find('.datetimepicker-years')
650
								.find('th:eq(1)')
651
								.text(year + '-' + (year + 9))
652
								.end()
653
								.find('td');
654
			year -= 1;
655
			for (var i = -1; i < 11; i++) {
656
				html += '<span class="year'+(i == -1 || i == 10 ? ' old' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>';
657
				year += 1;
658
			}
659
			yearCont.html(html);
660
			this.place();
661
		},
662
 
663
		updateNavArrows: function() {
664
			var d = new Date(this.viewDate),
665
				year = d.getUTCFullYear(),
666
				month = d.getUTCMonth(),
667
				day = d.getUTCDate(),
668
				hour = d.getUTCHours();
669
			switch (this.viewMode) {
670
				case 0:
671
					if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()
672
													 && month <= this.startDate.getUTCMonth()
673
													 && day <= this.startDate.getUTCDate()
674
													 && hour <= this.startDate.getUTCHours()) {
675
						this.picker.find('.prev').css({visibility: 'hidden'});
676
					} else {
677
						this.picker.find('.prev').css({visibility: 'visible'});
678
					}
679
					if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()
680
													&& month >= this.endDate.getUTCMonth()
681
													&& day >= this.endDate.getUTCDate()
682
													&& hour >= this.endDate.getUTCHours()) {
683
						this.picker.find('.next').css({visibility: 'hidden'});
684
					} else {
685
						this.picker.find('.next').css({visibility: 'visible'});
686
					}
687
					break;
688
				case 1:
689
					if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()
690
													 && month <= this.startDate.getUTCMonth()
691
													 && day <= this.startDate.getUTCDate()) {
692
						this.picker.find('.prev').css({visibility: 'hidden'});
693
					} else {
694
						this.picker.find('.prev').css({visibility: 'visible'});
695
					}
696
					if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()
697
													&& month >= this.endDate.getUTCMonth()
698
													&& day >= this.endDate.getUTCDate()) {
699
						this.picker.find('.next').css({visibility: 'hidden'});
700
					} else {
701
						this.picker.find('.next').css({visibility: 'visible'});
702
					}
703
					break;
704
				case 2:
705
					if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()
706
													 && month <= this.startDate.getUTCMonth()) {
707
						this.picker.find('.prev').css({visibility: 'hidden'});
708
					} else {
709
						this.picker.find('.prev').css({visibility: 'visible'});
710
					}
711
					if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()
712
													&& month >= this.endDate.getUTCMonth()) {
713
						this.picker.find('.next').css({visibility: 'hidden'});
714
					} else {
715
						this.picker.find('.next').css({visibility: 'visible'});
716
					}
717
					break;
718
				case 3:
719
				case 4:
720
					if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
721
						this.picker.find('.prev').css({visibility: 'hidden'});
722
					} else {
723
						this.picker.find('.prev').css({visibility: 'visible'});
724
					}
725
					if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
726
						this.picker.find('.next').css({visibility: 'hidden'});
727
					} else {
728
						this.picker.find('.next').css({visibility: 'visible'});
729
					}
730
					break;
731
			}
732
		},
733
 
734
        mousewheel: function(e){
735
 
736
            e.preventDefault();
737
            e.stopPropagation();
738
 
739
            if(this.wheelPause)
740
            {
741
                return;
742
            }
743
 
744
            this.wheelPause = true;
745
 
746
            var originalEvent = e.originalEvent;
747
 
748
            var delta = originalEvent.wheelDelta;
749
 
750
            var mode = delta > 0 ? 1:(delta === 0)?0:-1;
751
 
752
            if(this.wheelViewModeNavigationInverseDirection)
753
            {
754
                mode = -mode;
755
            }
756
 
757
            this.showMode(mode);
758
 
759
            setTimeout($.proxy(function(){
760
 
761
                this.wheelPause = false
762
 
763
            },this),this.wheelViewModeNavigationDelay);
764
 
765
 
766
 
767
        },
768
 
769
		click: function(e) {
770
			e.stopPropagation();
771
			e.preventDefault();
772
			var target = $(e.target).closest('span, td, th, legend');
773
			if (target.length == 1) {
774
				if (target.is('.disabled')) {
775
					this.element.trigger({
776
						type: 'outOfRange',
777
						date: this.viewDate,
778
						startDate: this.startDate,
779
						endDate: this.endDate
780
					});
781
					return;
782
				}
783
				switch(target[0].nodeName.toLowerCase()) {
784
					case 'th':
785
						switch(target[0].className) {
786
							case 'switch':
787
								this.showMode(1);
788
								break;
789
							case 'prev':
790
							case 'next':
791
								var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
792
								switch(this.viewMode){
793
									case 0:
794
										this.viewDate = this.moveHour(this.viewDate, dir);
795
										break;
796
									case 1:
797
										this.viewDate = this.moveDate(this.viewDate, dir);
798
										break;
799
									case 2:
800
										this.viewDate = this.moveMonth(this.viewDate, dir);
801
										break;
802
									case 3:
803
									case 4:
804
										this.viewDate = this.moveYear(this.viewDate, dir);
805
										break;
806
								}
807
								this.fill();
808
								break;
809
							case 'today':
810
								var date = new Date();
811
								date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), 0);
812
 
813
								this.viewMode = this.startViewMode;
814
								this.showMode(0);
815
								this._setDate(date);
816
								this.fill();
817
								if (this.autoclose) {
818
									this.hide();
819
								}
820
								break;
821
						}
822
						break;
823
					case 'span':
824
						if (!target.is('.disabled')) {
825
														var year    = this.viewDate.getUTCFullYear(),
826
																month   = this.viewDate.getUTCMonth(),
827
																day     = this.viewDate.getUTCDate(),
828
																hours   = this.viewDate.getUTCHours(),
829
																minutes = this.viewDate.getUTCMinutes(),
830
																seconds = this.viewDate.getUTCSeconds();
831
 
832
							if (target.is('.month')) {
833
								this.viewDate.setUTCDate(1);
834
								month = target.parent().find('span').index(target);
835
																day   = this.viewDate.getUTCDate();
836
								this.viewDate.setUTCMonth(month);
837
								this.element.trigger({
838
									type: 'changeMonth',
839
									date: this.viewDate
840
								});
841
																if (this.viewSelect >= 3) {
842
										this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
843
																}
844
							} else if (target.is('.year')) {
845
								this.viewDate.setUTCDate(1);
846
								year = parseInt(target.text(), 10) || 0;
847
								this.viewDate.setUTCFullYear(year);
848
								this.element.trigger({
849
									type: 'changeYear',
850
									date: this.viewDate
851
								});
852
																if (this.viewSelect >= 4) {
853
																		this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
854
																}
855
							} else if (target.is('.hour')){
856
								hours = parseInt(target.text(), 10) || 0;
857
																if (target.hasClass('hour_am') || target.hasClass('hour_pm')) {
858
																		if (hours == 12 && target.hasClass('hour_am')) {
859
																				hours = 0;
860
																		} else if (hours != 12 && target.hasClass('hour_pm')) {
861
																				hours += 12;
862
																		}
863
																}
864
																this.viewDate.setUTCHours(hours);
865
								this.element.trigger({
866
									type: 'changeHour',
867
									date: this.viewDate
868
								});
869
																if (this.viewSelect >= 1) {
870
										this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
871
																}
872
							} else if (target.is('.minute')){
873
								minutes = parseInt(target.text().substr(target.text().indexOf(':')+1), 10) || 0;
874
																this.viewDate.setUTCMinutes(minutes);
875
								this.element.trigger({
876
									type: 'changeMinute',
877
									date: this.viewDate
878
								});
879
																if (this.viewSelect >= 0) {
880
										this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
881
																}
882
							}
883
							if (this.viewMode != 0) {
884
								var oldViewMode = this.viewMode;
885
								this.showMode(-1);
886
								this.fill();
887
								if (oldViewMode == this.viewMode && this.autoclose) {
888
									this.hide();
889
								}
890
							} else {
891
								this.fill();
892
								if (this.autoclose) {
893
									this.hide();
894
								}
895
							}
896
						}
897
						break;
898
					case 'td':
899
						if (target.is('.day') && !target.is('.disabled')){
900
							var day = parseInt(target.text(), 10) || 1;
901
							var year = this.viewDate.getUTCFullYear(),
902
								month = this.viewDate.getUTCMonth(),
903
								hours = this.viewDate.getUTCHours(),
904
								minutes = this.viewDate.getUTCMinutes(),
905
								seconds = this.viewDate.getUTCSeconds();
906
							if (target.is('.old')) {
907
								if (month === 0) {
908
									month = 11;
909
									year -= 1;
910
								} else {
911
									month -= 1;
912
								}
913
							} else if (target.is('.new')) {
914
								if (month == 11) {
915
									month = 0;
916
									year += 1;
917
								} else {
918
									month += 1;
919
								}
920
							}
921
														this.viewDate.setUTCFullYear(year);
922
														this.viewDate.setUTCMonth(month);
923
														this.viewDate.setUTCDate(day);
924
														this.element.trigger({
925
																type: 'changeDay',
926
																date: this.viewDate
927
														});
928
														if (this.viewSelect >= 2) {
929
									this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
930
														}
931
						}
932
						var oldViewMode = this.viewMode;
933
						this.showMode(-1);
934
						this.fill();
935
						if (oldViewMode == this.viewMode && this.autoclose) {
936
							this.hide();
937
						}
938
						break;
939
				}
940
			}
941
		},
942
 
943
		_setDate: function(date, which){
944
			if (!which || which == 'date')
945
				this.date = date;
946
			if (!which || which  == 'view')
947
				this.viewDate = date;
948
			this.fill();
949
			this.setValue();
950
			var element;
951
			if (this.isInput) {
952
				element = this.element;
953
			} else if (this.component){
954
				element = this.element.find('input');
955
			}
956
			if (element) {
957
				element.change();
958
				if (this.autoclose && (!which || which == 'date')) {
959
					//this.hide();
960
				}
961
			}
962
			this.element.trigger({
963
				type: 'changeDate',
964
				date: this.date
965
			});
966
		},
967
 
968
		moveMinute: function(date, dir){
969
			if (!dir) return date;
970
			var new_date = new Date(date.valueOf());
971
			//dir = dir > 0 ? 1 : -1;
972
			new_date.setUTCMinutes(new_date.getUTCMinutes() + (dir * this.minuteStep));
973
			return new_date;
974
		},
975
 
976
		moveHour: function(date, dir){
977
			if (!dir) return date;
978
			var new_date = new Date(date.valueOf());
979
			//dir = dir > 0 ? 1 : -1;
980
			new_date.setUTCHours(new_date.getUTCHours() + dir);
981
			return new_date;
982
		},
983
 
984
		moveDate: function(date, dir){
985
			if (!dir) return date;
986
			var new_date = new Date(date.valueOf());
987
			//dir = dir > 0 ? 1 : -1;
988
			new_date.setUTCDate(new_date.getUTCDate() + dir);
989
			return new_date;
990
		},
991
 
992
		moveMonth: function(date, dir){
993
			if (!dir) return date;
994
			var new_date = new Date(date.valueOf()),
995
				day = new_date.getUTCDate(),
996
				month = new_date.getUTCMonth(),
997
				mag = Math.abs(dir),
998
				new_month, test;
999
			dir = dir > 0 ? 1 : -1;
1000
			if (mag == 1){
1001
				test = dir == -1
1002
					// If going back one month, make sure month is not current month
1003
					// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
1004
					? function(){ return new_date.getUTCMonth() == month; }
1005
					// If going forward one month, make sure month is as expected
1006
					// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
1007
					: function(){ return new_date.getUTCMonth() != new_month; };
1008
				new_month = month + dir;
1009
				new_date.setUTCMonth(new_month);
1010
				// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
1011
				if (new_month < 0 || new_month > 11)
1012
					new_month = (new_month + 12) % 12;
1013
			} else {
1014
				// For magnitudes >1, move one month at a time...
1015
				for (var i=0; i<mag; i++)
1016
					// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
1017
					new_date = this.moveMonth(new_date, dir);
1018
				// ...then reset the day, keeping it in the new month
1019
				new_month = new_date.getUTCMonth();
1020
				new_date.setUTCDate(day);
1021
				test = function(){ return new_month != new_date.getUTCMonth(); };
1022
			}
1023
			// Common date-resetting loop -- if date is beyond end of month, make it
1024
			// end of month
1025
			while (test()){
1026
				new_date.setUTCDate(--day);
1027
				new_date.setUTCMonth(new_month);
1028
			}
1029
			return new_date;
1030
		},
1031
 
1032
		moveYear: function(date, dir){
1033
			return this.moveMonth(date, dir*12);
1034
		},
1035
 
1036
		dateWithinRange: function(date){
1037
			return date >= this.startDate && date <= this.endDate;
1038
		},
1039
 
1040
		keydown: function(e){
1041
			if (this.picker.is(':not(:visible)')){
1042
				if (e.keyCode == 27) // allow escape to hide and re-show picker
1043
					this.show();
1044
				return;
1045
			}
1046
			var dateChanged = false,
1047
				dir, day, month,
1048
				newDate, newViewDate;
1049
			switch(e.keyCode){
1050
				case 27: // escape
1051
					this.hide();
1052
					e.preventDefault();
1053
					break;
1054
				case 37: // left
1055
				case 39: // right
1056
					if (!this.keyboardNavigation) break;
1057
					dir = e.keyCode == 37 ? -1 : 1;
1058
										viewMode = this.viewMode;
1059
										if (e.ctrlKey) {
1060
												viewMode += 2;
1061
										} else if (e.shiftKey) {
1062
												viewMode += 1;
1063
										}
1064
										if (viewMode == 4) {
1065
						newDate = this.moveYear(this.date, dir);
1066
						newViewDate = this.moveYear(this.viewDate, dir);
1067
										} else if (viewMode == 3) {
1068
						newDate = this.moveMonth(this.date, dir);
1069
						newViewDate = this.moveMonth(this.viewDate, dir);
1070
										} else if (viewMode == 2) {
1071
						newDate = this.moveDate(this.date, dir);
1072
						newViewDate = this.moveDate(this.viewDate, dir);
1073
										} else if (viewMode == 1) {
1074
						newDate = this.moveHour(this.date, dir);
1075
						newViewDate = this.moveHour(this.viewDate, dir);
1076
										} else if (viewMode == 0) {
1077
						newDate = this.moveMinute(this.date, dir);
1078
						newViewDate = this.moveMinute(this.viewDate, dir);
1079
										}
1080
					if (this.dateWithinRange(newDate)){
1081
						this.date = newDate;
1082
						this.viewDate = newViewDate;
1083
						this.setValue();
1084
						this.update();
1085
						e.preventDefault();
1086
						dateChanged = true;
1087
					}
1088
					break;
1089
				case 38: // up
1090
				case 40: // down
1091
					if (!this.keyboardNavigation) break;
1092
					dir = e.keyCode == 38 ? -1 : 1;
1093
										viewMode = this.viewMode;
1094
										if (e.ctrlKey) {
1095
												viewMode += 2;
1096
										} else if (e.shiftKey) {
1097
												viewMode += 1;
1098
										}
1099
										if (viewMode == 4) {
1100
						newDate = this.moveYear(this.date, dir);
1101
						newViewDate = this.moveYear(this.viewDate, dir);
1102
										} else if (viewMode == 3) {
1103
						newDate = this.moveMonth(this.date, dir);
1104
						newViewDate = this.moveMonth(this.viewDate, dir);
1105
										} else if (viewMode == 2) {
1106
						newDate = this.moveDate(this.date, dir * 7);
1107
						newViewDate = this.moveDate(this.viewDate, dir * 7);
1108
										} else if (viewMode == 1) {
1109
												if (this.showMeridian) {
1110
														newDate = this.moveHour(this.date, dir * 6);
1111
														newViewDate = this.moveHour(this.viewDate, dir * 6);
1112
												} else {
1113
														newDate = this.moveHour(this.date, dir * 4);
1114
														newViewDate = this.moveHour(this.viewDate, dir * 4);
1115
												}
1116
										} else if (viewMode == 0) {
1117
						newDate = this.moveMinute(this.date, dir * 4);
1118
						newViewDate = this.moveMinute(this.viewDate, dir * 4);
1119
										}
1120
					if (this.dateWithinRange(newDate)){
1121
						this.date = newDate;
1122
						this.viewDate = newViewDate;
1123
						this.setValue();
1124
						this.update();
1125
						e.preventDefault();
1126
						dateChanged = true;
1127
					}
1128
					break;
1129
				case 13: // enter
1130
										if (this.viewMode != 0) {
1131
												var oldViewMode = this.viewMode;
1132
												this.showMode(-1);
1133
												this.fill();
1134
												if (oldViewMode == this.viewMode && this.autoclose) {
1135
														this.hide();
1136
												}
1137
										} else {
1138
												this.fill();
1139
												if (this.autoclose) {
1140
									this.hide();
1141
												}
1142
										}
1143
					e.preventDefault();
1144
					break;
1145
				case 9: // tab
1146
					this.hide();
1147
					break;
1148
			}
1149
			if (dateChanged){
1150
				var element;
1151
				if (this.isInput) {
1152
					element = this.element;
1153
				} else if (this.component){
1154
					element = this.element.find('input');
1155
				}
1156
				if (element) {
1157
					element.change();
1158
				}
1159
				this.element.trigger({
1160
					type: 'changeDate',
1161
					date: this.date
1162
				});
1163
			}
1164
		},
1165
 
1166
		showMode: function(dir) {
1167
			if (dir) {
1168
				var newViewMode = Math.max(0, Math.min(DPGlobal.modes.length - 1, this.viewMode + dir));
1169
				if (newViewMode >= this.minView && newViewMode <= this.maxView) {
1170
					this.element.trigger({
1171
						type: 'changeMode',
1172
						date: this.viewDate,
1173
						oldViewMode: this.viewMode,
1174
						newViewMode: newViewMode
1175
					});
1176
 
1177
					this.viewMode = newViewMode;
1178
				}
1179
			}
1180
			/*
1181
				vitalets: fixing bug of very special conditions:
1182
				jquery 1.7.1 + webkit + show inline datetimepicker in bootstrap popover.
1183
				Method show() does not set display css correctly and datetimepicker is not shown.
1184
				Changed to .css('display', 'block') solve the problem.
1185
				See https://github.com/vitalets/x-editable/issues/37
1186
 
1187
				In jquery 1.7.2+ everything works fine.
1188
			*/
1189
			//this.picker.find('>div').hide().filter('.datetimepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
1190
			this.picker.find('>div').hide().filter('.datetimepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
1191
			this.updateNavArrows();
1192
		},
1193
 
1194
		reset: function(e) {
1195
			this._setDate(null, 'date');
1196
		}
1197
	};
1198
 
1199
	$.fn.datetimepicker = function ( option ) {
1200
		var args = Array.apply(null, arguments);
1201
		args.shift();
1202
		return this.each(function () {
1203
			var $this = $(this),
1204
				data = $this.data('datetimepicker'),
1205
				options = typeof option == 'object' && option;
1206
			if (!data) {
1207
				$this.data('datetimepicker', (data = new Datetimepicker(this, $.extend({}, $.fn.datetimepicker.defaults,options))));
1208
			}
1209
			if (typeof option == 'string' && typeof data[option] == 'function') {
1210
				data[option].apply(data, args);
1211
			}
1212
		});
1213
	};
1214
 
1215
	$.fn.datetimepicker.defaults = {
1216
	};
1217
	$.fn.datetimepicker.Constructor = Datetimepicker;
1218
	var dates = $.fn.datetimepicker.dates = {
1219
		en: {
1220
			days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
1221
			daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
1222
			daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
1223
			months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
1224
			monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
1225
			meridiem: ["am", "pm"],
1226
			suffix: ["st", "nd", "rd", "th"],
1227
			today: "Today"
1228
		}
1229
	};
1230
 
1231
	var DPGlobal = {
1232
		modes: [
1233
			{
1234
				clsName: 'minutes',
1235
				navFnc: 'Hours',
1236
				navStep: 1
1237
			},
1238
			{
1239
				clsName: 'hours',
1240
				navFnc: 'Date',
1241
				navStep: 1
1242
			},
1243
			{
1244
				clsName: 'days',
1245
				navFnc: 'Month',
1246
				navStep: 1
1247
			},
1248
			{
1249
				clsName: 'months',
1250
				navFnc: 'FullYear',
1251
				navStep: 1
1252
			},
1253
			{
1254
				clsName: 'years',
1255
				navFnc: 'FullYear',
1256
				navStep: 10
1257
		}],
1258
		isLeapYear: function (year) {
1259
			return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
1260
		},
1261
		getDaysInMonth: function (year, month) {
1262
			return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
1263
		},
1264
		getDefaultFormat: function (type, field) {
1265
			if (type == "standard") {
1266
				if (field == 'input')
1267
					return 'yyyy-mm-dd hh:ii';
1268
				else
1269
					return 'yyyy-mm-dd hh:ii:ss';
1270
			} else if (type == "php") {
1271
				if (field == 'input')
1272
					return 'Y-m-d H:i';
1273
				else
1274
					return 'Y-m-d H:i:s';
1275
			} else {
1276
				throw new Error("Invalid format type.");
1277
			}
1278
		},
1279
		validParts: function (type) {
1280
			if (type == "standard") {
1281
				return /hh?|HH?|p|P|ii?|ss?|dd?|DD?|mm?|MM?|yy(?:yy)?/g;
1282
			} else if (type == "php") {
1283
				return /[dDjlNwzFmMnStyYaABgGhHis]/g;
1284
			} else {
1285
				throw new Error("Invalid format type.");
1286
			}
1287
		},
1288
		nonpunctuation: /[^ -\/:-@\[-`{-~\t\n\rTZ]+/g,
1289
		parseFormat: function(format, type){
1290
			// IE treats \0 as a string end in inputs (truncating the value),
1291
			// so it's a bad format delimiter, anyway
1292
			var separators = format.replace(this.validParts(type), '\0').split('\0'),
1293
				parts = format.match(this.validParts(type));
1294
			if (!separators || !separators.length || !parts || parts.length == 0){
1295
				throw new Error("Invalid date format.");
1296
			}
1297
			return {separators: separators, parts: parts};
1298
		},
1299
		parseDate: function(date, format, language, type) {
1300
			if (date instanceof Date) {
1301
				var dateUTC = new Date(date.valueOf() - date.getTimezoneOffset() * 60000);
1302
								dateUTC.setMilliseconds(0);
1303
				return dateUTC;
1304
			}
1305
			if (/^\d{4}\-\d{1,2}\-\d{1,2}$/.test(date)) {
1306
				format = this.parseFormat('yyyy-mm-dd', type);
1307
			}
1308
			if (/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}$/.test(date)) {
1309
				format = this.parseFormat('yyyy-mm-dd hh:ii', type);
1310
			}
1311
			if (/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}\:\d{1,2}[Z]{0,1}$/.test(date)) {
1312
				format = this.parseFormat('yyyy-mm-dd hh:ii:ss', type);
1313
			}
1314
			if (/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(date)) {
1315
				var part_re = /([-+]\d+)([dmwy])/,
1316
					parts = date.match(/([-+]\d+)([dmwy])/g),
1317
					part, dir;
1318
				date = new Date();
1319
				for (var i=0; i<parts.length; i++) {
1320
					part = part_re.exec(parts[i]);
1321
					dir = parseInt(part[1]);
1322
					switch(part[2]){
1323
						case 'd':
1324
							date.setUTCDate(date.getUTCDate() + dir);
1325
							break;
1326
						case 'm':
1327
							date = Datetimepicker.prototype.moveMonth.call(Datetimepicker.prototype, date, dir);
1328
							break;
1329
						case 'w':
1330
							date.setUTCDate(date.getUTCDate() + dir * 7);
1331
							break;
1332
						case 'y':
1333
							date = Datetimepicker.prototype.moveYear.call(Datetimepicker.prototype, date, dir);
1334
							break;
1335
					}
1336
				}
1337
				return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), 0);
1338
			}
1339
			var parts = date && date.match(this.nonpunctuation) || [],
1340
				date = new Date(0, 0, 0, 0, 0, 0, 0),
1341
				parsed = {},
1342
				setters_order = ['hh', 'h', 'ii', 'i', 'ss', 's', 'yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'D', 'DD', 'd', 'dd', 'H', 'HH', 'p', 'P'],
1343
				setters_map = {
1344
					hh: function(d,v){ return d.setUTCHours(v); },
1345
					h:  function(d,v){ return d.setUTCHours(v); },
1346
					HH: function(d,v){ return d.setUTCHours(v==12?0:v); },
1347
					H:  function(d,v){ return d.setUTCHours(v==12?0:v); },
1348
					ii: function(d,v){ return d.setUTCMinutes(v); },
1349
					i:  function(d,v){ return d.setUTCMinutes(v); },
1350
					ss: function(d,v){ return d.setUTCSeconds(v); },
1351
					s:  function(d,v){ return d.setUTCSeconds(v); },
1352
					yyyy: function(d,v){ return d.setUTCFullYear(v); },
1353
					yy: function(d,v){ return d.setUTCFullYear(2000+v); },
1354
					m: function(d,v){
1355
						v -= 1;
1356
						while (v<0) v += 12;
1357
						v %= 12;
1358
						d.setUTCMonth(v);
1359
						while (d.getUTCMonth() != v)
1360
							d.setUTCDate(d.getUTCDate()-1);
1361
						return d;
1362
					},
1363
					d: function(d,v){ return d.setUTCDate(v); },
1364
					p: function(d,v){ return d.setUTCHours(v==1?d.getUTCHours()+12:d.getUTCHours()); }
1365
				},
1366
				val, filtered, part;
1367
			setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
1368
			setters_map['dd'] = setters_map['d'];
1369
					setters_map['P'] = setters_map['p'];
1370
			date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
1371
			if (parts.length == format.parts.length) {
1372
				for (var i=0, cnt = format.parts.length; i < cnt; i++) {
1373
					val = parseInt(parts[i], 10);
1374
					part = format.parts[i];
1375
					if (isNaN(val)) {
1376
						switch(part) {
1377
							case 'MM':
1378
								filtered = $(dates[language].months).filter(function(){
1379
									var m = this.slice(0, parts[i].length),
1380
										p = parts[i].slice(0, m.length);
1381
									return m == p;
1382
								});
1383
								val = $.inArray(filtered[0], dates[language].months) + 1;
1384
								break;
1385
							case 'M':
1386
								filtered = $(dates[language].monthsShort).filter(function(){
1387
									var m = this.slice(0, parts[i].length),
1388
										p = parts[i].slice(0, m.length);
1389
									return m == p;
1390
								});
1391
								val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
1392
								break;
1393
								case 'p':
1394
								case 'P':
1395
										val = $.inArray(parts[i].toLowerCase(), dates[language].meridiem);
1396
										break;
1397
						}
1398
					}
1399
					parsed[part] = val;
1400
				}
1401
				for (var i=0, s; i<setters_order.length; i++){
1402
					s = setters_order[i];
1403
					if (s in parsed && !isNaN(parsed[s]))
1404
						setters_map[s](date, parsed[s])
1405
				}
1406
			}
1407
			return date;
1408
		},
1409
		formatDate: function(date, format, language, type){
1410
			if (date == null) {
1411
				return '';
1412
			}
1413
			var val;
1414
			if (type == 'standard') {
1415
				val = {
1416
					// year
1417
					yy: date.getUTCFullYear().toString().substring(2),
1418
					yyyy: date.getUTCFullYear(),
1419
					// month
1420
					m: date.getUTCMonth() + 1,
1421
					M: dates[language].monthsShort[date.getUTCMonth()],
1422
					MM: dates[language].months[date.getUTCMonth()],
1423
					// day
1424
					d: date.getUTCDate(),
1425
					D: dates[language].daysShort[date.getUTCDay()],
1426
					DD: dates[language].days[date.getUTCDay()],
1427
					p: (dates[language].meridiem.length==2?dates[language].meridiem[date.getUTCHours()<12?0:1]:''),
1428
					// hour
1429
					h: date.getUTCHours(),
1430
					// minute
1431
					i: date.getUTCMinutes(),
1432
					// second
1433
					s: date.getUTCSeconds()
1434
				};
1435
								val.H  = (val.h%12==0? 12 : val.h%12);
1436
								val.HH = (val.H < 10 ? '0' : '') + val.H;
1437
								val.P  = val.p.toUpperCase();
1438
				val.hh = (val.h < 10 ? '0' : '') + val.h;
1439
				val.ii = (val.i < 10 ? '0' : '') + val.i;
1440
				val.ss = (val.s < 10 ? '0' : '') + val.s;
1441
				val.dd = (val.d < 10 ? '0' : '') + val.d;
1442
				val.mm = (val.m < 10 ? '0' : '') + val.m;
1443
			} else if (type == 'php') {
1444
				// php format
1445
				val = {
1446
					// year
1447
					y: date.getUTCFullYear().toString().substring(2),
1448
					Y: date.getUTCFullYear(),
1449
					// month
1450
					F: dates[language].months[date.getUTCMonth()],
1451
					M: dates[language].monthsShort[date.getUTCMonth()],
1452
					n: date.getUTCMonth() + 1,
1453
					t: DPGlobal.getDaysInMonth(date.getUTCFullYear(), date.getUTCMonth()),
1454
					// day
1455
					j: date.getUTCDate(),
1456
					l: dates[language].days[date.getUTCDay()],
1457
					D: dates[language].daysShort[date.getUTCDay()],
1458
					w: date.getUTCDay(), // 0 -> 6
1459
					N: (date.getUTCDay()==0?7:date.getUTCDay()),       // 1 -> 7
1460
					S: (date.getUTCDate()%10<=dates[language].suffix.length?dates[language].suffix[date.getUTCDate()%10-1]:''),
1461
					// hour
1462
					a: (dates[language].meridiem.length==2?dates[language].meridiem[date.getUTCHours()<12?0:1]:''),
1463
					g: (date.getUTCHours()%12==0?12:date.getUTCHours()%12),
1464
					G: date.getUTCHours(),
1465
					// minute
1466
					i: date.getUTCMinutes(),
1467
					// second
1468
					s: date.getUTCSeconds()
1469
				};
1470
				val.m = (val.n < 10 ? '0' : '') + val.n;
1471
				val.d = (val.j < 10 ? '0' : '') + val.j;
1472
				val.A = val.a.toString().toUpperCase();
1473
				val.h = (val.g < 10 ? '0' : '') + val.g;
1474
				val.H = (val.G < 10 ? '0' : '') + val.G;
1475
				val.i = (val.i < 10 ? '0' : '') + val.i;
1476
				val.s = (val.s < 10 ? '0' : '') + val.s;
1477
			} else {
1478
				throw new Error("Invalid format type.");
1479
			}
1480
			var date = [],
1481
				seps = $.extend([], format.separators);
1482
			for (var i=0, cnt = format.parts.length; i < cnt; i++) {
1483
				if (seps.length)
1484
					date.push(seps.shift())
1485
				date.push(val[format.parts[i]]);
1486
			}
1487
			return date.join('');
1488
		},
1489
		convertViewMode: function(viewMode){
1490
			switch (viewMode) {
1491
				case 4:
1492
				case 'decade':
1493
					viewMode = 4;
1494
					break;
1495
				case 3:
1496
				case 'year':
1497
					viewMode = 3;
1498
					break;
1499
				case 2:
1500
				case 'month':
1501
					viewMode = 2;
1502
					break;
1503
				case 1:
1504
				case 'day':
1505
					viewMode = 1;
1506
					break;
1507
				case 0:
1508
				case 'hour':
1509
					viewMode = 0;
1510
					break;
1511
			}
1512
 
1513
			return viewMode;
1514
		},
1515
		headTemplate: '<thead>'+
1516
							'<tr>'+
1517
								'<th class="prev"><i class="fa fa-angle-left"/></th>'+
1518
								'<th colspan="5" class="switch"></th>'+
1519
								'<th class="next"><i class="fa fa-angle-right"/></th>'+
1520
							'</tr>'+
1521
						'</thead>',
1522
		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
1523
		footTemplate: '<tfoot><tr><th colspan="7" class="today"></th></tr></tfoot>'
1524
	};
1525
	DPGlobal.template = '<div class="datetimepicker">'+
1526
							'<div class="datetimepicker-minutes">'+
1527
								'<table class=" table-condensed">'+
1528
									DPGlobal.headTemplate+
1529
									DPGlobal.contTemplate+
1530
									DPGlobal.footTemplate+
1531
								'</table>'+
1532
							'</div>'+
1533
							'<div class="datetimepicker-hours">'+
1534
								'<table class=" table-condensed">'+
1535
									DPGlobal.headTemplate+
1536
									DPGlobal.contTemplate+
1537
									DPGlobal.footTemplate+
1538
								'</table>'+
1539
							'</div>'+
1540
							'<div class="datetimepicker-days">'+
1541
								'<table class=" table-condensed">'+
1542
									DPGlobal.headTemplate+
1543
									'<tbody></tbody>'+
1544
									DPGlobal.footTemplate+
1545
								'</table>'+
1546
							'</div>'+
1547
							'<div class="datetimepicker-months">'+
1548
								'<table class="table-condensed">'+
1549
									DPGlobal.headTemplate+
1550
									DPGlobal.contTemplate+
1551
									DPGlobal.footTemplate+
1552
								'</table>'+
1553
							'</div>'+
1554
							'<div class="datetimepicker-years">'+
1555
								'<table class="table-condensed">'+
1556
									DPGlobal.headTemplate+
1557
									DPGlobal.contTemplate+
1558
									DPGlobal.footTemplate+
1559
								'</table>'+
1560
							'</div>'+
1561
						'</div>';
1562
 
1563
	$.fn.datetimepicker.DPGlobal = DPGlobal;
1564
 
1565
 
1566
	/* DATETIMEPICKER NO CONFLICT
1567
	* =================== */
1568
 
1569
	$.fn.datetimepicker.noConflict = function () {
1570
	    $.fn.datetimepicker = old;
1571
	    return this;
1572
	};
1573
 
1574
 
1575
	/* DATETIMEPICKER DATA-API
1576
	* ================== */
1577
 
1578
	$(document).on(
1579
		'focus.datetimepicker.data-api click.datetimepicker.data-api',
1580
		'[data-provide="datetimepicker"]',
1581
		function (e) {
1582
		    var $this = $(this);
1583
		    if ($this.data('datetimepicker')) return;
1584
		    e.preventDefault();
1585
		    // component click requires us to explicitly show it
1586
		    $this.datetimepicker('show');
1587
		}
1588
	);
1589
	$(function () {
1590
	    $('[data-provide="datetimepicker-inline"]').datetimepicker();
1591
	});
1592
 
1593
}( window.jQuery );