bootstrap-daterangepicker-rails 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Date Range Picker for Twitter Bootstrap
2
2
 
3
+ To use with Rails 4.x, use this branch: https://github.com/jordanbrock/bootstrap-daterangepicker-rails/tree/rails4
4
+
5
+ Thanks to https://github.com/allomov for doing all the work on the 4.x branch.
6
+
7
+
3
8
  _Description from DateRangePicker for Twitter Bootstrap_
4
9
 
5
10
  This date range picker component for Twitter Bootstrap creates a dropdown menu from which a user can
@@ -29,7 +34,7 @@ gem 'coffee-rails'
29
34
 
30
35
  # application.js
31
36
 
32
- //= require date
37
+ //= require moment
33
38
  //= require daterangepicker
34
39
 
35
40
 
@@ -1,7 +1,7 @@
1
1
  module Bootstrap
2
2
  module Daterangepicker
3
3
  module Rails
4
- VERSION = '0.0.5'
4
+ VERSION = '0.0.6'
5
5
  end
6
6
  end
7
7
  end
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @version: 1.1
2
+ * @version: 1.2
3
3
  * @author: Dan Grossman http://www.dangrossman.info/
4
- * @date: 2013-03-04
5
- * @copyright: Copyright (c) 2012 Dan Grossman. All rights reserved.
4
+ * @date: 2013-07-25
5
+ * @copyright: Copyright (c) 2012-2013 Dan Grossman. All rights reserved.
6
6
  * @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0
7
7
  * @website: http://www.improvely.com/
8
8
  */
@@ -12,64 +12,46 @@
12
12
  var hasOptions = typeof options == 'object';
13
13
  var localeObject;
14
14
 
15
- //state
16
- this.startDate = Date.today();
17
- this.endDate = Date.today();
15
+ //option defaults
16
+
17
+ this.startDate = moment().startOf('day');
18
+ this.endDate = moment().startOf('day');
18
19
  this.minDate = false;
19
20
  this.maxDate = false;
20
- this.changed = false;
21
- this.cleared = false;
22
- this.showDropdowns = false;
23
- this.ranges = {};
24
21
  this.dateLimit = false;
22
+
23
+ this.showDropdowns = false;
24
+ this.showWeekNumbers = false;
25
+ this.timePicker = false;
26
+ this.timePickerIncrement = 30;
27
+ this.timePicker12Hour = true;
28
+ this.ranges = {};
25
29
  this.opens = 'right';
26
- this.cb = function () { };
27
- this.format = 'MM/dd/yyyy';
30
+
31
+ this.buttonClasses = ['btn', 'btn-small'];
32
+ this.applyClass = 'btn-success';
33
+ this.cancelClass = 'btn-default';
34
+
35
+ this.format = 'MM/DD/YYYY';
28
36
  this.separator = ' - ';
29
- this.showWeekNumbers = false;
30
- this.buttonClasses = ['btn-success'];
31
- this.applyClass = 'btn btn-small btn-success';
32
- this.clearClass = 'btn btn-small';
37
+
33
38
  this.locale = {
34
39
  applyLabel: 'Apply',
35
- clearLabel:"Clear",
40
+ cancelLabel: 'Cancel',
36
41
  fromLabel: 'From',
37
42
  toLabel: 'To',
38
43
  weekLabel: 'W',
39
44
  customRangeLabel: 'Custom Range',
40
- daysOfWeek: Date.CultureInfo.shortestDayNames,
41
- monthNames: Date.CultureInfo.monthNames,
45
+ daysOfWeek: moment()._lang._weekdaysMin,
46
+ monthNames: moment()._lang._monthsShort,
42
47
  firstDay: 0
43
48
  };
44
49
 
45
- localeObject = this.locale;
46
-
47
- this.leftCalendar = {
48
- month: Date.today().set({ day: 1, month: this.startDate.getMonth(), year: this.startDate.getFullYear() }),
49
- calendar: Array()
50
- };
51
-
52
- this.rightCalendar = {
53
- month: Date.today().set({ day: 1, month: this.endDate.getMonth(), year: this.endDate.getFullYear() }),
54
- calendar: Array()
55
- };
50
+ this.cb = function () { };
56
51
 
57
52
  //element that triggered the date range picker
58
53
  this.element = $(element);
59
54
 
60
- //try parse date if in text input
61
- if (!hasOptions || (typeof options.startDate == 'undefined' && typeof options.endDate == 'undefined')) {
62
- if ($(this.element).is('input[type=text]')) {
63
- var val = $(this.element).val();
64
- var split = val.split(this.separator);
65
-
66
- if(split.length == 2) {
67
- this.startDate = Date.parseExact(split[0], this.format);
68
- this.endDate = Date.parseExact(split[1], this.format);
69
- }
70
- }
71
- }
72
-
73
55
  if (this.element.hasClass('pull-right'))
74
56
  this.opens = 'left';
75
57
 
@@ -82,8 +64,10 @@
82
64
  this.element.on('click', $.proxy(this.show, this));
83
65
  }
84
66
 
