jinda_adminlte 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +5 -5
  2. data/lib/generators/jinda_adminlte/install_generator.rb +0 -2
  3. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/Chart.js +3477 -0
  4. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/bootstrap-datepicker.min.css +7 -0
  5. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/bootstrap-datepicker.min.js +8 -0
  6. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/bootstrap.css +6760 -0
  7. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/bootstrap3-wysihtml5.all.js +14975 -0
  8. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/bootstrap3-wysihtml5.all.min.js +8 -0
  9. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/bootstrap3-wysihtml5.min.css +3 -0
  10. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/daterangepicker.css +269 -0
  11. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/daterangepicker.js +1626 -0
  12. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/daterangepicker.scss +611 -0
  13. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/fastclick.js +841 -0
  14. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/jquery-jvectormap-1.2.2.css +40 -0
  15. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/jquery-jvectormap-1.2.2.min.js +8 -0
  16. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/jquery-jvectormap-world-mill-en.js +1 -0
  17. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/jquery-jvectormap.css +135 -0
  18. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/jquery.knob.min.js +1 -0
  19. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/jquery.min.js +5 -0
  20. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/jquery.slimscroll.min.js +16 -0
  21. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/jquery.sparkline.min.js +6 -0
  22. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/moment.min.js +7 -0
  23. data/lib/generators/jinda_adminlte/templates/application.haml +2 -28
  24. data/lib/generators/jinda_adminlte/templates/application.js +1 -1
  25. data/lib/generators/jinda_adminlte/templates/jindalte.css.scss +2 -1
  26. data/lib/generators/jinda_adminlte/templates/jindalte.js +5 -26
  27. data/lib/jinda_adminlte/version.rb +1 -1
  28. metadata +23 -6
  29. data/lib/generators/jinda_adminlte/templates/app/assets/jinda_assets/bootstrap.min.css +0 -6
  30. data/lib/generators/jinda_adminlte/templates/app/index.mm +0 -180
  31. data/lib/generators/jinda_adminlte/templates/index.mm +0 -184
