bootstrap-daterangepicker-rails 0.1.1 → 0.1.2

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