67
+ localeObject = this.locale;
68
+
85
69
  if (hasOptions) {
86
- if(typeof options.locale == 'object') {
70
+ if (typeof options.locale == 'object') {
87
71
  $.each(localeObject, function (property, value) {
88
72
  localeObject[property] = options.locale[property] || value;
89
73
  });
@@ -93,8 +77,8 @@
93
77
  this.applyClass = options.applyClass;
94
78
  }
95
79
 
96
- if (options.clearClass) {
97
- this.clearClass = options.clearClass;
80
+ if (options.cancelClass) {
81
+ this.cancelClass = options.cancelClass;
98
82
  }
99
83
  }
100
84
 
@@ -112,7 +96,7 @@
112
96
  '<input class="input-mini" type="text" name="daterangepicker_end" value="" disabled="disabled" />' +
113
97
  '</div>' +
114
98
  '<button class="' + this.applyClass + ' applyBtn" disabled="disabled">' + this.locale.applyLabel + '</button>&nbsp;' +
115
- '<button class="' + this.clearClass + ' clearBtn">' + this.locale.clearLabel + '</button>' +
99
+ '<button class="' + this.cancelClass + ' cancelBtn">' + this.locale.cancelLabel + '</button>' +
116
100
  '</div>' +
117
101
  '</div>' +
118
102
  '</div>';
@@ -128,55 +112,48 @@
128
112
  this.separator = options.separator;
129
113
 
130
114
  if (typeof options.startDate == 'string')
131
- this.startDate = Date.parseExact(options.startDate, this.format);
115
+ this.startDate = moment(options.startDate, this.format);
132
116
 
133
117
  if (typeof options.endDate == 'string')
134
- this.endDate = Date.parseExact(options.endDate, this.format);
118
+ this.endDate = moment(options.endDate, this.format);
135
119
 
136
120
  if (typeof options.minDate == 'string')
137
- this.minDate = Date.parseExact(options.minDate, this.format);
121
+ this.minDate = moment(options.minDate, this.format);
138
122
 
139
123
  if (typeof options.maxDate == 'string')
140
- this.maxDate = Date.parseExact(options.maxDate, this.format);
124
+ this.maxDate = moment(options.maxDate, this.format);
141
125
 
142
126
  if (typeof options.startDate == 'object')
143
- this.startDate = options.startDate;
127
+ this.startDate = moment(options.startDate);
144
128
 
145
129
  if (typeof options.endDate == 'object')
146
- this.endDate = options.endDate;
130
+ this.endDate = moment(options.endDate);
147
131
 
148
132
  if (typeof options.minDate == 'object')
149
- this.minDate = options.minDate;
133
+ this.minDate = moment(options.minDate);
150
134
 
151
135
  if (typeof options.maxDate == 'object')
152
- this.maxDate = options.maxDate;
136
+ this.maxDate = moment(options.maxDate);
153
137
 
154
138
  if (typeof options.ranges == 'object') {
155
139
  for (var range in options.ranges) {
156
140
 
157
- var start = options.ranges[range][0];
158
- var end = options.ranges[range][1];
159
-
160
- if (typeof start == 'string')
161
- start = Date.parse(start);
162
-
163
- if (typeof end == 'string')
164
- end = Date.parse(end);
141
+ var start = moment(options.ranges[range][0]);
142
+ var end = moment(options.ranges[range][1]);
165
143
 
166
144
  // If we have a min/max date set, bound this range
167
145
  // to it, but only if it would otherwise fall
168
146
  // outside of the min/max.
169
- if (this.minDate && start < this.minDate)
170
- start = this.minDate;
147
+ if (this.minDate && start.isBefore(this.minDate))
148
+ start = moment(this.minDate);
171
149
 
172
- if (this.maxDate && end > this.maxDate)
173
- end = this.maxDate;
150
+ if (this.maxDate && end.isAfter(this.maxDate))
151
+ end = moment(this.maxDate);
174
152
 
175
153
  // If the end of the range is before the minimum (if min is set) OR
176
154
  // the start of the range is after the max (also if set) don't display this
177
155
  // range option.
178
- if ((this.minDate && end < this.minDate) || (this.maxDate && start > this.maxDate))
179
- {
156
+ if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) {
180
157
  continue;
181
158
  }
182
159
 
@@ -191,7 +168,7 @@
191
168
  list += '</ul>';
192
169
  this.container.find('.ranges').prepend(list);
193
170
  }
194
-
171
+
195
172
  if (typeof options.dateLimit == 'object')
196
173
  this.dateLimit = options.dateLimit;
197
174
 
@@ -221,11 +198,28 @@
221
198
  if (typeof options.buttonClasses == 'object') {
222
199
  this.buttonClasses = options.buttonClasses;
223
200
  }
224
-
201
+
225
202
  if (typeof options.showDropdowns == 'boolean') {
226
203
  this.showDropdowns = options.showDropdowns;
227
204
  }
228
205
 
206
+ if (typeof options.timePicker == 'boolean') {
207
+ this.timePicker = options.timePicker;
208
+ }
209
+
210
+ if (typeof options.timePickerIncrement == 'number') {
211
+ this.timePickerIncrement = options.timePickerIncrement;
212
+ }
213
+
214
+ if (typeof options.timePicker12Hour == 'boolean') {
215
+ this.timePicker12Hour = options.timePicker12Hour;
216
+ }
217
+
218
+ }
219
+
220
+ if (!this.timePicker) {
221
+ this.startDate = this.startDate.startOf('day');
222
+ this.endDate = this.endDate.startOf('day');
229
223
  }
230
224
 
231
225
  //apply CSS classes to buttons
@@ -242,20 +236,53 @@
242
236
  right.removeClass('right').addClass('left');
243
237
  }
244
238
 
245
- if (typeof options == 'undefined' || typeof options.ranges == 'undefined')
239
+ if (typeof options == 'undefined' || typeof options.ranges == 'undefined') {
246
240
  this.container.find('.calendar').show();
241
+ this.move();
242
+ }
247
243
 
248
244
  if (typeof cb == 'function')
249
245
  this.cb = cb;
250
246
 
251
247
  this.container.addClass('opens' + this.opens);
252
248
 
249
+ //try parse date if in text input
250
+ if (!hasOptions || (typeof options.startDate == 'undefined' && typeof options.endDate == 'undefined')) {
251
+ if ($(this.element).is('input[type=text]')) {
252
+ var val = $(this.element).val();
253
+ var split = val.split(this.separator);
254
+ var start, end;
255
+ if (split.length == 2) {
256
+ start = moment(split[0], this.format);
257
+ end = moment(split[1], this.format);
258
+ }
259
+ if (start != null && end != null) {
260
+ this.startDate = start;
261
+ this.endDate = end;
262
+ }
263
+ }
264
+ }
265
+
266
+ //state
267
+ this.oldStartDate = this.startDate;
268
+ this.oldEndDate = this.endDate;
269
+
270
+ this.leftCalendar = {
271
+ month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]),
272
+ calendar: []
273
+ };
274
+
275
+ this.rightCalendar = {
276
+ month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]),
277
+ calendar: []
278
+ };
279
+
253
280
  //event listeners