@@ -0,0 +1,1626 @@
1
+ /**
2
+ * @version: 2.1.25
3
+ * @author: Dan Grossman http://www.dangrossman.info/
4
+ * @copyright: Copyright (c) 2012-2017 Dan Grossman. All rights reserved.
5
+ * @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
6
+ * @website: https://www.daterangepicker.com/
7
+ */
8
+ // Follow the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js
9
+ (function (root, factory) {
10
+ if (typeof define === 'function' && define.amd) {
11
+ // AMD. Make globaly available as well
12
+ define(['moment', 'jquery'], function (moment, jquery) {
13
+ return (root.daterangepicker = factory(moment, jquery));
14
+ });
15
+ } else if (typeof module === 'object' && module.exports) {
16
+ // Node / Browserify
17
+ //isomorphic issue
18
+ var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined;
19
+ if (!jQuery) {
20
+ jQuery = require('jquery');
21
+ if (!jQuery.fn) jQuery.fn = {};
22
+ }
23
+ module.exports = factory(require('moment'), jQuery);
24
+ } else {
25
+ // Browser globals
26
+ root.daterangepicker = factory(root.moment, root.jQuery);
27
+ }
28
+ }(this, function(moment, $) {
29
+ var DateRangePicker = function(element, options, cb) {
30
+
31
+ //default settings for options
32
+ this.parentEl = 'body';
33
+ this.element = $(element);
34
+ this.startDate = moment().startOf('day');
35
+ this.endDate = moment().endOf('day');
36
+ this.minDate = false;
37
+ this.maxDate = false;
38
+ this.dateLimit = false;
39
+ this.autoApply = false;
40
+ this.singleDatePicker = false;
41
+ this.showDropdowns = false;
42
+ this.showWeekNumbers = false;
43
+ this.showISOWeekNumbers = false;
44
+ this.showCustomRangeLabel = true;
45
+ this.timePicker = false;
46
+ this.timePicker24Hour = false;
47
+ this.timePickerIncrement = 1;
48
+ this.timePickerSeconds = false;
49
+ this.linkedCalendars = true;
50
+ this.autoUpdateInput = true;
51
+ this.alwaysShowCalendars = false;
52
+ this.ranges = {};
53
+
54
+ this.opens = 'right';
55
+ if (this.element.hasClass('pull-right'))
56
+ this.opens = 'left';
57
+
58
+ this.drops = 'down';
59
+ if (this.element.hasClass('dropup'))
60
+ this.drops = 'up';
61
+
62
+ this.buttonClasses = 'btn btn-sm';
63
+ this.applyClass = 'btn-success';
64
+ this.cancelClass = 'btn-default';
65
+
66
+ this.locale = {
67
+ direction: 'ltr',
68
+ format: moment.localeData().longDateFormat('L'),
69
+ separator: ' - ',
70
+ applyLabel: 'Apply',
71
+ cancelLabel: 'Cancel',
72
+ weekLabel: 'W',
73
+ customRangeLabel: 'Custom Range',
74
+ daysOfWeek: moment.weekdaysMin(),
75
+ monthNames: moment.monthsShort(),
76
+ firstDay: moment.localeData().firstDayOfWeek()
77
+ };
78
+
79
+ this.callback = function() { };
80
+
81
+ //some state information
82
+ this.isShowing = false;
83
+ this.leftCalendar = {};
84
+ this.rightCalendar = {};
85
+
86
+ //custom options from user
87
+ if (typeof options !== 'object' || options === null)
88
+ options = {};
89
+
90
+ //allow setting options with data attributes
91
+ //data-api options will be overwritten with custom javascript options
92
+ options = $.extend(this.element.data(), options);
93
+
94
+ //html template for the picker UI
95
+ if (typeof options.template !== 'string' && !(options.template instanceof $))
96
+ options.template = '<div class="daterangepicker dropdown-menu">' +
97
+ '<div class="calendar left">' +
98
+ '<div class="daterangepicker_input">' +
99
+ '<input class="input-mini form-control" type="text" name="daterangepicker_start" value="" />' +
100
+ '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
101
+ '<div class="calendar-time">' +
102
+ '<div></div>' +
103
+ '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
104
+ '</div>' +
105
+ '</div>' +
106
+ '<div class="calendar-table"></div>' +
107
+ '</div>' +
108
+ '<div class="calendar right">' +
109
+ '<div class="daterangepicker_input">' +
110
+ '<input class="input-mini form-control" type="text" name="daterangepicker_end" value="" />' +
111
+ '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
112
+ '<div class="calendar-time">' +
113
+ '<div></div>' +
114
+ '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
115
+ '</div>' +
116
+ '</div>' +
117
+ '<div class="calendar-table"></div>' +
118
+ '</div>' +
119
+ '<div class="ranges">' +
120
+ '<div class="range_inputs">' +
121
+ '<button class="applyBtn" disabled="disabled" type="button"></button> ' +
122
+ '<button class="cancelBtn" type="button"></button>' +
123
+ '</div>' +
124
+ '</div>' +
125
+ '</div>';
126
+
127
+ this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
128
+ this.container = $(options.template).appendTo(this.parentEl);
129
+
130
+ //
131
+ // handle all the possible options overriding defaults
132
+ //
133
+
134
+ if (typeof options.locale === 'object') {
135
+
136
+ if (typeof options.locale.direction === 'string')
137
+ this.locale.direction = options.locale.direction;
138
+
139
+ if (typeof options.locale.format === 'string')
140
+ this.locale.format = options.locale.format;
141
+
142
+ if (typeof options.locale.separator === 'string')
143
+ this.locale.separator = options.locale.separator;
144
+
145
+ if (typeof options.locale.daysOfWeek === 'object')
146
+ this.locale.daysOfWeek = options.locale.daysOfWeek.slice();
147
+
148
+ if (typeof options.locale.monthNames === 'object')
149
+ this.locale.monthNames = options.locale.monthNames.slice();
150
+
151
+ if (typeof options.locale.firstDay === 'number')
152
+ this.locale.firstDay = options.locale.firstDay;
153
+
154
+ if (typeof options.locale.applyLabel === 'string')
155
+ this.locale.applyLabel = options.locale.applyLabel;
156
+
157
+ if (typeof options.locale.cancelLabel === 'string')
158
+ this.locale.cancelLabel = options.locale.cancelLabel;
159
+
160
+ if (typeof options.locale.weekLabel === 'string')
161
+ this.locale.weekLabel = options.locale.weekLabel;
162
+
163
+ if (typeof options.locale.customRangeLabel === 'string'){
164
+ //Support unicode chars in the custom range name.
165
+ var elem = document.createElement('textarea');
166
+ elem.innerHTML = options.locale.customRangeLabel;
167
+ var rangeHtml = elem.value;
168
+ this.locale.customRangeLabel = rangeHtml;
169
+ }
170
+ }
171
+ this.container.addClass(this.locale.direction);
172
+
173
+ if (typeof options.startDate === 'string')
174
+ this.startDate = moment(options.startDate, this.locale.format);
175
+
176
+ if (typeof options.endDate === 'string')
177
+ this.endDate = moment(options.endDate, this.locale.format);
178
+
179
+ if (typeof options.minDate === 'string')
180
+ this.minDate = moment(options.minDate, this.locale.format);
181
+
182
+ if (typeof options.maxDate === 'string')
183
+ this.maxDate = moment(options.maxDate, this.locale.format);
184
+
185
+ if (typeof options.startDate === 'object')
186
+ this.startDate = moment(options.startDate);
187
+
188
+ if (typeof options.endDate === 'object')
189
+ this.endDate = moment(options.endDate);
190
+
191
+ if (typeof options.minDate === 'object')
192
+ this.minDate = moment(options.minDate);
193
+
194
+ if (typeof options.maxDate === 'object')
195
+ this.maxDate = moment(options.maxDate);
196
+
197
+ // sanity check for bad options
198
+ if (this.minDate && this.startDate.isBefore(this.minDate))
199
+ this.startDate = this.minDate.clone();
200
+
201
+ // sanity check for bad options
202
+ if (this.maxDate && this.endDate.isAfter(this.maxDate))
203
+ this.endDate = this.maxDate.clone();
204
+
205
+ if (typeof options.applyClass === 'string')
206
+ this.applyClass = options.applyClass;
207
+
208
+ if (typeof options.cancelClass === 'string')
209
+ this.cancelClass = options.cancelClass;
210
+
211
+ if (typeof options.dateLimit === 'object')
212
+ this.dateLimit = options.dateLimit;
213
+
214
+ if (typeof options.opens === 'string')
215
+ this.opens = options.opens;
216
+
217
+ if (typeof options.drops === 'string')
218
+ this.drops = options.drops;
219
+
220
+ if (typeof options.showWeekNumbers === 'boolean')
221
+ this.showWeekNumbers = options.showWeekNumbers;
222
+
223
+ if (typeof options.showISOWeekNumbers === 'boolean')
224
+ this.showISOWeekNumbers = options.showISOWeekNumbers;
225
+
226
+ if (typeof options.buttonClasses === 'string')
227
+ this.buttonClasses = options.buttonClasses;
228
+
229
+ if (typeof options.buttonClasses === 'object')
230
+ this.buttonClasses = options.buttonClasses.join(' ');
231
+
232
+ if (typeof options.showDropdowns === 'boolean')
233
+ this.showDropdowns = options.showDropdowns;
234
+
235
+ if (typeof options.showCustomRangeLabel === 'boolean')
236
+ this.showCustomRangeLabel = options.showCustomRangeLabel;
237
+
238
+ if (typeof options.singleDatePicker === 'boolean') {
239
+ this.singleDatePicker = options.singleDatePicker;
240
+ if (this.singleDatePicker)
241
+ this.endDate = this.startDate.clone();
242
+ }
243
+
244
+ if (typeof options.timePicker === 'boolean')
245
+ this.timePicker = options.timePicker;
246
+
247
+ if (typeof options.timePickerSeconds === 'boolean')
248
+ this.timePickerSeconds = options.timePickerSeconds;
249
+
250
+ if (typeof options.timePickerIncrement === 'number')
251
+ this.timePickerIncrement = options.timePickerIncrement;
252
+
253
+ if (typeof options.timePicker24Hour === 'boolean')
254
+ this.timePicker24Hour = options.timePicker24Hour;
255
+
256
+ if (typeof options.autoApply === 'boolean')
257
+ this.autoApply = options.autoApply;
258
+
259
+ if (typeof options.autoUpdateInput === 'boolean')
260
+ this.autoUpdateInput = options.autoUpdateInput;
261
+
262
+ if (typeof options.linkedCalendars === 'boolean')
263
+ this.linkedCalendars = options.linkedCalendars;
264
+
265
+ if (typeof options.isInvalidDate === 'function')
266
+ this.isInvalidDate = options.isInvalidDate;
267
+
268
+ if (typeof options.isCustomDate === 'function')
269
+ this.isCustomDate = options.isCustomDate;
270
+
271
+ if (typeof options.alwaysShowCalendars === 'boolean')
272
+ this.alwaysShowCalendars = options.alwaysShowCalendars;
273
+
274
+ // update day names order to firstDay
275
+ if (this.locale.firstDay != 0) {
276
+ var iterator = this.locale.firstDay;
277
+ while (iterator > 0) {
278
+ this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
279
+ iterator--;
280
+ }
281
+ }
282
+
283
+ var start, end, range;
284
+
285
+ //if no start/end dates set, check if an input element contains initial values
286
+ if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
287
+ if ($(this.element).is('input[type=text]')) {
288
+ var val = $(this.element).val(),
289
+ split = val.split(this.locale.separator);
290
+
291
+ start = end = null;
292
+
293
+ if (split.length == 2) {
294
+ start = moment(split[0], this.locale.format);
295
+ end = moment(split[1], this.locale.format);
296
+ } else if (this.singleDatePicker && val !== "") {
297
+ start = moment(val, this.locale.format);
298
+ end = moment(val, this.locale.format);
299
+ }
300
+ if (start !== null && end !== null) {
301
+ this.setStartDate(start);
302
+ this.setEndDate(end);
303
+ }
304
+ }
305
+ }
306
+
307
+ if (typeof options.ranges === 'object') {
308
+ for (range in options.ranges) {
309
+
310
+ if (typeof options.ranges[range][0] === 'string')
311
+ start = moment(options.ranges[range][0], this.locale.format);
312
+ else
313
+ start = moment(options.ranges[range][0]);
314
+
315
+ if (typeof options.ranges[range][1] === 'string')
316
+ end = moment(options.ranges[range][1], this.locale.format);
317
+ else
318
+ end = moment(options.ranges[range][1]);
319
+
320
+ // If the start or end date exceed those allowed by the minDate or dateLimit
321
+ // options, shorten the range to the allowable period.
322
+ if (this.minDate && start.isBefore(this.minDate))
323
+ start = this.minDate.clone();
324
+
325
+ var maxDate = this.maxDate;
326
+ if (this.dateLimit && maxDate && start.clone().add(this.dateLimit).isAfter(maxDate))
327
+ maxDate = start.clone().add(this.dateLimit);
328
+ if (maxDate && end.isAfter(maxDate))
329
+ end = maxDate.clone();
330
+
331
+ // If the end of the range is before the minimum or the start of the range is
332
+ // after the maximum, don't display this range option at all.
333
+ if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day'))
334
+ || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day')))
335
+ continue;
336
+
337
+ //Support unicode chars in the range names.
338
+ var elem = document.createElement('textarea');
339
+ elem.innerHTML = range;
340
+ var rangeHtml = elem.value;
341
+
342
+ this.ranges[rangeHtml] = [start, end];
343
+ }
344
+
345
+ var list = '<ul>';
346
+ for (range in this.ranges) {
347
+ list += '<li data-range-key="' + range + '">' + range + '</li>';
348
+ }
349
+ if (this.showCustomRangeLabel) {
350
+ list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + '</li>';
351
+ }
352
+ list += '</ul>';
353
+ this.container.find('.ranges').prepend(list);
354
+ }
355
+
356
+ if (typeof cb === 'function') {
357
+ this.callback = cb;
358
+ }
359
+
360
+ if (!this.timePicker) {
361
+ this.startDate = this.startDate.startOf('day');
362
+ this.endDate = this.endDate.endOf('day');
363
+ this.container.find('.calendar-time').hide();
364
+ }
365
+
366
+ //can't be used together for now
367
+ if (this.timePicker && this.autoApply)
368
+ this.autoApply = false;
369
+
370
+ if (this.autoApply && typeof options.ranges !== 'object') {
371
+ this.container.find('.ranges').hide();
372
+ } else if (this.autoApply) {
373
+ this.container.find('.applyBtn, .cancelBtn').addClass('hide');
374
+ }
375
+
376
+ if (this.singleDatePicker) {
377
+ this.container.addClass('single');
378
+ this.container.find('.calendar.left').addClass('single');
379
+ this.container.find('.calendar.left').show();
380
+ this.container.find('.calendar.right').hide();
381
+ this.container.find('.daterangepicker_input input, .daterangepicker_input > i').hide();
382
+ if (this.timePicker) {
383
+ this.container.find('.ranges ul').hide();
384
+ } else {
385
+ this.container.find('.ranges').hide();
386
+ }
387
+ }
388
+
389
+ if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) {
390
+ this.container.addClass('show-calendar');
391
+ }
392
+
393
+ this.container.addClass('opens' + this.opens);
394
+
395
+ //swap the position of the predefined ranges if opens right
396
+ if (typeof options.ranges !== 'undefined' && this.opens == 'right') {
397
+ this.container.find('.ranges').prependTo( this.container.find('.calendar.left').parent() );
398
+ }
399
+
400
+ //apply CSS classes and labels to buttons
401
+ this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses);
402
+ if (this.applyClass.length)
403
+ this.container.find('.applyBtn').addClass(this.applyClass);
404
+ if (this.cancelClass.length)
405
+ this.container.find('.cancelBtn').addClass(this.cancelClass);
406
+ this.container.find('.applyBtn').html(this.locale.applyLabel);
407
+ this.container.find('.cancelBtn').html(this.locale.cancelLabel);
408
+
409
+ //
410
+ // event listeners
411
+ //
412
+
413
+ this.container.find('.calendar')
414
+ .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
415
+ .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
416
+ .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
417
+ .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
418
+ .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))
419
+ .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
420
+ .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
421
+ .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this))
422
+ .on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this))
423
+ .on('focus.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsFocused, this))
424
+ .on('blur.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsBlurred, this))
425
+ .on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this));
426
+
427
+ this.container.find('.ranges')
428
+ .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
429
+ .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
430
+ .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
431
+ .on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this))
432
+ .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));
433
+
434
+ if (this.element.is('input') || this.element.is('button')) {
435
+ this.element.on({
436
+ 'click.daterangepicker': $.proxy(this.show, this),
437
+ 'focus.daterangepicker': $.proxy(this.show, this),
438
+ 'keyup.daterangepicker': $.proxy(this.elementChanged, this),
439
+ 'keydown.daterangepicker': $.proxy(this.keydown, this)
440
+ });
441
+ } else {
442
+ this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
443
+ }
444
+
445
+ //
446
+ // if attached to a text input, set the initial value
447
+ //
448
+
449
+ if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
450
+ this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
451
+ this.element.trigger('change');
452
+ } else if (this.element.is('input') && this.autoUpdateInput) {
453
+ this.element.val(this.startDate.format(this.locale.format));
454
+ this.element.trigger('change');
455
+ }
456
+
457
+ };
458
+
459
+ DateRangePicker.prototype = {
460
+
461
+ constructor: DateRangePicker,
462
+
463
+ setStartDate: function(startDate) {
464
+ if (typeof startDate === 'string')
465
+ this.startDate = moment(startDate, this.locale.format);
466
+
467
+ if (typeof startDate === 'object')
468
+ this.startDate = moment(startDate);
469
+
470
+ if (!this.timePicker)
471
+ this.startDate = this.startDate.startOf('day');
472
+
473
+ if (this.timePicker && this.timePickerIncrement)
474
+ this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
475
+
476
+ if (this.minDate && this.startDate.isBefore(this.minDate)) {
477
+ this.startDate = this.minDate.clone();
478
+ if (this.timePicker && this.timePickerIncrement)
479
+ this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
480
+ }
481
+
482
+ if (this.maxDate && this.startDate.isAfter(this.maxDate)) {
483
+ this.startDate = this.maxDate.clone();
484
+ if (this.timePicker && this.timePickerIncrement)
485
+ this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
486
+ }
487
+
488
+ if (!this.isShowing)
489
+ this.updateElement();
490
+
491
+ this.updateMonthsInView();
492
+ },
493
+
494
+ setEndDate: function(endDate) {
495
+ if (typeof endDate === 'string')
496
+ this.endDate = moment(endDate, this.locale.format);
497
+
498
+ if (typeof endDate === 'object')
499
+ this.endDate = moment(endDate);
500
+
501
+ if (!this.timePicker)
502
+ this.endDate = this.endDate.endOf('day');
503
+
504
+ if (this.timePicker && this.timePickerIncrement)
505
+ this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
506
+
507
+ if (this.endDate.isBefore(this.startDate))
508
+ this.endDate = this.startDate.clone();
509
+
510
+ if (this.maxDate && this.endDate.isAfter(this.maxDate))
511
+ this.endDate = this.maxDate.clone();
512
+
513
+ if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate))
514
+ this.endDate = this.startDate.clone().add(this.dateLimit);
515
+
516
+ this.previousRightTime = this.endDate.clone();
517
+
518
+ if (!this.isShowing)
519
+ this.updateElement();
520
+
521
+ this.updateMonthsInView();
522
+ },
523
+
524
+ isInvalidDate: function() {
525
+ return false;
526
+ },
527
+
528
+ isCustomDate: function() {
529
+ return false;
530
+ },
531
+
532
+ updateView: function() {
533
+ if (this.timePicker) {
534
+ this.renderTimePicker('left');
535
+ this.renderTimePicker('right');
536
+ if (!this.endDate) {
537
+ this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled');
538
+ } else {
539
+ this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled');
540
+ }
541
+ }
542
+ if (this.endDate) {
543
+ this.container.find('input[name="daterangepicker_end"]').removeClass('active');
544
+ this.container.find('input[name="daterangepicker_start"]').addClass('active');
545
+ } else {
546
+ this.container.find('input[name="daterangepicker_end"]').addClass('active');
547
+ this.container.find('input[name="daterangepicker_start"]').removeClass('active');
548
+ }
549
+ this.updateMonthsInView();
550
+ this.updateCalendars();
551
+ this.updateFormInputs();
552
+ },
553
+
554
+ updateMonthsInView: function() {
555
+ if (this.endDate) {
556
+
557
+ //if both dates are visible already, do nothing
558
+ if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month &&
559
+ (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
560
+ &&
561
+ (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
562
+ ) {
563
+ return;
564
+ }
565
+
566
+ this.leftCalendar.month = this.startDate.clone().date(2);
567
+ if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) {
568
+ this.rightCalendar.month = this.endDate.clone().date(2);
569
+ } else {
570
+ this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
571
+ }
572
+
573
+ } else {
574
+ if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) {
575
+ this.leftCalendar.month = this.startDate.clone().date(2);
576
+ this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
577
+ }
578
+ }
579
+ if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) {
580
+ this.rightCalendar.month = this.maxDate.clone().date(2);
581
+ this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month');
582
+ }
583
+ },
584
+
585
+ updateCalendars: function() {
586
+
587
+ if (this.timePicker) {
588
+ var hour, minute, second;
589
+ if (this.endDate) {
590
+ hour = parseInt(this.container.find('.left .hourselect').val(), 10);
591
+ minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
592
+ second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
593
+ if (!this.timePicker24Hour) {
594
+ var ampm = this.container.find('.left .ampmselect').val();
595
+ if (ampm === 'PM' && hour < 12)
596
+ hour += 12;
597
+ if (ampm === 'AM' && hour === 12)
598
+ hour = 0;
599
+ }
600
+ } else {
601
+ hour = parseInt(this.container.find('.right .hourselect').val(), 10);
602
+ minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
603
+ second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
604
+ if (!this.timePicker24Hour) {
605
+ var ampm = this.container.find('.right .ampmselect').val();
606
+ if (ampm === 'PM' && hour < 12)
607
+ hour += 12;
608
+ if (ampm === 'AM' && hour === 12)
609
+ hour = 0;
610
+ }
611
+ }
612
+ this.leftCalendar.month.hour(hour).minute(minute).second(second);
613
+ this.rightCalendar.month.hour(hour).minute(minute).second(second);
614
+ }
615
+
616
+ this.renderCalendar('left');
617
+ this.renderCalendar('right');
618
+
619
+ //highlight any predefined range matching the current start and end dates
620
+ this.container.find('.ranges li').removeClass('active');
621
+ if (this.endDate == null) return;
622
+
623
+ this.calculateChosenLabel();
624
+ },
625
+
626
+ renderCalendar: function(side) {
627
+
628
+ //
629
+ // Build the matrix of dates that will populate the calendar
630
+ //
631
+
632
+ var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar;
633
+ var month = calendar.month.month();
634
+ var year = calendar.month.year();
635
+ var hour = calendar.month.hour();
636
+ var minute = calendar.month.minute();
637
+ var second = calendar.month.second();
638
+ var daysInMonth = moment([year, month]).daysInMonth();
639
+ var firstDay = moment([year, month, 1]);
640
+ var lastDay = moment([year, month, daysInMonth]);
641
+ var lastMonth = moment(firstDay).subtract(1, 'month').month();
642
+ var lastYear = moment(firstDay).subtract(1, 'month').year();
643
+ var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
644
+ var dayOfWeek = firstDay.day();
645
+
646
+ //initialize a 6 rows x 7 columns array for the calendar
647
+ var calendar = [];
648
+ calendar.firstDay = firstDay;
649
+ calendar.lastDay = lastDay;
650
+
651
+ for (var i = 0; i < 6; i++) {
652
+ calendar[i] = [];
653
+ }
654
+
655
+ //populate the calendar with date objects
656
+ var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;
657
+ if (startDay > daysInLastMonth)
658
+ startDay -= 7;
659
+
660
+ if (dayOfWeek == this.locale.firstDay)
661
+ startDay = daysInLastMonth - 6;
662
+
663
+ var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]);
664
+
665
+ var col, row;
666
+ for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) {
667
+ if (i > 0 && col % 7 === 0) {
668
+ col = 0;
669
+ row++;
670
+ }
671
+ calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second);
672
+ curDate.hour(12);
673
+
674
+ if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') {
675
+ calendar[row][col] = this.minDate.clone();
676
+ }
677
+
678
+ if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') {
679
+ calendar[row][col] = this.maxDate.clone();
680
+ }
681
+
682
+ }
683
+
684
+ //make the calendar object available to hoverDate/clickDate
685
+ if (side == 'left') {
686
+ this.leftCalendar.calendar = calendar;
687
+ } else {
688
+ this.rightCalendar.calendar = calendar;
689
+ }
690
+
691
+ //
692
+ // Display the calendar
693
+ //
694
+
695
+ var minDate = side == 'left' ? this.minDate : this.startDate;
696
+ var maxDate = this.maxDate;
697
+ var selected = side == 'left' ? this.startDate : this.endDate;
698
+ var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'};
699
+
700
+ var html = '<table class="table-condensed">';
701
+ html += '<thead>';
702
+ html += '<tr>';
703
+
704
+ // add empty cell for week number
705
+ if (this.showWeekNumbers || this.showISOWeekNumbers)
706
+ html += '<th></th>';
707
+
708
+ if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) {
709
+ html += '<th class="prev available"><i class="fa fa-' + arrow.left + ' glyphicon glyphicon-' + arrow.left + '"></i></th>';
710
+ } else {
711
+ html += '<th></th>';
712
+ }
713
+
714
+ var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");
715
+
716
+ if (this.showDropdowns) {
717
+ var currentMonth = calendar[1][1].month();
718
+ var currentYear = calendar[1][1].year();
719
+ var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);
720
+ var minYear = (minDate && minDate.year()) || (currentYear - 50);
721
+ var inMinYear = currentYear == minYear;
722
+ var inMaxYear = currentYear == maxYear;
723
+
724
+ var monthHtml = '<select class="monthselect">';
725
+ for (var m = 0; m < 12; m++) {
726
+ if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
727
+ monthHtml += "<option value='" + m + "'" +
728
+ (m === currentMonth ? " selected='selected'" : "") +
729
+ ">" + this.locale.monthNames[m] + "</option>";
730
+ } else {
731
+ monthHtml += "<option value='" + m + "'" +
732
+ (m === currentMonth ? " selected='selected'" : "") +
733
+ " disabled='disabled'>" + this.locale.monthNames[m] + "</option>";
734
+ }
735
+ }
736
+ monthHtml += "</select>";
737
+
738
+ var yearHtml = '<select class="yearselect">';
739
+ for (var y = minYear; y <= maxYear; y++) {
740
+ yearHtml += '<option value="' + y + '"' +
741
+ (y === currentYear ? ' selected="selected"' : '') +
742
+ '>' + y + '</option>';
743
+ }
744
+ yearHtml += '</select>';
745
+
746
+ dateHtml = monthHtml + yearHtml;
747
+ }
748
+
749
+ html += '<th colspan="5" class="month">' + dateHtml + '</th>';
750
+ if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) {
751
+ html += '<th class="next available"><i class="fa fa-' + arrow.right + ' glyphicon glyphicon-' + arrow.right + '"></i></th>';
752
+ } else {
753
+ html += '<th></th>';
754
+ }
755
+
756
+ html += '</tr>';
757
+ html += '<tr>';
758
+
759
+ // add week number label
760
+ if (this.showWeekNumbers || this.showISOWeekNumbers)
761
+ html += '<th class="week">' + this.locale.weekLabel + '</th>';
762
+
763
+ $.each(this.locale.daysOfWeek, function(index, dayOfWeek) {
764
+ html += '<th>' + dayOfWeek + '</th>';
765
+ });
766
+
767
+ html += '</tr>';
768
+ html += '</thead>';
769
+ html += '<tbody>';
770
+
771
+ //adjust maxDate to reflect the dateLimit setting in order to
772
+ //grey out end dates beyond the dateLimit
773
+ if (this.endDate == null && this.dateLimit) {
774
+ var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day');
775
+ if (!maxDate || maxLimit.isBefore(maxDate)) {
776
+ maxDate = maxLimit;
777
+ }
778
+ }
779
+
780
+ for (var row = 0; row < 6; row++) {
781
+ html += '<tr>';
782
+
783
+ // add week number
784
+ if (this.showWeekNumbers)
785
+ html += '<td class="week">' + calendar[row][0].week() + '</td>';
786
+ else if (this.showISOWeekNumbers)
787
+ html += '<td class="week">' + calendar[row][0].isoWeek() + '</td>';
788
+
789
+ for (var col = 0; col < 7; col++) {
790
+
791
+ var classes = [];
792
+
793
+ //highlight today's date
794
+ if (calendar[row][col].isSame(new Date(), "day"))
795
+ classes.push('today');
796
+
797
+ //highlight weekends
798
+ if (calendar[row][col].isoWeekday() > 5)
799
+ classes.push('weekend');
800
+
801
+ //grey out the dates in other months displayed at beginning and end of this calendar
802
+ if (calendar[row][col].month() != calendar[1][1].month())
803
+ classes.push('off');
804
+
805
+ //don't allow selection of dates before the minimum date
806
+ if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day'))
807
+ classes.push('off', 'disabled');
808
+
809
+ //don't allow selection of dates after the maximum date
810
+ if (maxDate && calendar[row][col].isAfter(maxDate, 'day'))
811
+ classes.push('off', 'disabled');
812
+
813
+ //don't allow selection of date if a custom function decides it's invalid
814
+ if (this.isInvalidDate(calendar[row][col]))
815
+ classes.push('off', 'disabled');
816
+
817
+ //highlight the currently selected start date
818
+ if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD'))
819
+ classes.push('active', 'start-date');
820
+
821
+ //highlight the currently selected end date
822
+ if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD'))
823
+ classes.push('active', 'end-date');
824
+
825
+ //highlight dates in-between the selected dates
826
+ if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate)
827
+ classes.push('in-range');
828
+
829
+ //apply custom classes for this date
830
+ var isCustom = this.isCustomDate(calendar[row][col]);
831
+ if (isCustom !== false) {
832
+ if (typeof isCustom === 'string')
833
+ classes.push(isCustom);
834
+ else
835
+ Array.prototype.push.apply(classes, isCustom);
836
+ }
837
+
838
+ var cname = '', disabled = false;
839
+ for (var i = 0; i < classes.length; i++) {
840
+ cname += classes[i] + ' ';
841
+ if (classes[i] == 'disabled')
842
+ disabled = true;
843
+ }
844
+ if (!disabled)
845
+ cname += 'available';
846
+
847
+ html += '<td class="' + cname.replace(/^\s+|\s+$/g, '') + '" data-title="' + 'r' + row + 'c' + col + '">' + calendar[row][col].date() + '</td>';
848
+
849
+ }
850
+ html += '</tr>';
851
+ }
852
+
853
+ html += '</tbody>';
854
+ html += '</table>';
855
+
856
+ this.container.find('.calendar.' + side + ' .calendar-table').html(html);
857
+
858
+ },
859
+
860
+ renderTimePicker: function(side) {
861
+
862
+ // Don't bother updating the time picker if it's currently disabled
863
+ // because an end date hasn't been clicked yet
864
+ if (side == 'right' && !this.endDate) return;
865
+
866
+ var html, selected, minDate, maxDate = this.maxDate;
867
+
868
+ if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate)))
869
+ maxDate = this.startDate.clone().add(this.dateLimit);
870
+
871
+ if (side == 'left') {
872
+ selected = this.startDate.clone();
873
+ minDate = this.minDate;
874
+ } else if (side == 'right') {
875
+ selected = this.endDate.clone();
876
+ minDate = this.startDate;
877
+
878
+ //Preserve the time already selected
879
+ var timeSelector = this.container.find('.calendar.right .calendar-time div');
880
+ if (timeSelector.html() != '') {
881
+
882
+ selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour());
883
+ selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute());
884
+ selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second());
885
+
886
+ if (!this.timePicker24Hour) {
887
+ var ampm = timeSelector.find('.ampmselect option:selected').val();
888
+ if (ampm === 'PM' && selected.hour() < 12)
889
+ selected.hour(selected.hour() + 12);
890
+ if (ampm === 'AM' && selected.hour() === 12)
891
+ selected.hour(0);
892
+ }
893
+
894
+ }
895
+
896
+ if (selected.isBefore(this.startDate))
897
+ selected = this.startDate.clone();
898
+
899
+ if (maxDate && selected.isAfter(maxDate))
900
+ selected = maxDate.clone();
901
+
902
+ }
903
+
904
+ //
905
+ // hours
906
+ //
907
+
908
+ html = '<select class="hourselect">';
909
+
910
+ var start = this.timePicker24Hour ? 0 : 1;
911
+ var end = this.timePicker24Hour ? 23 : 12;
912
+
913
+ for (var i = start; i <= end; i++) {
914
+ var i_in_24 = i;
915
+ if (!this.timePicker24Hour)
916
+ i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i);
917
+
918
+ var time = selected.clone().hour(i_in_24);
919
+ var disabled = false;
920
+ if (minDate && time.minute(59).isBefore(minDate))
921
+ disabled = true;
922
+ if (maxDate && time.minute(0).isAfter(maxDate))
923
+ disabled = true;
924
+
925
+ if (i_in_24 == selected.hour() && !disabled) {
926
+ html += '<option value="' + i + '" selected="selected">' + i + '</option>';
927
+ } else if (disabled) {
928
+ html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>';
929
+ } else {
930
+ html += '<option value="' + i + '">' + i + '</option>';
931
+ }
932
+ }
933
+
934
+ html += '</select> ';
935
+
936
+ //
937
+ // minutes
938
+ //
939
+
940
+ html += ': <select class="minuteselect">';
941
+
942
+ for (var i = 0; i < 60; i += this.timePickerIncrement) {
943
+ var padded = i < 10 ? '0' + i : i;
944
+ var time = selected.clone().minute(i);
945
+
946
+ var disabled = false;
947
+ if (minDate && time.second(59).isBefore(minDate))
948
+ disabled = true;
949
+ if (maxDate && time.second(0).isAfter(maxDate))
950
+ disabled = true;
951
+
952
+ if (selected.minute() == i && !disabled) {
953
+ html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
954
+ } else if (disabled) {
955
+ html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
956
+ } else {
957
+ html += '<option value="' + i + '">' + padded + '</option>';
958
+ }
959
+ }
960
+
961
+ html += '</select> ';
962
+
963
+ //
964
+ // seconds
965
+ //
966
+
967
+ if (this.timePickerSeconds) {
968
+ html += ': <select class="secondselect">';
969
+
970
+ for (var i = 0; i < 60; i++) {
971
+ var padded = i < 10 ? '0' + i : i;
972
+ var time = selected.clone().second(i);
973
+
974
+ var disabled = false;
975
+ if (minDate && time.isBefore(minDate))
976
+ disabled = true;
977
+ if (maxDate && time.isAfter(maxDate))
978
+ disabled = true;
979
+
980
+ if (selected.second() == i && !disabled) {
981
+ html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
982
+ } else if (disabled) {
983
+ html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
984
+ } else {
985
+ html += '<option value="' + i + '">' + padded + '</option>';
986
+ }
987
+ }
988
+
989
+ html += '</select> ';
990
+ }
991
+
992
+ //
993
+ // AM/PM
994
+ //
995
+
996
+ if (!this.timePicker24Hour) {
997
+ html += '<select class="ampmselect">';
998
+
999
+ var am_html = '';
1000
+ var pm_html = '';
1001
+
1002
+ if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate))
1003
+ am_html = ' disabled="disabled" class="disabled"';
1004
+
1005
+ if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate))
1006
+ pm_html = ' disabled="disabled" class="disabled"';
1007
+
1008
+ if (selected.hour() >= 12) {
1009
+ html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>';
1010
+ } else {
1011
+ html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>';
1012
+ }
1013
+
1014
+ html += '</select>';
1015
+ }
1016
+
1017
+ this.container.find('.calendar.' + side + ' .calendar-time div').html(html);
1018
+
1019
+ },
1020
+
1021
+ updateFormInputs: function() {
1022
+
1023
+ //ignore mouse movements while an above-calendar text input has focus
1024
+ if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1025
+ return;
1026
+
1027
+ this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format));
1028
+ if (this.endDate)
1029
+ this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format));
1030
+
1031
+ if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) {
1032
+ this.container.find('button.applyBtn').removeAttr('disabled');
1033
+ } else {
1034
+ this.container.find('button.applyBtn').attr('disabled', 'disabled');
1035
+ }
1036
+
1037
+ },
1038
+
1039
+ move: function() {
1040
+ var parentOffset = { top: 0, left: 0 },
1041
+ containerTop;
1042
+ var parentRightEdge = $(window).width();
1043
+ if (!this.parentEl.is('body')) {
1044
+ parentOffset = {
1045
+ top: this.parentEl.offset().top - this.parentEl.scrollTop(),
1046
+ left: this.parentEl.offset().left - this.parentEl.scrollLeft()
1047
+ };
1048
+ parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;
1049
+ }
1050
+
1051
+ if (this.drops == 'up')
1052
+ containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
1053
+ else
1054
+ containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;
1055
+ this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup');
1056
+
1057
+ if (this.opens == 'left') {
1058
+ this.container.css({
1059
+ top: containerTop,
1060
+ right: parentRightEdge - this.element.offset().left - this.element.outerWidth(),
1061
+ left: 'auto'
1062
+ });
1063
+ if (this.container.offset().left < 0) {
1064
+ this.container.css({
1065
+ right: 'auto',
1066
+ left: 9
1067
+ });
1068
+ }
1069
+ } else if (this.opens == 'center') {
1070
+ this.container.css({
1071
+ top: containerTop,
1072
+ left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2
1073
+ - this.container.outerWidth() / 2,
1074
+ right: 'auto'
1075
+ });
1076
+ if (this.container.offset().left < 0) {
1077
+ this.container.css({
1078
+ right: 'auto',
1079
+ left: 9
1080
+ });
1081
+ }
1082
+ } else {
1083
+ this.container.css({
1084
+ top: containerTop,
1085
+ left: this.element.offset().left - parentOffset.left,
1086
+ right: 'auto'
1087
+ });
1088
+ if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
1089
+ this.container.css({
1090
+ left: 'auto',
1091
+ right: 0
1092
+ });
1093
+ }
1094
+ }
1095
+ },
1096
+
1097
+ show: function(e) {
1098
+ if (this.isShowing) return;
1099
+
1100
+ // Create a click proxy that is private to this instance of datepicker, for unbinding
1101
+ this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this);
1102
+
1103
+ // Bind global datepicker mousedown for hiding and
1104
+ $(document)
1105
+ .on('mousedown.daterangepicker', this._outsideClickProxy)
1106
+ // also support mobile devices
1107
+ .on('touchend.daterangepicker', this._outsideClickProxy)
1108
+ // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them
1109
+ .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)
1110
+ // and also close when focus changes to outside the picker (eg. tabbing between controls)
1111
+ .on('focusin.daterangepicker', this._outsideClickProxy);
1112
+
1113
+ // Reposition the picker if the window is resized while it's open
1114
+ $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this));
1115
+
1116
+ this.oldStartDate = this.startDate.clone();
1117
+ this.oldEndDate = this.endDate.clone();
1118
+ this.previousRightTime = this.endDate.clone();
1119
+
1120
+ this.updateView();
1121
+ this.container.show();
1122
+ this.move();
1123
+ this.element.trigger('show.daterangepicker', this);
1124
+ this.isShowing = true;
1125
+ },
1126
+
1127
+ hide: function(e) {
1128
+ if (!this.isShowing) return;
1129
+
1130
+ //incomplete date selection, revert to last values
1131
+ if (!this.endDate) {
1132
+ this.startDate = this.oldStartDate.clone();
1133
+ this.endDate = this.oldEndDate.clone();
1134
+ }
1135
+
1136
+ //if a new date range was selected, invoke the user callback function
1137
+ if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
1138
+ this.callback(this.startDate, this.endDate, this.chosenLabel);
1139
+
1140
+ //if picker is attached to a text input, update it
1141
+ this.updateElement();
1142
+
1143
+ $(document).off('.daterangepicker');
1144
+ $(window).off('.daterangepicker');
1145
+ this.container.hide();
1146
+ this.element.trigger('hide.daterangepicker', this);
1147
+ this.isShowing = false;
1148
+ },
1149
+
1150
+ toggle: function(e) {
1151
+ if (this.isShowing) {
1152
+ this.hide();
1153
+ } else {
1154
+ this.show();
1155
+ }
1156
+ },
1157
+
1158
+ outsideClick: function(e) {
1159
+ var target = $(e.target);
1160
+ // if the page is clicked anywhere except within the daterangerpicker/button
1161
+ // itself then call this.hide()
1162
+ if (
1163
+ // ie modal dialog fix
1164
+ e.type == "focusin" ||
1165
+ target.closest(this.element).length ||
1166
+ target.closest(this.container).length ||
1167
+ target.closest('.calendar-table').length
1168
+ ) return;
1169
+ this.hide();
1170
+ this.element.trigger('outsideClick.daterangepicker', this);
1171
+ },
1172
+
1173
+ showCalendars: function() {
1174
+ this.container.addClass('show-calendar');
1175
+ this.move();
1176
+ this.element.trigger('showCalendar.daterangepicker', this);
1177
+ },
1178
+
1179
+ hideCalendars: function() {
1180
+ this.container.removeClass('show-calendar');
1181
+ this.element.trigger('hideCalendar.daterangepicker', this);
1182
+ },
1183
+
1184
+ hoverRange: function(e) {
1185
+
1186
+ //ignore mouse movements while an above-calendar text input has focus
1187
+ if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1188
+ return;
1189
+
1190
+ var label = e.target.getAttribute('data-range-key');
1191
+
1192
+ if (label == this.locale.customRangeLabel) {
1193
+ this.updateView();
1194
+ } else {
1195
+ var dates = this.ranges[label];
1196
+ this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format));
1197
+ this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format));
1198
+ }
1199
+
1200
+ },
1201
+
1202
+ clickRange: function(e) {
1203
+ var label = e.target.getAttribute('data-range-key');
1204
+ this.chosenLabel = label;
1205
+ if (label == this.locale.customRangeLabel) {
1206
+ this.showCalendars();
1207
+ } else {
1208
+ var dates = this.ranges[label];
1209
+ this.startDate = dates[0];
1210
+ this.endDate = dates[1];
1211
+
1212
+ if (!this.timePicker) {
1213
+ this.startDate.startOf('day');
1214
+ this.endDate.endOf('day');
1215
+ }
1216
+
1217
+ if (!this.alwaysShowCalendars)
1218
+ this.hideCalendars();
1219
+ this.clickApply();
1220
+ }
1221
+ },
1222
+
1223
+ clickPrev: function(e) {
1224
+ var cal = $(e.target).parents('.calendar');
1225
+ if (cal.hasClass('left')) {
1226
+ this.leftCalendar.month.subtract(1, 'month');
1227
+ if (this.linkedCalendars)
1228
+ this.rightCalendar.month.subtract(1, 'month');
1229
+ } else {
1230
+ this.rightCalendar.month.subtract(1, 'month');
1231
+ }
1232
+ this.updateCalendars();
1233
+ },
1234
+
1235
+ clickNext: function(e) {
1236
+ var cal = $(e.target).parents('.calendar');
1237
+ if (cal.hasClass('left')) {
1238
+ this.leftCalendar.month.add(1, 'month');
1239
+ } else {
1240
+ this.rightCalendar.month.add(1, 'month');
1241
+ if (this.linkedCalendars)
1242
+ this.leftCalendar.month.add(1, 'month');
1243
+ }
1244
+ this.updateCalendars();
1245
+ },
1246
+
1247
+ hoverDate: function(e) {
1248
+
1249
+ //ignore mouse movements while an above-calendar text input has focus
1250
+ //if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1251
+ // return;
1252
+
1253
+ //ignore dates that can't be selected
1254
+ if (!$(e.target).hasClass('available')) return;
1255
+
1256
+ //have the text inputs above calendars reflect the date being hovered over
1257
+ var title = $(e.target).attr('data-title');
1258
+ var row = title.substr(1, 1);
1259
+ var col = title.substr(3, 1);
1260
+ var cal = $(e.target).parents('.calendar');
1261
+ var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
1262
+
1263
+ if (this.endDate && !this.container.find('input[name=daterangepicker_start]').is(":focus")) {
1264
+ this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format));
1265
+ } else if (!this.endDate && !this.container.find('input[name=daterangepicker_end]').is(":focus")) {
1266
+ this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format));
1267
+ }
1268
+
1269
+ //highlight the dates between the start date and the date being hovered as a potential end date
1270
+ var leftCalendar = this.leftCalendar;
1271
+ var rightCalendar = this.rightCalendar;
1272
+ var startDate = this.startDate;
1273
+ if (!this.endDate) {
1274
+ this.container.find('.calendar tbody td').each(function(index, el) {
1275
+
1276
+ //skip week numbers, only look at dates
1277
+ if ($(el).hasClass('week')) return;
1278
+
1279
+ var title = $(el).attr('data-title');
1280
+ var row = title.substr(1, 1);
1281
+ var col = title.substr(3, 1);
1282
+ var cal = $(el).parents('.calendar');
1283
+ var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];
1284
+
1285
+ if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) {
1286
+ $(el).addClass('in-range');
1287
+ } else {
1288
+ $(el).removeClass('in-range');
1289
+ }
1290
+
1291
+ });
1292
+ }
1293
+
1294
+ },
1295
+
1296
+ clickDate: function(e) {
1297
+
1298
+ if (!$(e.target).hasClass('available')) return;
1299
+
1300
+ var title = $(e.target).attr('data-title');
1301
+ var row = title.substr(1, 1);
1302
+ var col = title.substr(3, 1);
1303
+ var cal = $(e.target).parents('.calendar');
1304
+ var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
1305
+
1306
+ //
1307
+ // this function needs to do a few things:
1308
+ // * alternate between selecting a start and end date for the range,
1309
+ // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date
1310
+ // * if autoapply is enabled, and an end date was chosen, apply the selection
1311
+ // * if single date picker mode, and time picker isn't enabled, apply the selection immediately
1312
+ // * if one of the inputs above the calendars was focused, cancel that manual input
1313
+ //
1314
+
1315
+ if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start
1316
+ if (this.timePicker) {
1317
+ var hour = parseInt(this.container.find('.left .hourselect').val(), 10);
1318
+ if (!this.timePicker24Hour) {
1319
+ var ampm = this.container.find('.left .ampmselect').val();
1320
+ if (ampm === 'PM' && hour < 12)
1321
+ hour += 12;
1322
+ if (ampm === 'AM' && hour === 12)
1323
+ hour = 0;
1324
+ }
1325
+ var minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
1326
+ var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
1327
+ date = date.clone().hour(hour).minute(minute).second(second);
1328
+ }
1329
+ this.endDate = null;
1330
+ this.setStartDate(date.clone());
1331
+ } else if (!this.endDate && date.isBefore(this.startDate)) {
1332
+ //special case: clicking the same date for start/end,
1333
+ //but the time of the end date is before the start date
1334
+ this.setEndDate(this.startDate.clone());
1335
+ } else { // picking end
1336
+ if (this.timePicker) {
1337
+ var hour = parseInt(this.container.find('.right .hourselect').val(), 10);
1338
+ if (!this.timePicker24Hour) {
1339
+ var ampm = this.container.find('.right .ampmselect').val();
1340
+ if (ampm === 'PM' && hour < 12)
1341
+ hour += 12;
1342
+ if (ampm === 'AM' && hour === 12)
1343
+ hour = 0;
1344
+ }
1345
+ var minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
1346
+ var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
1347
+ date = date.clone().hour(hour).minute(minute).second(second);
1348
+ }
1349
+ this.setEndDate(date.clone());
1350
+ if (this.autoApply) {
1351
+ this.calculateChosenLabel();
1352
+ this.clickApply();
1353
+ }
1354
+ }
1355
+
1356
+ if (this.singleDatePicker) {
1357
+ this.setEndDate(this.startDate);
1358
+ if (!this.timePicker)
1359
+ this.clickApply();
1360
+ }
1361
+
1362
+ this.updateView();
1363
+
1364
+ //This is to cancel the blur event handler if the mouse was in one of the inputs
1365
+ e.stopPropagation();
1366
+
1367
+ },
1368
+
1369
+ calculateChosenLabel: function () {
1370
+ var customRange = true;
1371
+ var i = 0;
1372
+ for (var range in this.ranges) {
1373
+ if (this.timePicker) {
1374
+ if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {
1375
+ customRange = false;
1376
+ this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();
1377
+ break;
1378
+ }
1379
+ } else {
1380
+ //ignore times when comparing dates if time picker is not enabled
1381
+ if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) {
1382
+ customRange = false;
1383
+ this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();
1384
+ break;
1385
+ }
1386
+ }
1387
+ i++;
1388
+ }
1389
+ if (customRange) {
1390
+ if (this.showCustomRangeLabel) {
1391
+ this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html();
1392
+ } else {
1393
+ this.chosenLabel = null;
1394
+ }
1395
+ this.showCalendars();
1396
+ }
1397
+ },
1398
+
1399
+ clickApply: function(e) {
1400
+ this.hide();
1401
+ this.element.trigger('apply.daterangepicker', this);
1402
+ },
1403
+
1404
+ clickCancel: function(e) {
1405
+ this.startDate = this.oldStartDate;
1406
+ this.endDate = this.oldEndDate;
1407
+ this.hide();
1408
+ this.element.trigger('cancel.daterangepicker', this);
1409
+ },
1410
+
1411
+ monthOrYearChanged: function(e) {
1412
+ var isLeft = $(e.target).closest('.calendar').hasClass('left'),
1413
+ leftOrRight = isLeft ? 'left' : 'right',
1414
+ cal = this.container.find('.calendar.'+leftOrRight);
1415
+
1416
+ // Month must be Number for new moment versions
1417
+ var month = parseInt(cal.find('.monthselect').val(), 10);
1418
+ var year = cal.find('.yearselect').val();
1419
+
1420
+ if (!isLeft) {
1421
+ if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) {
1422
+ month = this.startDate.month();
1423
+ year = this.startDate.year();
1424
+ }
1425
+ }
1426
+
1427
+ if (this.minDate) {
1428
+ if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) {
1429
+ month = this.minDate.month();
1430
+ year = this.minDate.year();
1431
+ }
1432
+ }
1433
+
1434
+ if (this.maxDate) {
1435
+ if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) {
1436
+ month = this.maxDate.month();
1437
+ year = this.maxDate.year();
1438
+ }
1439
+ }
1440
+
1441
+ if (isLeft) {
1442
+ this.leftCalendar.month.month(month).year(year);
1443
+ if (this.linkedCalendars)
1444
+ this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month');
1445
+ } else {
1446
+ this.rightCalendar.month.month(month).year(year);
1447
+ if (this.linkedCalendars)
1448
+ this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month');
1449
+ }
1450
+ this.updateCalendars();
1451
+ },
1452
+
1453
+ timeChanged: function(e) {
1454
+
1455
+ var cal = $(e.target).closest('.calendar'),
1456
+ isLeft = cal.hasClass('left');
1457
+
1458
+ var hour = parseInt(cal.find('.hourselect').val(), 10);
1459
+ var minute = parseInt(cal.find('.minuteselect').val(), 10);
1460
+ var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0;
1461
+
1462
+ if (!this.timePicker24Hour) {
1463
+ var ampm = cal.find('.ampmselect').val();
1464
+ if (ampm === 'PM' && hour < 12)
1465
+ hour += 12;
1466
+ if (ampm === 'AM' && hour === 12)
1467
+ hour = 0;
1468
+ }
1469
+
1470
+ if (isLeft) {
1471
+ var start = this.startDate.clone();
1472
+ start.hour(hour);
1473
+ start.minute(minute);
1474
+ start.second(second);
1475
+ this.setStartDate(start);
1476
+ if (this.singleDatePicker) {
1477
+ this.endDate = this.startDate.clone();
1478
+ } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) {
1479
+ this.setEndDate(start.clone());
1480
+ }
1481
+ } else if (this.endDate) {
1482
+ var end = this.endDate.clone();
1483
+ end.hour(hour);
1484
+ end.minute(minute);
1485
+ end.second(second);
1486
+ this.setEndDate(end);
1487
+ }
1488
+
1489
+ //update the calendars so all clickable dates reflect the new time component
1490
+ this.updateCalendars();
1491
+
1492
+ //update the form inputs above the calendars with the new time
1493
+ this.updateFormInputs();
1494
+
1495
+ //re-render the time pickers because changing one selection can affect what's enabled in another
1496
+ this.renderTimePicker('left');
1497
+ this.renderTimePicker('right');
1498
+
1499
+ },
1500
+
1501
+ formInputsChanged: function(e) {
1502
+ var isRight = $(e.target).closest('.calendar').hasClass('right');
1503
+ var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format);
1504
+ var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format);
1505
+
1506
+ if (start.isValid() && end.isValid()) {
1507
+
1508
+ if (isRight && end.isBefore(start))
1509
+ start = end.clone();
1510
+
1511
+ this.setStartDate(start);
1512
+ this.setEndDate(end);
1513
+
1514
+ if (isRight) {
1515
+ this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format));
1516
+ } else {
1517
+ this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format));
1518
+ }
1519
+
1520
+ }
1521
+
1522
+ this.updateView();
1523
+ },
1524
+
1525
+ formInputsFocused: function(e) {
1526
+
1527
+ // Highlight the focused input
1528
+ this.container.find('input[name="daterangepicker_start"], input[name="daterangepicker_end"]').removeClass('active');
1529
+ $(e.target).addClass('active');
1530
+
1531
+ // Set the state such that if the user goes back to using a mouse,
1532
+ // the calendars are aware we're selecting the end of the range, not
1533
+ // the start. This allows someone to edit the end of a date range without
1534
+ // re-selecting the beginning, by clicking on the end date input then
1535
+ // using the calendar.
1536
+ var isRight = $(e.target).closest('.calendar').hasClass('right');
1537
+ if (isRight) {
1538
+ this.endDate = null;
1539
+ this.setStartDate(this.startDate.clone());
1540
+ this.updateView();
1541
+ }
1542
+
1543
+ },
1544
+
1545
+ formInputsBlurred: function(e) {
1546
+
1547
+ // this function has one purpose right now: if you tab from the first
1548
+ // text input to the second in the UI, the endDate is nulled so that
1549
+ // you can click another, but if you tab out without clicking anything
1550
+ // or changing the input value, the old endDate should be retained
1551
+
1552
+ if (!this.endDate) {
1553
+ var val = this.container.find('input[name="daterangepicker_end"]').val();
1554
+ var end = moment(val, this.locale.format);
1555
+ if (end.isValid()) {
1556
+ this.setEndDate(end);
1557
+ this.updateView();
1558
+ }
1559
+ }
1560
+
1561
+ },
1562
+
1563
+ elementChanged: function() {
1564
+ if (!this.element.is('input')) return;
1565
+ if (!this.element.val().length) return;
1566
+ if (this.element.val().length < this.locale.format.length) return;
1567
+
1568
+ var dateString = this.element.val().split(this.locale.separator),
1569
+ start = null,
1570
+ end = null;
1571
+
1572
+ if (dateString.length === 2) {
1573
+ start = moment(dateString[0], this.locale.format);
1574
+ end = moment(dateString[1], this.locale.format);
1575
+ }
1576
+
1577
+ if (this.singleDatePicker || start === null || end === null) {
1578
+ start = moment(this.element.val(), this.locale.format);
1579
+ end = start;
1580
+ }
1581
+
1582
+ if (!start.isValid() || !end.isValid()) return;
1583
+
1584
+ this.setStartDate(start);
1585
+ this.setEndDate(end);
1586
+ this.updateView();
1587
+ },
1588
+
1589
+ keydown: function(e) {
1590
+ //hide on tab or enter
1591
+ if ((e.keyCode === 9) || (e.keyCode === 13)) {
1592
+ this.hide();
1593
+ }
1594
+ },
1595
+
1596
+ updateElement: function() {
1597
+ if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
1598
+ this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
1599
+ this.element.trigger('change');
1600
+ } else if (this.element.is('input') && this.autoUpdateInput) {
1601
+ this.element.val(this.startDate.format(this.locale.format));
1602
+ this.element.trigger('change');
1603
+ }
1604
+ },
1605
+
1606
+ remove: function() {
1607
+ this.container.remove();
1608
+ this.element.off('.daterangepicker');
1609
+ this.element.removeData();
1610
+ }
1611
+
1612
+ };
1613
+
1614
+ $.fn.daterangepicker = function(options, callback) {
1615
+ this.each(function() {
1616
+ var el = $(this);
1617
+ if (el.data('daterangepicker'))
1618
+ el.data('daterangepicker').remove();
1619
+ el.data('daterangepicker', new DateRangePicker(el, options, callback));
1620
+ });
1621
+ return this;
1622
+ };
1623
+
1624
+ return DateRangePicker;
1625
+
1626
+ }));