254
281
  this.container.on('mousedown', $.proxy(this.mousedown, this));
255
282
  this.container.find('.calendar').on('click', '.prev', $.proxy(this.clickPrev, this));
256
283
  this.container.find('.calendar').on('click', '.next', $.proxy(this.clickNext, this));
257
284
  this.container.find('.ranges').on('click', 'button.applyBtn', $.proxy(this.clickApply, this));
258
- this.container.find('.ranges').on('click', 'button.clearBtn', $.proxy(this.clickClear, this));
285
+ this.container.find('.ranges').on('click', 'button.cancelBtn', $.proxy(this.clickCancel, this));
259
286
 
260
287
  this.container.find('.calendar').on('click', 'td.available', $.proxy(this.clickDate, this));
261
288
  this.container.find('.calendar').on('mouseenter', 'td.available', $.proxy(this.enterDate, this));
@@ -264,10 +291,14 @@
264
291
  this.container.find('.ranges').on('click', 'li', $.proxy(this.clickRange, this));
265
292
  this.container.find('.ranges').on('mouseenter', 'li', $.proxy(this.enterRange, this));
266
293
  this.container.find('.ranges').on('mouseleave', 'li', $.proxy(this.updateView, this));
267
-
294
+
268
295
  this.container.find('.calendar').on('change', 'select.yearselect', $.proxy(this.updateYear, this));
269
296
  this.container.find('.calendar').on('change', 'select.monthselect', $.proxy(this.updateMonth, this));
270
297
 
298
+ this.container.find('.calendar').on('change', 'select.hourselect', $.proxy(this.updateTime, this));
299
+ this.container.find('.calendar').on('change', 'select.minuteselect', $.proxy(this.updateTime, this));
300
+ this.container.find('.calendar').on('change', 'select.ampmselect', $.proxy(this.updateTime, this));
301
+
271
302
  this.element.on('keyup', $.proxy(this.updateFromControl, this));
272
303
 
273
304
  this.updateView();
@@ -279,22 +310,18 @@
279
310
 
280
311
  constructor: DateRangePicker,
281
312
 
282
- mousedown: function (e) {
313
+ mousedown: function (e) {
283
314
  e.stopPropagation();
284
-
285
- //allow select list to function normally
286
- if(!this.showDropdowns || $(e.target).not('select').length)
287
- e.preventDefault();
288
315
  },
289
316
 
290
317
  updateView: function () {
291
- this.leftCalendar.month.set({ month: this.startDate.getMonth(), year: this.startDate.getFullYear() });
292
- this.rightCalendar.month.set({ month: this.endDate.getMonth(), year: this.endDate.getFullYear() });
318
+ this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
319
+ this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
293
320
 
294
- this.container.find('input[name=daterangepicker_start]').val(this.startDate.toString(this.format));
295
- this.container.find('input[name=daterangepicker_end]').val(this.endDate.toString(this.format));
321
+ this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format));
322
+ this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format));
296
323
 
297
- if (this.startDate.equals(this.endDate) || this.startDate.isBefore(this.endDate)) {
324
+ if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) {
298
325
  this.container.find('button.applyBtn').removeAttr('disabled');
299
326
  } else {
300
327
  this.container.find('button.applyBtn').attr('disabled', 'disabled');
@@ -303,10 +330,11 @@
303
330
 
304
331
  updateFromControl: function () {
305
332
  if (!this.element.is('input')) return;
333
+ if (!this.element.val().length) return;
306
334
 
307
335
  var dateString = this.element.val().split(this.separator);
308
- var start = Date.parseExact(dateString[0], this.format);
309
- var end = Date.parseExact(dateString[1], this.format);
336
+ var start = moment(dateString[0], this.format);
337
+ var end = moment(dateString[1], this.format);
310
338
 
311
339
  if (start == null || end == null) return;
312
340
  if (end.isBefore(start)) return;
@@ -320,32 +348,42 @@
320
348
  },
321
349
 
322
350
  notify: function () {
323
- if (!this.cleared) {
324
- this.updateView();
325
- }
326
-
327
- if (this.element.is('input')) {
328
- this.element.val(this.cleared ? '' : this.startDate.toString(this.format) + this.separator + this.endDate.toString(this.format));
329
- }
330
- var arg1 = (this.cleared ? null : this.startDate),
331
- arg2 = (this.cleared ? null : this.endDate);
332
- this.cleared = false;
333
- this.cb(arg1,arg2);
351
+ this.updateView();
352
+ this.cb(this.startDate, this.endDate);
334
353
  },
335
354
 
336
355
  move: function () {
356
+ var minWidth = $(this.container).find('.ranges').outerWidth();
357
+ if ($(this.container).find('.calendar').is(':visible')) {
358
+ var padding = 24; // FIXME: this works for the default styling, but isn't flexible
359
+ minWidth += $(this.container).find('.calendar').outerWidth() * 2 + padding;
360
+ }
337
361
  if (this.opens == 'left') {
338
362
  this.container.css({
339
363
  top: this.element.offset().top + this.element.outerHeight(),
340
364
  right: $(window).width() - this.element.offset().left - this.element.outerWidth(),
341
- left: 'auto'
365
+ left: 'auto',
366
+ 'min-width': minWidth
342
367
  });
368
+ if (this.container.offset().left < 0) {
369
+ this.container.css({
370
+ right: 'auto',
371
+ left: 9
372
+ });
373
+ }
343
374
  } else {
344
375
  this.container.css({
345
376
  top: this.element.offset().top + this.element.outerHeight(),
346
377
  left: this.element.offset().left,
347
- right: 'auto'
378
+ right: 'auto',
379
+ 'min-width': minWidth
348
380
  });
381
+ if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
382
+ this.container.css({
383
+ left: 'auto',
384
+ right: 0
385
+ });
386
+ }
349
387
  }
350
388
  },
351
389
 
@@ -358,21 +396,21 @@
358
396
  e.preventDefault();
359
397
  }
360
398
 
361
- this.changed = false;
362
-
363
- this.element.trigger('shown',{target:e.target,picker:this});
399
+ this.oldStartDate = this.startDate;
400
+ this.oldEndDate = this.endDate;
364
401
 
365
402
  $(document).on('mousedown', $.proxy(this.hide, this));
403
+ this.element.trigger('shown', {target: e.target, picker: this});
366
404
  },
367
405
 
368
406
  hide: function (e) {
369
407
  this.container.hide();
370
- $(document).off('mousedown', this.hide);
371
408
 
372
- if (this.changed) {
373
- this.changed = false;
409
+ if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
374
410
  this.notify();
375
- }
411
+
412
+ $(document).off('mousedown', this.hide);
413
+ this.element.trigger('hidden', { picker: this });
376
414
  },
377
415
 
378
416
  enterRange: function (e) {
@@ -381,8 +419,8 @@
381
419
  this.updateView();
382
420
  } else {
383
421
  var dates = this.ranges[label];
384
- this.container.find('input[name=daterangepicker_start]').val(dates[0].toString(this.format));
385
- this.container.find('input[name=daterangepicker_end]').val(dates[1].toString(this.format));
422
+ this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format));
423
+ this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format));
386
424
  }
387
425
  },
388
426
 
@@ -390,17 +428,24 @@
390
428
  var label = e.target.innerHTML;
391
429
  if (label == this.locale.customRangeLabel) {
392
430
  this.container.find('.calendar').show();
431
+ this.move();
393
432
  } else {
394
433
  var dates = this.ranges[label];
395
434
 
396
435
  this.startDate = dates[0];
397
436
  this.endDate = dates[1];
398
437
 
399
- this.leftCalendar.month.set({ month: this.startDate.getMonth(), year: this.startDate.getFullYear() });
400
- this.rightCalendar.month.set({ month: this.endDate.getMonth(), year: this.endDate.getFullYear() });
438
+ if (!this.timePicker) {
439
+ this.startDate.startOf('day');
440
+ this.endDate.startOf('day');
441
+ }
442
+
443
+ this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute());
444
+ this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute());
401
445
  this.updateCalendars();
402
446
 
403
- this.changed = true;
447
+ if (this.element.is('input'))
448
+ this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));
404
449
 
405
450
  this.container.find('.calendar').hide();
406
451
  this.hide();
@@ -410,9 +455,9 @@
410
455
  clickPrev: function (e) {
411
456
  var cal = $(e.target).parents('.calendar');
412
457
  if (cal.hasClass('left')) {
413
- this.leftCalendar.month.add({ months: -1 });
458
+ this.leftCalendar.month.subtract('month', 1);
414
459
  } else {
415
- this.rightCalendar.month.add({ months: -1 });
460
+ this.rightCalendar.month.subtract('month', 1);
416
461
  }
417
462
  this.updateCalendars();
418
463
  },
@@ -420,126 +465,147 @@
420
465
  clickNext: function (e) {
421
466
  var cal = $(e.target).parents('.calendar');
422
467
  if (cal.hasClass('left')) {
423
- this.leftCalendar.month.add({ months: 1 });
468
+ this.leftCalendar.month.add('month', 1);
424
469
  } else {
425
- this.rightCalendar.month.add({ months: 1 });
470
+ this.rightCalendar.month.add('month', 1);
426
471
  }
427
472
  this.updateCalendars();
428
473
  },
429
474
 
430
475
  enterDate: function (e) {
431
476
 
432
- var title = $(e.target).attr('title');
477
+ var title = $(e.target).attr('data-title');
433
478
  var row = title.substr(1, 1);
434
479
  var col = title.substr(3, 1);
435
480
  var cal = $(e.target).parents('.calendar');
436
481
 
437
482
  if (cal.hasClass('left')) {
438
- this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].toString(this.format));
483
+ this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format));
439
484
  } else {
440
- this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].toString(this.format));
485
+ this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format));
441
486
  }
442
487
 
443
488
  },
444
489
 
445
490
  clickDate: function (e) {
446
- var title = $(e.target).attr('title');
491
+ var title = $(e.target).attr('data-title');
447
492
  var row = title.substr(1, 1);
448
493
  var col = title.substr(3, 1);
449
494
  var cal = $(e.target).parents('.calendar');
450
495
 
451
496
  if (cal.hasClass('left')) {
452
- startDate = this.leftCalendar.calendar[row][col];
453
- endDate = this.endDate;
497
+ var startDate = this.leftCalendar.calendar[row][col];
498
+ var endDate = this.endDate;
454
499
  if (typeof this.dateLimit == 'object') {
455
- var maxDate = new Date(startDate).add(this.dateLimit);
500
+ var maxDate = moment(startDate).add(this.dateLimit).startOf('day');
456
501
  if (endDate.isAfter(maxDate)) {
457
502
  endDate = maxDate;
458
503
  }
459
504
  }
460
- this.element.trigger('clicked', {
461
- dir: 'left',
462
- picker: this
463
- });
464
505
  } else {
465
- startDate = this.startDate;
466
- endDate = this.rightCalendar.calendar[row][col];
506
+ var startDate = this.startDate;
507
+ var endDate = this.rightCalendar.calendar[row][col];
467
508
  if (typeof this.dateLimit == 'object') {
468
- var negConfig = {
469
- days: 0 - this.dateLimit.days,
470
- months: 0 - this.dateLimit.months,
471
- years: 0 - this.dateLimit.years
472
- };
473
- var minDate = new Date(endDate).add(negConfig);
509
+ var minDate = moment(endDate).subtract(this.dateLimit).startOf('day');
474
510
  if (startDate.isBefore(minDate)) {
475
511
  startDate = minDate;
476
512
  }
477
- }
478
- this.element.trigger('clicked', {
479
- dir: 'right',
480
- picker: this
481
- });
513
+ }
482
514
  }
483
515
 
484
516
  cal.find('td').removeClass('active');
485
517
 
486
- if (startDate.equals(endDate) || startDate.isBefore(endDate)) {
518
+ if (startDate.isSame(endDate) || startDate.isBefore(endDate)) {
487
519
  $(e.target).addClass('active');
488
- if (!startDate.equals(this.startDate) || !endDate.equals(this.endDate))
489
- this.changed = true;
490
520
  this.startDate = startDate;
491
521
  this.endDate = endDate;
492
522
  } else if (startDate.isAfter(endDate)) {
493
523
  $(e.target).addClass('active');
494
- this.changed = true;
495
524
  this.startDate = startDate;
496
- this.endDate = startDate.clone().add(1).days();
525
+ this.endDate = moment(startDate).add('day', 1).startOf('day');
497
526
  }
498
527
 
499
- this.leftCalendar.month.set({ month: this.startDate.getMonth(), year: this.startDate.getFullYear() });
500
- this.rightCalendar.month.set({ month: this.endDate.getMonth(), year: this.endDate.getFullYear() });
528
+ this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
529
+ this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
501
530
  this.updateCalendars();
502
531
  },
503
532
 
504
533
  clickApply: function (e) {
534
+ if (this.element.is('input'))
535
+ this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));
505
536
  this.hide();
506
537
  },
507
538
 
508
- clickClear: function (e) {
509
- this.changed = true;
510
- this.cleared = true;
539
+ clickCancel: function (e) {
540
+ this.startDate = this.oldStartDate;
541
+ this.endDate = this.oldEndDate;
542
+ this.updateView();
543
+ this.updateCalendars();
511
544
  this.hide();
512
545
  },
513
-
514
- updateYear: function(e) {
515
- var year = parseInt($(e.target).val());
516
- var isLeft = $(e.target).closest('.calendar').hasClass('left');
517
-
518
- if(isLeft) {
519
- this.leftCalendar.month.set({ month: this.startDate.getMonth(), year: year });
520
- } else {
521
- this.rightCalendar.month.set({ month: this.endDate.getMonth(), year: year });
522
- }
523
-
546
+
547
+ updateYear: function (e) {
548
+ var year = parseInt($(e.target).val());
549
+ var isLeft = $(e.target).closest('.calendar').hasClass('left');
550
+
551
+ if (isLeft) {
552
+ this.leftCalendar.month.month(this.startDate.month()).year(year);
553
+ } else {
554
+ this.rightCalendar.month.month(this.endDate.month()).year(year);
555
+ }
556
+
524
557
  this.updateCalendars();
525
- },
526
-
527
- updateMonth: function(e) {
528
- var month = parseInt($(e.target).val());
529
- var isLeft = $(e.target).closest('.calendar').hasClass('left');
530
-
531
- if(isLeft) {
532
- this.leftCalendar.month.set({ month: month, year: this.startDate.getFullYear() });
533
- } else {
534
- this.rightCalendar.month.set({ month: month, year: this.endDate.getFullYear() });
535
- }
536
-
558
+ },
559
+
560
+ updateMonth: function (e) {
561
+ var month = parseInt($(e.target).val());
562
+ var isLeft = $(e.target).closest('.calendar').hasClass('left');
563
+
564
+ if (isLeft) {
565
+ this.leftCalendar.month.month(month).year(this.startDate.year());
566
+ } else {
567
+ this.rightCalendar.month.month(month).year(this.endDate.year());
568
+ }
569
+ this.updateCalendars();
570
+ },
571
+
572
+ updateTime: function(e) {
573
+
574
+ var isLeft = $(e.target).closest('.calendar').hasClass('left');
575
+ var cal = this.container.find('.calendar.left');
576
+ if (!isLeft)
577
+ cal = this.container.find('.calendar.right');
578
+
579
+ var hour = parseInt(cal.find('.hourselect').val());
580
+ var minute = parseInt(cal.find('.minuteselect').val());
581
+
582
+ if (this.timePicker12Hour) {
583
+ var ampm = cal.find('.ampmselect').val();
584
+ if (ampm == 'PM' && hour < 12)
585
+ hour += 12;
586
+ }
587
+
588
+ if (isLeft) {
589
+ var start = this.startDate;
590
+ start.hour(hour);
591
+ start.minute(minute);
592
+ this.startDate = start;
593
+ this.leftCalendar.month.hour(hour).minute(minute);
594
+ } else {
595
+ var end = this.endDate;
596
+ end.hour(hour);
597
+ end.minute(minute);
598
+ this.endDate = end;
599
+ this.rightCalendar.month.hour(hour).minute(minute);
600
+ }
601
+
537
602
  this.updateCalendars();
538
- },
603
+
604
+ },
539
605
 
540
606
  updateCalendars: function () {
541
- this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.getMonth(), this.leftCalendar.month.getFullYear());
542
- this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.getMonth(), this.rightCalendar.month.getFullYear());
607
+ this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), 'left');
608
+ this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), 'right');
543
609
  this.container.find('.calendar.left').html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate));
544
610
  this.container.find('.calendar.right').html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate));
545
611
 
@@ -547,33 +613,38 @@
547
613
  var customRange = true;
548
614
  var i = 0;
549
615
  for (var range in this.ranges) {
550
- if (this.startDate.equals(this.ranges[range][0]) && this.endDate.equals(this.ranges[range][1])) {
551
- customRange = false;
552
- this.container.find('.ranges li:eq(' + i + ')').addClass('active');
616
+ if (this.timePicker) {
617
+ if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {
618
+ customRange = false;
619
+ this.container.find('.ranges li:eq(' + i + ')').addClass('active');
620
+ }
621
+ } else {
622
+ //ignore times when comparing dates if time picker is not enabled
623
+ 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')) {
624
+ customRange = false;
625
+ this.container.find('.ranges li:eq(' + i + ')').addClass('active');
626
+ }
553
627
  }
554
628
  i++;
555
629
  }
556
630
  if (customRange)
557
631
  this.container.find('.ranges li:last').addClass('active');
558
-
559
- this.element.trigger('updated', this);
560
632
  },
561
633
 
562
- buildCalendar: function (month, year) {
634
+ buildCalendar: function (month, year, hour, minute, side) {
563
635
 
564
- var firstDay = Date.today().set({ day: 1, month: month, year: year });
565
- var lastMonth = firstDay.clone().add(-1).day().getMonth();
566
- var lastYear = firstDay.clone().add(-1).day().getFullYear();
636
+ var firstDay = moment([year, month, 1]);
637
+ var lastMonth = moment(firstDay).subtract('month', 1).month();
638
+ var lastYear = moment(firstDay).subtract('month', 1).year();
567
639
 
568
- var daysInMonth = Date.getDaysInMonth(year, month);
569
- var daysInLastMonth = Date.getDaysInMonth(lastYear, lastMonth);
640
+ var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
570
641
 
571
- var dayOfWeek = firstDay.getDay();
642
+ var dayOfWeek = firstDay.day();
572
643
 
573
644
  //initialize a 6 rows x 7 columns array for the calendar
574
- var calendar = Array();
645
+ var calendar = [];
575
646
  for (var i = 0; i < 6; i++) {
576
- calendar[i] = Array();
647
+ calendar[i] = [];
577
648
  }
578
649
 
579
650
  //populate the calendar with date objects
@@ -584,8 +655,8 @@
584
655
  if (dayOfWeek == this.locale.firstDay)
585
656
  startDay = daysInLastMonth - 6;
586
657
 
587
- var curDate = Date.today().set({ day: startDay, month: lastMonth, year: lastYear });
588
- for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = curDate.clone().add(1).day()) {
658
+ var curDate = moment([lastYear, lastMonth, startDay, hour, minute]);
659
+ for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('day', 1)) {
589
660
  if (i > 0 && col % 7 == 0) {
590
661
  col = 0;
591
662
  row++;
@@ -596,75 +667,71 @@
596
667
  return calendar;
597
668
 
598
669
  },
599
-
600
- renderDropdowns: function (selected, minDate, maxDate) {
601
- var currentMonth = selected.getMonth();
602
- var monthHtml = '<select class="monthselect">';
603
- var inMinYear = false;
604
- var inMaxYear = false;
605
-
606
- for (var m = 0; m < 12; m++) {
607
- if ((!inMinYear || m >= minDate.getMonth()) && (!inMaxYear || m <= maxDate.getMonth())) {
608
- monthHtml += "<option value='" + m + "'" +
609
- (m === currentMonth ? " selected='selected'" : "") +
610
- ">" + this.locale.monthNames[m] + "</option>";
611
- }
612
- }
613
- monthHtml += "</select>";
614
-
615
- var currentYear = selected.getFullYear();
616
- var maxYear = (maxDate && maxDate.getFullYear()) || (currentYear + 5);
617
- var minYear = (minDate && minDate.getFullYear()) || (currentYear - 50);
618
- var yearHtml = '<select class="yearselect">'
619
-
620
- for(var y = minYear; y <= maxYear; y++) {
621
- yearHtml += '<option value="' + y + '"' +
622
- (y === currentYear ? ' selected="selected"' : '') +
623
- '>' + y + '</option>';
624
- }
625
-
626
- yearHtml += '</select>';
627
-
628
- return monthHtml + yearHtml;
629
- },
670
+
671
+ renderDropdowns: function (selected, minDate, maxDate) {
672
+ var currentMonth = selected.month();
673
+ var monthHtml = '<select class="monthselect">';
674
+ var inMinYear = false;
675
+ var inMaxYear = false;
676
+
677
+ for (var m = 0; m < 12; m++) {
678
+ if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
679
+ monthHtml += "<option value='" + m + "'" +
680
+ (m === currentMonth ? " selected='selected'" : "") +
681
+ ">" + this.locale.monthNames[m] + "</option>";
682
+ }
683
+ }
684
+ monthHtml += "</select>";
685
+
686
+ var currentYear = selected.year();
687
+ var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);
688
+ var minYear = (minDate && minDate.year()) || (currentYear - 50);
689
+ var yearHtml = '<select class="yearselect">'
690
+
691
+ for (var y = minYear; y <= maxYear; y++) {
692
+ yearHtml += '<option value="' + y + '"' +
693
+ (y === currentYear ? ' selected="selected"' : '') +
694
+ '>' + y + '</option>';
695
+ }
696
+
697
+ yearHtml += '</select>';
698
+
699
+ return monthHtml + yearHtml;
700
+ },
630
701
 
631
702
  renderCalendar: function (calendar, selected, minDate, maxDate) {
632
- var html = '<table class="table-condensed">';
703
+
704
+ var html = '<div class="calendar-date">';
705
+ html += '<table class="table-condensed">';
633
706
  html += '<thead>';
634
707
  html += '<tr>';
635
-
708
+
636
709
  // add empty cell for week number
637
710
  if (this.showWeekNumbers)
638
711
  html += '<th></th>';
639
-
640
- if (!minDate || minDate < calendar[1][1])
641
- {
712
+
713
+ if (!minDate || minDate.isBefore(calendar[1][1])) {
642
714
  html += '<th class="prev available"><i class="icon-arrow-left"></i></th>';
715
+ } else {
716
+ html += '<th></th>';
717
+ }
718
+
719
+ var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");
720
+
721
+ if (this.showDropdowns) {
722
+ dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate);
643
723
  }
644
- else
645
- {
646
- html += '<th></th>';
647
- }
648
-
649
- var dateHtml = this.locale.monthNames[calendar[1][1].getMonth()] + calendar[1][1].toString(" yyyy");
650
-
651
- if(this.showDropdowns) {
652
- dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate);
653
- }
654
-
724
+
655
725
  html += '<th colspan="5" style="width: auto">' + dateHtml + '</th>';
656
- if (!maxDate || maxDate > calendar[1][1])
657
- {
726
+ if (!maxDate || maxDate.isAfter(calendar[1][1])) {
658
727
  html += '<th class="next available"><i class="icon-arrow-right"></i></th>';
659
- }
660
- else
661
- {
662
- html += '<th></th>';
728
+ } else {
729
+ html += '<th></th>';
663
730
  }
664
731
 
665
732
  html += '</tr>';
666
733
  html += '<tr>';
667
-
734
+
668
735
  // add week number label
669
736
  if (this.showWeekNumbers)
670
737
  html += '<th class="week">' + this.locale.weekLabel + '</th>';
@@ -679,43 +746,95 @@
679
746
 
680
747
  for (var row = 0; row < 6; row++) {
681
748
  html += '<tr>';
682
-
749
+
683
750
  // add week number
684
751
  if (this.showWeekNumbers)
685
- html += '<td class="week">' + calendar[row][0].getWeek() + '</td>';
686
-
752
+ html += '<td class="week">' + calendar[row][0].week() + '</td>';
753
+
687
754
  for (var col = 0; col < 7; col++) {
688
755
  var cname = 'available ';
689
- cname += (calendar[row][col].getMonth() == calendar[1][1].getMonth()) ? '' : 'off';
756
+ cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off';
690
757
 
691
- // Normalise the time so the comparison won't fail
692
- selected.setHours(0,0,0,0);
693
-
694
- if ( (minDate && calendar[row][col] < minDate) || (maxDate && calendar[row][col] > maxDate))
695
- {
758
+ if ((minDate && calendar[row][col].isBefore(minDate)) || (maxDate && calendar[row][col].isAfter(maxDate))) {
696
759
  cname = ' off disabled ';
697
- }
698
- else if (calendar[row][col].equals(selected))
699
- {
760
+ } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) {
700
761
  cname += ' active ';
701
- if (calendar[row][col].equals(this.startDate)) { cname += ' start-date '; }
702
- if (calendar[row][col].equals(this.endDate)) { cname += ' end-date '; }
703
- }
704
- else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate)
705
- {
762
+ if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) {
763
+ cname += ' start-date ';
764
+ }
765
+ if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) {
766
+ cname += ' end-date ';
767
+ }
768
+ } else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) {
706
769
  cname += ' in-range ';
707
- if (calendar[row][col].equals(this.startDate)) { cname += ' start-date '; }
708
- if (calendar[row][col].equals(this.endDate)) { cname += ' end-date '; }
770
+ if (calendar[row][col].isSame(this.startDate)) { cname += ' start-date '; }
771
+ if (calendar[row][col].isSame(this.endDate)) { cname += ' end-date '; }
709
772
  }
710
-
773
+
711
774
  var title = 'r' + row + 'c' + col;
712
- html += '<td class="' + cname.replace(/\s+/g,' ').replace(/^\s?(.*?)\s?$/,'$1') + '" title="' + title + '">' + calendar[row][col].getDate() + '</td>';
775
+ html += '<td class="' + cname.replace(/\s+/g, ' ').replace(/^\s?(.*?)\s?$/, '$1') + '" data-title="' + title + '">' + calendar[row][col].date() + '</td>';
713
776
  }
714
777
  html += '</tr>';
715
778
  }
716
779
 
717
780
  html += '</tbody>';
718
781
  html += '</table>';
782
+ html += '</div>';
783
+
784
+ if (this.timePicker) {
785
+
786
+ html += '<div class="calendar-time">';
787
+ html += '<select class="hourselect">';
788
+ var start = 0;
789
+ var end = 23;
790
+ var selected_hour = selected.hour();
791
+ if (this.timePicker12Hour) {
792
+ start = 1;
793
+ end = 12;
794
+ if (selected_hour >= 12)
795
+ selected_hour -= 12;
796
+ if (selected_hour == 0)
797
+ selected_hour = 12;
798
+ }
799
+
800
+ for (var i = start; i <= end; i++) {
801
+ if (i == selected_hour) {
802
+ html += '<option value="' + i + '" selected="selected">' + i + '</option>';
803
+ } else {
804
+ html += '<option value="' + i + '">' + i + '</option>';
805
+ }
806
+ }
807
+
808
+ html += '</select> : ';
809
+
810
+ html += '<select class="minuteselect">';
811
+
812
+ for (var i = 0; i < 60; i += this.timePickerIncrement) {
813
+ var num = i;
814
+ if (num < 10)
815
+ num = '0' + num;
816
+ if (i == selected.minute()) {
817
+ html += '<option value="' + i + '" selected="selected">' + num + '</option>';
818
+ } else {
819
+ html += '<option value="' + i + '">' + num + '</option>';
820
+ }
821
+ }
822
+
823
+ html += '</select> ';
824
+
825
+ if (this.timePicker12Hour) {
826
+ html += '<select class="ampmselect">';
827
+ if (selected.hour() >= 12) {
828
+ html += '<option value="AM">AM</option><option value="PM" selected="selected">PM</option>';
829
+ } else {
830
+ html += '<option value="AM" selected="selected">AM</option><option value="PM">PM</option>';
831
+ }
832
+ html += '</select>';
833
+ }
834
+
835
+ html += '</div>';
836
+
837
+ }
719
838
 
720
839
  return html;
721
840
 
@@ -724,12 +843,12 @@
724
843
  };
725
844
 
726
845
  $.fn.daterangepicker = function (options, cb) {
727
- this.each(function() {
728
- var el = $(this);
729
- if (!el.data('daterangepicker'))
730
- el.data('daterangepicker', new DateRangePicker(el, options, cb));
731
- });
732
- return this;
846
+ this.each(function () {
847
+ var el = $(this);
848
+ if (!el.data('daterangepicker'))
849
+ el.data('daterangepicker', new DateRangePicker(el, options, cb));
850
+ });
851
+ return this;
733
852
  };
734
853
 
735
- } (window.jQuery);
854
+ }(window.jQuery);