bootstrap-daterangepicker-rails 0.0.8 → 0.0.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 74d416af849d9db6a14e6c7f8482f1004e50b412
4
- data.tar.gz: 797929b9a3d13cf612c4e46eace69c57618cb678
3
+ metadata.gz: f1d75cabce4f55c23f925accb2b9d42a1b52f79b
4
+ data.tar.gz: 21aae648963dd016bcdfb1676b5123fe5d19d81f
5
5
  SHA512:
6
- metadata.gz: e439b6cfe45fee1e62511918638de8e8ca626615dae18f4637199937dd6905cb2c58bee20767434fe31f71f118f1dcd96d177952cdbc0d2b41b8e7743f311293
7
- data.tar.gz: e0492dcca44816bfab49044b360a4b7f8a91ef42f3b78ed1a91d4d797facc2f74097139ab308af86e48939d0423e80b02d672bbe220b62b20716449c03cb7fa7
6
+ metadata.gz: c62e627da471ab781c336f2209b5b0f8c3ecdad7241395758782df032c80230e312125ef08690616a31a353ebb2b2b0c141a486c103b2a4a39d6158b8d24a904
7
+ data.tar.gz: b02190fa29cec461a390f52bd55b68cdd6ba1a4ad6d7d146657d4e8f4fa933caa768e894cc10917dc19efeee3ccefbae27a60a93c8e08894c804c68cdb7b834b
data/README.md CHANGED
@@ -1,10 +1,5 @@
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
-
8
3
  _Description from DateRangePicker for Twitter Bootstrap_
9
4
 
10
5
  This date range picker component for Twitter Bootstrap creates a dropdown menu from which a user can
@@ -17,20 +12,21 @@ into the text box. Otherwise, you can provide a custom callback function to rece
17
12
 
18
13
  [Live demo & option usage examples](http://www.dangrossman.info/2012/08/20/a-date-range-picker-for-twitter-bootstrap/)
19
14
 
20
- ## Usage
15
+ ## Installation and Usage
21
16
 
22
17
  This component relies on [Twitter Bootstrap](http://twitter.github.com/bootstrap/),
23
18
  [momentjs](http://www.momentjs.com/) and [jQuery](http://jquery.com/).
24
19
 
25
- Basic usage:
20
+ Basic usage (with Bootstrap 3)
21
+
22
+ (Suffix `daterangepicker` with `-bs2` or `-bs3` for your version of Bootstrap.)
26
23
 
27
24
  ```
28
25
 
29
26
  # Gemfile
30
27
  gem 'jquery-rails'
28
+ gem 'momentjs-rails'
31
29
  gem 'bootstrap-daterangepicker-rails'
32
- gem 'coffee-rails'
33
-
34
30
 
35
31
  # application.js
36
32
 
@@ -42,7 +38,7 @@ gem 'coffee-rails'
42
38
 
43
39
  /*
44
40
  *= require bootstrap
45
- *= require daterangepicker
41
+ *= require daterangepicker-bs3
46
42
  */
47
43
 
48
44
 
@@ -64,6 +60,11 @@ Additional options allow:
64
60
 
65
61
  Syntax for all the options can be found in the examples.html file.
66
62
 
63
+
64
+ ## Thanks
65
+
66
+ Thanks to https://github.com/allomov for doing all the work on the 4.x branch.
67
+
67
68
  ## License
68
69
 
69
70
  This code is made available under the [Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0),
@@ -1,7 +1,7 @@
1
1
  module Bootstrap
2
2
  module Daterangepicker
3
3
  module Rails
4
- VERSION = '0.0.8'
4
+ VERSION = '0.0.9'
5
5
  end
6
6
  end
7
7
  end
@@ -1,53 +1,14 @@
1
1
  /**
2
- * @version: 1.2
2
+ * @version: 1.3.8
3
3
  * @author: Dan Grossman http://www.dangrossman.info/
4
- * @date: 2013-07-25
5
- * @copyright: Copyright (c) 2012-2013 Dan Grossman. All rights reserved.
4
+ * @date: 2014-07-10
5
+ * @copyright: Copyright (c) 2012-2014 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
  */
9
- !function ($) {
9
+ !function ($, moment) {
10
10
 
11
11
  var DateRangePicker = function (element, options, cb) {
12
- var hasOptions = typeof options == 'object';
13
- var localeObject;
14
-
15
- //option defaults
16
-
17
- this.startDate = moment().startOf('day');
18
- this.endDate = moment().startOf('day');
19
- this.minDate = false;
20
- this.maxDate = false;
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 = {};
29
- this.opens = 'right';
30
-
31
- this.buttonClasses = ['btn', 'btn-small'];
32
- this.applyClass = 'btn-success';
33
- this.cancelClass = 'btn-default';
34
-
35
- this.format = 'MM/DD/YYYY';
36
- this.separator = ' - ';
37
-
38
- this.locale = {
39
- applyLabel: 'Apply',
40
- cancelLabel: 'Cancel',
41
- fromLabel: 'From',
42
- toLabel: 'To',
43
- weekLabel: 'W',
44
- customRangeLabel: 'Custom Range',
45
- daysOfWeek: moment()._lang._weekdaysMin.slice(),
46
- monthNames: moment()._lang._monthsShort.slice(),
47
- firstDay: 0
48
- };
49
-
50
- this.cb = function () { };
51
12
 
52
13
  // by default, the daterangepicker element is placed at the bottom of HTML body
53
14
  this.parentEl = 'body';
@@ -55,131 +16,182 @@
55
16
  //element that triggered the date range picker
56
17
  this.element = $(element);
57
18
 
58
- if (this.element.hasClass('pull-right'))
59
- this.opens = 'left';
60
-
61
- if (this.element.is('input')) {
62
- this.element.on({
63
- click: $.proxy(this.show, this),
64
- focus: $.proxy(this.show, this)
65
- });
66
- } else {
67
- this.element.on('click', $.proxy(this.show, this));
68
- }
69
-
70
- localeObject = this.locale;
71
-
72
- if (hasOptions) {
73
- if (typeof options.locale == 'object') {
74
- $.each(localeObject, function (property, value) {
75
- localeObject[property] = options.locale[property] || value;
76
- });
77
- }
78
-
79
- if (options.applyClass) {
80
- this.applyClass = options.applyClass;
81
- }
82
-
83
- if (options.cancelClass) {
84
- this.cancelClass = options.cancelClass;
85
- }
86
- }
19
+ //tracks visible state
20
+ this.isShowing = false;
87
21
 
22
+ //create the picker HTML object
88
23
  var DRPTemplate = '<div class="daterangepicker dropdown-menu">' +
89
24
  '<div class="calendar left"></div>' +
90
25
  '<div class="calendar right"></div>' +
91
26
  '<div class="ranges">' +
92
27
  '<div class="range_inputs">' +
93
- '<div class="daterangepicker_start_input" style="float: left">' +
94
- '<label for="daterangepicker_start">' + this.locale.fromLabel + '</label>' +
95
- '<input class="input-mini" type="text" name="daterangepicker_start" value="" disabled="disabled" />' +
28
+ '<div class="daterangepicker_start_input">' +
29
+ '<label for="daterangepicker_start"></label>' +
30
+ '<input class="input-mini" type="text" name="daterangepicker_start" value="" readonly="readonly" />' +
96
31
  '</div>' +
97
- '<div class="daterangepicker_end_input" style="float: left; padding-left: 11px">' +
98
- '<label for="daterangepicker_end">' + this.locale.toLabel + '</label>' +
99
- '<input class="input-mini" type="text" name="daterangepicker_end" value="" disabled="disabled" />' +
32
+ '<div class="daterangepicker_end_input">' +
33
+ '<label for="daterangepicker_end"></label>' +
34
+ '<input class="input-mini" type="text" name="daterangepicker_end" value="" readonly="readonly" />' +
100
35
  '</div>' +
101
- '<button class="' + this.applyClass + ' applyBtn" disabled="disabled">' + this.locale.applyLabel + '</button>&nbsp;' +
102
- '<button class="' + this.cancelClass + ' cancelBtn">' + this.locale.cancelLabel + '</button>' +
36
+ '<button class="applyBtn" disabled="disabled"></button>&nbsp;' +
37
+ '<button class="cancelBtn"></button>' +
103
38
  '</div>' +
104
39
  '</div>' +
105
40
  '</div>';
106
41
 
107
- this.parentEl = (hasOptions && options.parentEl && $(options.parentEl)) || $(this.parentEl);
108
- //the date range picker
42
+ //custom options
43
+ if (typeof options !== 'object' || options === null)
44
+ options = {};
45
+
46
+ this.parentEl = (typeof options === 'object' && options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
109
47
  this.container = $(DRPTemplate).appendTo(this.parentEl);
110
48
 
111
- if (hasOptions) {
49
+ this.setOptions(options, cb);
50
+
51
+ //apply CSS classes and labels to buttons
52
+ var c = this.container;
53
+ $.each(this.buttonClasses, function (idx, val) {
54
+ c.find('button').addClass(val);
55
+ });
56
+ this.container.find('.daterangepicker_start_input label').html(this.locale.fromLabel);
57
+ this.container.find('.daterangepicker_end_input label').html(this.locale.toLabel);
58
+ if (this.applyClass.length)
59
+ this.container.find('.applyBtn').addClass(this.applyClass);
60
+ if (this.cancelClass.length)
61
+ this.container.find('.cancelBtn').addClass(this.cancelClass);
62
+ this.container.find('.applyBtn').html(this.locale.applyLabel);
63
+ this.container.find('.cancelBtn').html(this.locale.cancelLabel);
64
+
65
+ //event listeners
66
+
67
+ this.container.find('.calendar')
68
+ .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
69
+ .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
70
+ .on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
71
+ .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.enterDate, this))
72
+ .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))
73
+ .on('change.daterangepicker', 'select.yearselect', $.proxy(this.updateMonthYear, this))
74
+ .on('change.daterangepicker', 'select.monthselect', $.proxy(this.updateMonthYear, this))
75
+ .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.ampmselect', $.proxy(this.updateTime, this));
76
+
77
+ this.container.find('.ranges')
78
+ .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
79
+ .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
80
+ .on('click.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this))
81
+ .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
82
+ .on('mouseenter.daterangepicker', 'li', $.proxy(this.enterRange, this))
83
+ .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));
112
84
 
113
- if (typeof options.format == 'string')
85
+ if (this.element.is('input')) {
86
+ this.element.on({
87
+ 'click.daterangepicker': $.proxy(this.show, this),
88
+ 'focus.daterangepicker': $.proxy(this.show, this),
89
+ 'keyup.daterangepicker': $.proxy(this.updateFromControl, this)
90
+ });
91
+ } else {
92
+ this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
93
+ }
94
+
95
+ };
96
+
97
+ DateRangePicker.prototype = {
98
+
99
+ constructor: DateRangePicker,
100
+
101
+ setOptions: function(options, callback) {
102
+
103
+ this.startDate = moment().startOf('day');
104
+ this.endDate = moment().endOf('day');
105
+ this.minDate = false;
106
+ this.maxDate = false;
107
+ this.dateLimit = false;
108
+
109
+ this.showDropdowns = false;
110
+ this.showWeekNumbers = false;
111
+ this.timePicker = false;
112
+ this.timePickerIncrement = 30;
113
+ this.timePicker12Hour = true;
114
+ this.singleDatePicker = false;
115
+ this.ranges = {};
116
+
117
+ this.opens = 'right';
118
+ if (this.element.hasClass('pull-right'))
119
+ this.opens = 'left';
120
+
121
+ this.buttonClasses = ['btn', 'btn-small btn-sm'];
122
+ this.applyClass = 'btn-success';
123
+ this.cancelClass = 'btn-default';
124
+
125
+ this.format = 'MM/DD/YYYY';
126
+ this.separator = ' - ';
127
+
128
+ this.locale = {
129
+ applyLabel: 'Apply',
130
+ cancelLabel: 'Cancel',
131
+ fromLabel: 'From',
132
+ toLabel: 'To',
133
+ weekLabel: 'W',
134
+ customRangeLabel: 'Custom Range',
135
+ daysOfWeek: moment()._lang._weekdaysMin.slice(),
136
+ monthNames: moment()._lang._monthsShort.slice(),
137
+ firstDay: 0
138
+ };
139
+
140
+ this.cb = function () { };
141
+
142
+ if (typeof options.format === 'string')
114
143
  this.format = options.format;
115
144
 
116
- if (typeof options.separator == 'string')
145
+ if (typeof options.separator === 'string')
117
146
  this.separator = options.separator;
118
147
 
119
- if (typeof options.startDate == 'string')
148
+ if (typeof options.startDate === 'string')
120
149
  this.startDate = moment(options.startDate, this.format);
121
150
 
122
- if (typeof options.endDate == 'string')
151
+ if (typeof options.endDate === 'string')
123
152
  this.endDate = moment(options.endDate, this.format);
124
153
 
125
- if (typeof options.minDate == 'string')
154
+ if (typeof options.minDate === 'string')
126
155
  this.minDate = moment(options.minDate, this.format);
127
156
 
128
- if (typeof options.maxDate == 'string')
157
+ if (typeof options.maxDate === 'string')
129
158
  this.maxDate = moment(options.maxDate, this.format);
130
159
 
131
- if (typeof options.startDate == 'object')
160
+ if (typeof options.startDate === 'object')
132
161
  this.startDate = moment(options.startDate);
133
162
 
134
- if (typeof options.endDate == 'object')
163
+ if (typeof options.endDate === 'object')
135
164
  this.endDate = moment(options.endDate);
136
165
 
137
- if (typeof options.minDate == 'object')
166
+ if (typeof options.minDate === 'object')
138
167
  this.minDate = moment(options.minDate);
139
168
 
140
- if (typeof options.maxDate == 'object')
169
+ if (typeof options.maxDate === 'object')
141
170
  this.maxDate = moment(options.maxDate);
142
171
 
143
- if (typeof options.ranges == 'object') {
144
- for (var range in options.ranges) {
145
-
146
- var start = moment(options.ranges[range][0]);
147
- var end = moment(options.ranges[range][1]);
172
+ if (typeof options.applyClass === 'string')
173
+ this.applyClass = options.applyClass;
148
174
 
149
- // If we have a min/max date set, bound this range
150
- // to it, but only if it would otherwise fall
151
- // outside of the min/max.
152
- if (this.minDate && start.isBefore(this.minDate))
153
- start = moment(this.minDate);
175
+ if (typeof options.cancelClass === 'string')
176
+ this.cancelClass = options.cancelClass;
154
177
 
155
- if (this.maxDate && end.isAfter(this.maxDate))
156
- end = moment(this.maxDate);
178
+ if (typeof options.dateLimit === 'object')
179
+ this.dateLimit = options.dateLimit;
157
180
 
158
- // If the end of the range is before the minimum (if min is set) OR
159
- // the start of the range is after the max (also if set) don't display this
160
- // range option.
161
- if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) {
162
- continue;
163
- }
181
+ // update day names order to firstDay
182
+ if (typeof options.locale === 'object') {
164
183
 
165
- this.ranges[range] = [start, end];
184
+ if (typeof options.locale.daysOfWeek === 'object') {
185
+ // Create a copy of daysOfWeek to avoid modification of original
186
+ // options object for reusability in multiple daterangepicker instances
187
+ this.locale.daysOfWeek = options.locale.daysOfWeek.slice();
166
188
  }
167
189
 
168
- var list = '<ul>';
169
- for (var range in this.ranges) {
170
- list += '<li>' + range + '</li>';
190
+ if (typeof options.locale.monthNames === 'object') {
191
+ this.locale.monthNames = options.locale.monthNames.slice();
171
192
  }
172
- list += '<li>' + this.locale.customRangeLabel + '</li>';
173
- list += '</ul>';
174
- this.container.find('.ranges').prepend(list);
175
- }
176
193
 
177
- if (typeof options.dateLimit == 'object')
178
- this.dateLimit = options.dateLimit;
179
-
180
- // update day names order to firstDay
181
- if (typeof options.locale == 'object') {
182
- if (typeof options.locale.firstDay == 'number') {
194
+ if (typeof options.locale.firstDay === 'number') {
183
195
  this.locale.firstDay = options.locale.firstDay;
184
196
  var iterator = options.locale.firstDay;
185
197
  while (iterator > 0) {
@@ -187,140 +199,215 @@
187
199
  iterator--;
188
200
  }
189
201
  }
202
+
203
+ if (typeof options.locale.applyLabel === 'string') {
204
+ this.locale.applyLabel = options.locale.applyLabel;
205
+ }
206
+
207
+ if (typeof options.locale.cancelLabel === 'string') {
208
+ this.locale.cancelLabel = options.locale.cancelLabel;
209
+ }
210
+
211
+ if (typeof options.locale.fromLabel === 'string') {
212
+ this.locale.fromLabel = options.locale.fromLabel;
213
+ }
214
+
215
+ if (typeof options.locale.toLabel === 'string') {
216
+ this.locale.toLabel = options.locale.toLabel;
217
+ }
218
+
219
+ if (typeof options.locale.weekLabel === 'string') {
220
+ this.locale.weekLabel = options.locale.weekLabel;
221
+ }
222
+
223
+ if (typeof options.locale.customRangeLabel === 'string') {
224
+ this.locale.customRangeLabel = options.locale.customRangeLabel;
225
+ }
190
226
  }
191
227
 
192
- if (typeof options.opens == 'string')
228
+ if (typeof options.opens === 'string')
193
229
  this.opens = options.opens;
194
230
 
195
- if (typeof options.showWeekNumbers == 'boolean') {
231
+ if (typeof options.showWeekNumbers === 'boolean') {
196
232
  this.showWeekNumbers = options.showWeekNumbers;
197
233
  }
198
234
 
199
- if (typeof options.buttonClasses == 'string') {
235
+ if (typeof options.buttonClasses === 'string') {
200
236
  this.buttonClasses = [options.buttonClasses];
201
237
  }
202
238
 
203
- if (typeof options.buttonClasses == 'object') {
239
+ if (typeof options.buttonClasses === 'object') {
204
240
  this.buttonClasses = options.buttonClasses;
205
241
  }
206
242
 
207
- if (typeof options.showDropdowns == 'boolean') {
243
+ if (typeof options.showDropdowns === 'boolean') {
208
244
  this.showDropdowns = options.showDropdowns;
209
245
  }
210
246
 
211
- if (typeof options.timePicker == 'boolean') {
247
+ if (typeof options.singleDatePicker === 'boolean') {
248
+ this.singleDatePicker = options.singleDatePicker;
249
+ }
250
+
251
+ if (typeof options.timePicker === 'boolean') {
212
252
  this.timePicker = options.timePicker;
213
253
  }
214
254
 
215
- if (typeof options.timePickerIncrement == 'number') {
255
+ if (typeof options.timePickerIncrement === 'number') {
216
256
  this.timePickerIncrement = options.timePickerIncrement;
217
257
  }
218
258
 
219
- if (typeof options.timePicker12Hour == 'boolean') {
259
+ if (typeof options.timePicker12Hour === 'boolean') {
220
260
  this.timePicker12Hour = options.timePicker12Hour;
221
261
  }
222
262
 
223
- }
224
-
225
- if (!this.timePicker) {
226
- this.startDate = this.startDate.startOf('day');
227
- this.endDate = this.endDate.startOf('day');
228
- }
263
+ var start, end, range;
264
+
265
+ //if no start/end dates set, check if an input element contains initial values
266
+ if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
267
+ if ($(this.element).is('input[type=text]')) {
268
+ var val = $(this.element).val();
269
+ var split = val.split(this.separator);
270
+ start = end = null;
271
+ if (split.length == 2) {
272
+ start = moment(split[0], this.format);
273
+ end = moment(split[1], this.format);
274
+ } else if (this.singleDatePicker) {
275
+ start = moment(val, this.format);
276
+ end = moment(val, this.format);
277
+ }
278
+ if (start !== null && end !== null) {
279
+ this.startDate = start;
280
+ this.endDate = end;
281
+ }
282
+ }
283
+ }
229
284
 
230
- //apply CSS classes to buttons
231
- var c = this.container;
232
- $.each(this.buttonClasses, function (idx, val) {
233
- c.find('button').addClass(val);
234
- });
285
+ if (typeof options.ranges === 'object') {
286
+ for (range in options.ranges) {
235
287
 
236
- if (this.opens == 'right') {
237
- //swap calendar positions
238
- var left = this.container.find('.calendar.left');
239
- var right = this.container.find('.calendar.right');
240
- left.removeClass('left').addClass('right');
241
- right.removeClass('right').addClass('left');
242
- }
288
+ start = moment(options.ranges[range][0]);
289
+ end = moment(options.ranges[range][1]);
243
290
 
244
- if (typeof options == 'undefined' || typeof options.ranges == 'undefined') {
245
- this.container.find('.calendar').show();
246
- this.move();
247
- }
291
+ // If we have a min/max date set, bound this range
292
+ // to it, but only if it would otherwise fall
293
+ // outside of the min/max.
294
+ if (this.minDate && start.isBefore(this.minDate))
295
+ start = moment(this.minDate);
248
296
 
249
- if (typeof cb == 'function')
250
- this.cb = cb;
297
+ if (this.maxDate && end.isAfter(this.maxDate))
298
+ end = moment(this.maxDate);
251
299
 
252
- this.container.addClass('opens' + this.opens);
300
+ // If the end of the range is before the minimum (if min is set) OR
301
+ // the start of the range is after the max (also if set) don't display this
302
+ // range option.
303
+ if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) {
304
+ continue;
305
+ }
253
306
 
254
- //try parse date if in text input
255
- if (!hasOptions || (typeof options.startDate == 'undefined' && typeof options.endDate == 'undefined')) {
256
- if ($(this.element).is('input[type=text]')) {
257
- var val = $(this.element).val();
258
- var split = val.split(this.separator);
259
- var start, end;
260
- if (split.length == 2) {
261
- start = moment(split[0], this.format);
262
- end = moment(split[1], this.format);
307
+ this.ranges[range] = [start, end];
263
308
  }
264
- if (start != null && end != null) {
265
- this.startDate = start;
266
- this.endDate = end;
309
+
310
+ var list = '<ul>';
311
+ for (range in this.ranges) {
312
+ list += '<li>' + range + '</li>';
267
313
  }
314
+ list += '<li>' + this.locale.customRangeLabel + '</li>';
315
+ list += '</ul>';
316
+ this.container.find('.ranges ul').remove();
317
+ this.container.find('.ranges').prepend(list);
318
+ }
319
+
320
+ if (typeof callback === 'function') {
321
+ this.cb = callback;
322
+ }
323
+
324
+ if (!this.timePicker) {
325
+ this.startDate = this.startDate.startOf('day');
326
+ this.endDate = this.endDate.endOf('day');
268
327
  }
269
- }
270
328
 
271
- //state
272
- this.oldStartDate = this.startDate.clone();
273
- this.oldEndDate = this.endDate.clone();
329
+ if (this.singleDatePicker) {
330
+ this.opens = 'right';
331
+ this.container.find('.calendar.right').show();
332
+ this.container.find('.calendar.left').hide();
333
+ this.container.find('.ranges').hide();
334
+ if (!this.container.find('.calendar.right').hasClass('single'))
335
+ this.container.find('.calendar.right').addClass('single');
336
+ } else {
337
+ this.container.find('.calendar.right').removeClass('single');
338
+ this.container.find('.ranges').show();
339
+ }
274
340
 
275
- this.leftCalendar = {
276
- month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]),
277
- calendar: []
278
- };
341
+ this.oldStartDate = this.startDate.clone();
342
+ this.oldEndDate = this.endDate.clone();
343
+ this.oldChosenLabel = this.chosenLabel;
279
344
 
280
- this.rightCalendar = {
281
- month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]),
282
- calendar: []
283
- };
345
+ this.leftCalendar = {
346
+ month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]),
347
+ calendar: []
348
+ };
284
349
 
285
- //event listeners
286
- this.container.on('mousedown', $.proxy(this.mousedown, this));
350
+ this.rightCalendar = {
351
+ month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]),
352
+ calendar: []
353
+ };
287
354
 
288
- this.container.find('.calendar')
289
- .on('click', '.prev', $.proxy(this.clickPrev, this))
290
- .on('click', '.next', $.proxy(this.clickNext, this))
291
- .on('click', 'td.available', $.proxy(this.clickDate, this))
292
- .on('mouseenter', 'td.available', $.proxy(this.enterDate, this))
293
- .on('mouseleave', 'td.available', $.proxy(this.updateFormInputs, this))
294
- .on('change', 'select.yearselect', $.proxy(this.updateMonthYear, this))
295
- .on('change', 'select.monthselect', $.proxy(this.updateMonthYear, this))
296
- .on('change', 'select.hourselect,select.minuteselect,select.ampmselect', $.proxy(this.updateTime, this));
355
+ if (this.opens == 'right') {
356
+ //swap calendar positions
357
+ var left = this.container.find('.calendar.left');
358
+ var right = this.container.find('.calendar.right');
359
+ left.removeClass('left').addClass('right');
360
+ right.removeClass('right').addClass('left');
361
+ }
297
362
 
298
- this.container.find('.ranges')
299
- .on('click', 'button.applyBtn', $.proxy(this.clickApply, this))
300
- .on('click', 'button.cancelBtn', $.proxy(this.clickCancel, this))
301
- .on('click', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this))
302
- .on('click', 'li', $.proxy(this.clickRange, this))
303
- .on('mouseenter', 'li', $.proxy(this.enterRange, this))
304
- .on('mouseleave', 'li', $.proxy(this.updateFormInputs, this));
363
+ if (typeof options.ranges === 'undefined' && !this.singleDatePicker) {
364
+ this.container.addClass('show-calendar');
365
+ }
305
366
 
306
- this.element.on('keyup', $.proxy(this.updateFromControl, this));
367
+ this.container.addClass('opens' + this.opens);
307
368
 
308
- this.updateView();
309
- this.updateCalendars();
369
+ this.updateView();
370
+ this.updateCalendars();
310
371
 
311
- };
372
+ },
312
373
 
313
- DateRangePicker.prototype = {
374
+ setStartDate: function(startDate) {
375
+ if (typeof startDate === 'string')
376
+ this.startDate = moment(startDate, this.format);
314
377
 
315
- constructor: DateRangePicker,
378
+ if (typeof startDate === 'object')
379
+ this.startDate = moment(startDate);
380
+
381
+ if (!this.timePicker)
382
+ this.startDate = this.startDate.startOf('day');
383
+
384
+ this.oldStartDate = this.startDate.clone();
385
+
386
+ this.updateView();
387
+ this.updateCalendars();
388
+ this.updateInputText();
389
+ },
316
390
 
317
- mousedown: function (e) {
318
- e.stopPropagation();
391
+ setEndDate: function(endDate) {
392
+ if (typeof endDate === 'string')
393
+ this.endDate = moment(endDate, this.format);
394
+
395
+ if (typeof endDate === 'object')
396
+ this.endDate = moment(endDate);
397
+
398
+ if (!this.timePicker)
399
+ this.endDate = this.endDate.endOf('day');
400
+
401
+ this.oldEndDate = this.endDate.clone();
402
+
403
+ this.updateView();
404
+ this.updateCalendars();
405
+ this.updateInputText();
319
406
  },
320
407
 
321
408
  updateView: function () {
322
- this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
323
- this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
409
+ this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute());
410
+ this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute());
324
411
  this.updateFormInputs();
325
412
  },
326
413
 
@@ -339,11 +426,20 @@
339
426
  if (!this.element.is('input')) return;
340
427
  if (!this.element.val().length) return;
341
428
 
342
- var dateString = this.element.val().split(this.separator);
343
- var start = moment(dateString[0], this.format);
344
- var end = moment(dateString[1], this.format);
429
+ var dateString = this.element.val().split(this.separator),
430
+ start = null,
431
+ end = null;
432
+
433
+ if(dateString.length === 2) {
434
+ start = moment(dateString[0], this.format);
435
+ end = moment(dateString[1], this.format);
436
+ }
437
+
438
+ if (this.singleDatePicker || start === null || end === null) {
439
+ start = moment(this.element.val(), this.format);
440
+ end = start;
441
+ }
345
442
 
346
- if (start == null || end == null) return;
347
443
  if (end.isBefore(start)) return;
348
444
 
349
445
  this.oldStartDate = this.startDate.clone();
@@ -360,14 +456,18 @@
360
456
 
361
457
  notify: function () {
362
458
  this.updateView();
363
- this.cb(this.startDate, this.endDate);
459
+ this.cb(this.startDate, this.endDate, this.chosenLabel);
364
460
  },
365
461
 
366
462
  move: function () {
367
- var parentOffset = {
368
- top: this.parentEl.offset().top - (this.parentEl.is('body') ? 0 : this.parentEl.scrollTop()),
369
- left: this.parentEl.offset().left - (this.parentEl.is('body') ? 0 : this.parentEl.scrollLeft())
370
- };
463
+ var parentOffset = { top: 0, left: 0 };
464
+ if (!this.parentEl.is('body')) {
465
+ parentOffset = {
466
+ top: this.parentEl.offset().top - this.parentEl.scrollTop(),
467
+ left: this.parentEl.offset().left - this.parentEl.scrollLeft()
468
+ };
469
+ }
470
+
371
471
  if (this.opens == 'left') {
372
472
  this.container.css({
373
473
  top: this.element.offset().top + this.element.outerHeight() - parentOffset.top,
@@ -395,20 +495,56 @@
395
495
  }
396
496
  },
397
497
 
498
+ toggle: function (e) {
499
+ if (this.element.hasClass('active')) {
500
+ this.hide();
501
+ } else {
502
+ this.show();
503
+ }
504
+ },
505
+
398
506
  show: function (e) {
507
+ if (this.isShowing) return;
508
+
509
+ this.element.addClass('active');
399
510
  this.container.show();
400
511
  this.move();
401
512
 
402
- if (e) {
403
- e.stopPropagation();
404
- e.preventDefault();
405
- }
513
+ // Create a click proxy that is private to this instance of datepicker, for unbinding
514
+ this._outsideClickProxy = $.proxy(function (e) { this.outsideClick(e); }, this);
515
+ // Bind global datepicker mousedown for hiding and
516
+ $(document)
517
+ .on('mousedown.daterangepicker', this._outsideClickProxy)
518
+ // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them
519
+ .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)
520
+ // and also close when focus changes to outside the picker (eg. tabbing between controls)
521
+ .on('focusin.daterangepicker', this._outsideClickProxy);
522
+
523
+ this.isShowing = true;
524
+ this.element.trigger('show.daterangepicker', this);
525
+ },
406
526
 
407
- $(document).on('mousedown', $.proxy(this.hide, this));
408
- this.element.trigger('shown', {target: e.target, picker: this});
527
+ outsideClick: function (e) {
528
+ var target = $(e.target);
529
+ // if the page is clicked anywhere except within the daterangerpicker/button
530
+ // itself then call this.hide()
531
+ if (
532
+ target.closest(this.element).length ||
533
+ target.closest(this.container).length ||
534
+ target.closest('.calendar-date').length
535
+ ) return;
536
+ this.hide();
409
537
  },
410
538
 
411
539
  hide: function (e) {
540
+ if (!this.isShowing) return;
541
+
542
+ $(document)
543
+ .off('mousedown.daterangepicker')
544
+ .off('click.daterangepicker', '[data-toggle=dropdown]')
545
+ .off('focusin.daterangepicker');
546
+
547
+ this.element.removeClass('active');
412
548
  this.container.hide();
413
549
 
414
550
  if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
@@ -417,11 +553,12 @@
417
553
  this.oldStartDate = this.startDate.clone();
418
554
  this.oldEndDate = this.endDate.clone();
419
555
 
420
- $(document).off('mousedown', this.hide);
421
- this.element.trigger('hidden', { picker: this });
556
+ this.isShowing = false;
557
+ this.element.trigger('hide.daterangepicker', this);
422
558
  },
423
559
 
424
560
  enterRange: function (e) {
561
+ // mouse pointer has entered a range label
425
562
  var label = e.target.innerHTML;
426
563
  if (label == this.locale.customRangeLabel) {
427
564
  this.updateView();
@@ -433,17 +570,27 @@
433
570
  },
434
571
 
435
572
  showCalendars: function() {
436
- this.container.find('.calendar').show();
573
+ this.container.addClass('show-calendar');
437
574
  this.move();
575
+ this.element.trigger('showCalendar.daterangepicker', this);
576
+ },
577
+
578
+ hideCalendars: function() {
579
+ this.container.removeClass('show-calendar');
580
+ this.element.trigger('hideCalendar.daterangepicker', this);
438
581
  },
439
582
 
440
583
  updateInputText: function() {
441
- if (this.element.is('input'))
584
+ if (this.element.is('input') && !this.singleDatePicker) {
442
585
  this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));
586
+ } else if (this.element.is('input')) {
587
+ this.element.val(this.startDate.format(this.format));
588
+ }
443
589
  },
444
590
 
445
591
  clickRange: function (e) {
446
592
  var label = e.target.innerHTML;
593
+ this.chosenLabel = label;
447
594
  if (label == this.locale.customRangeLabel) {
448
595
  this.showCalendars();
449
596
  } else {
@@ -454,7 +601,7 @@
454
601
 
455
602
  if (!this.timePicker) {
456
603
  this.startDate.startOf('day');
457
- this.endDate.startOf('day');
604
+ this.endDate.endOf('day');
458
605
  }
459
606
 
460
607
  this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute());
@@ -463,8 +610,9 @@
463
610
 
464
611
  this.updateInputText();
465
612
 
466
- this.container.find('.calendar').hide();
613
+ this.hideCalendars();
467
614
  this.hide();
615
+ this.element.trigger('apply.daterangepicker', this);
468
616
  }
469
617
  },
470
618
 
@@ -509,19 +657,20 @@
509
657
  var col = title.substr(3, 1);
510
658
  var cal = $(e.target).parents('.calendar');
511
659
 
660
+ var startDate, endDate;
512
661
  if (cal.hasClass('left')) {
513
- var startDate = this.leftCalendar.calendar[row][col];
514
- var endDate = this.endDate;
515
- if (typeof this.dateLimit == 'object') {
662
+ startDate = this.leftCalendar.calendar[row][col];
663
+ endDate = this.endDate;
664
+ if (typeof this.dateLimit === 'object') {
516
665
  var maxDate = moment(startDate).add(this.dateLimit).startOf('day');
517
666
  if (endDate.isAfter(maxDate)) {
518
667
  endDate = maxDate;
519
668
  }
520
669
  }
521
670
  } else {
522
- var startDate = this.startDate;
523
- var endDate = this.rightCalendar.calendar[row][col];
524
- if (typeof this.dateLimit == 'object') {
671
+ startDate = this.startDate;
672
+ endDate = this.rightCalendar.calendar[row][col];
673
+ if (typeof this.dateLimit === 'object') {
525
674
  var minDate = moment(endDate).subtract(this.dateLimit).startOf('day');
526
675
  if (startDate.isBefore(minDate)) {
527
676
  startDate = minDate;
@@ -529,72 +678,80 @@
529
678
  }
530
679
  }
531
680
 
681
+ if (this.singleDatePicker && cal.hasClass('left')) {
682
+ endDate = startDate.clone();
683
+ } else if (this.singleDatePicker && cal.hasClass('right')) {
684
+ startDate = endDate.clone();
685
+ }
686
+
532
687
  cal.find('td').removeClass('active');
533
688
 
534
689
  if (startDate.isSame(endDate) || startDate.isBefore(endDate)) {
535
690
  $(e.target).addClass('active');
536
691
  this.startDate = startDate;
537
692
  this.endDate = endDate;
693
+ this.chosenLabel = this.locale.customRangeLabel;
538
694
  } else if (startDate.isAfter(endDate)) {
539
695
  $(e.target).addClass('active');
696
+ var difference = this.endDate.diff(this.startDate);
540
697
  this.startDate = startDate;
541
- this.endDate = moment(startDate).add('day', 1).startOf('day');
698
+ this.endDate = moment(startDate).add('ms', difference);
699
+ this.chosenLabel = this.locale.customRangeLabel;
542
700
  }
543
701
 
544
702
  this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
545
703
  this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
546
704
  this.updateCalendars();
705
+
706
+ if (!this.timePicker)
707
+ endDate.endOf('day');
708
+
709
+ if (this.singleDatePicker)
710
+ this.clickApply();
547
711
  },
548
712
 
549
713
  clickApply: function (e) {
550
714
  this.updateInputText();
551
715
  this.hide();
716
+ this.element.trigger('apply.daterangepicker', this);
552
717
  },
553
718
 
554
719
  clickCancel: function (e) {
555
720
  this.startDate = this.oldStartDate;
556
721
  this.endDate = this.oldEndDate;
722
+ this.chosenLabel = this.oldChosenLabel;
557
723
  this.updateView();
558
724
  this.updateCalendars();
559
725
  this.hide();
726
+ this.element.trigger('cancel.daterangepicker', this);
560
727
  },
561
728
 
562
729
  updateMonthYear: function (e) {
563
-
564
- var isLeft = $(e.target).closest('.calendar').hasClass('left');
565
- var cal = this.container.find('.calendar.left');
566
- if (!isLeft)
567
- cal = this.container.find('.calendar.right');
730
+ var isLeft = $(e.target).closest('.calendar').hasClass('left'),
731
+ leftOrRight = isLeft ? 'left' : 'right',
732
+ cal = this.container.find('.calendar.'+leftOrRight);
568
733
 
569
734
  // Month must be Number for new moment versions
570
735
  var month = parseInt(cal.find('.monthselect').val(), 10);
571
736
  var year = cal.find('.yearselect').val();
572
737
 
573
- if (isLeft) {
574
- this.leftCalendar.month.month(month).year(year);
575
- } else {
576
- this.rightCalendar.month.month(month).year(year);
577
- }
578
-
738
+ this[leftOrRight+'Calendar'].month.month(month).year(year);
579
739
  this.updateCalendars();
580
-
581
740
  },
582
741
 
583
742
  updateTime: function(e) {
584
743
 
585
- var isLeft = $(e.target).closest('.calendar').hasClass('left');
586
- var cal = this.container.find('.calendar.left');
587
- if (!isLeft)
588
- cal = this.container.find('.calendar.right');
744
+ var cal = $(e.target).closest('.calendar'),
745
+ isLeft = cal.hasClass('left');
589
746
 
590
- var hour = parseInt(cal.find('.hourselect').val());
591
- var minute = parseInt(cal.find('.minuteselect').val());
747
+ var hour = parseInt(cal.find('.hourselect').val(), 10);
748
+ var minute = parseInt(cal.find('.minuteselect').val(), 10);
592
749
 
593
750
  if (this.timePicker12Hour) {
594
751
  var ampm = cal.find('.ampmselect').val();
595
- if (ampm == 'PM' && hour < 12)
752
+ if (ampm === 'PM' && hour < 12)
596
753
  hour += 12;
597
- if (ampm == 'AM' && hour == 12)
754
+ if (ampm === 'AM' && hour === 12)
598
755
  hour = 0;
599
756
  }
600
757
 
@@ -613,14 +770,13 @@
613
770
  }
614
771
 
615
772
  this.updateCalendars();
616
-
617
773
  },
618
774
 
619
775
  updateCalendars: function () {
620
776
  this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), 'left');
621
777
  this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), 'right');
622
- this.container.find('.calendar.left').html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate));
623
- this.container.find('.calendar.right').html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate));
778
+ this.container.find('.calendar.left').empty().html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate));
779
+ this.container.find('.calendar.right').empty().html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate));
624
780
 
625
781
  this.container.find('.ranges li').removeClass('active');
626
782
  var customRange = true;
@@ -629,23 +785,26 @@
629
785
  if (this.timePicker) {
630
786
  if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {
631
787
  customRange = false;
632
- this.container.find('.ranges li:eq(' + i + ')').addClass('active');
788
+ this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')
789
+ .addClass('active').html();
633
790
  }
634
791
  } else {
635
792
  //ignore times when comparing dates if time picker is not enabled
636
793
  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')) {
637
794
  customRange = false;
638
- this.container.find('.ranges li:eq(' + i + ')').addClass('active');
795
+ this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')
796
+ .addClass('active').html();
639
797
  }
640
798
  }
641
799
  i++;
642
800
  }
643
- if (customRange)
644
- this.container.find('.ranges li:last').addClass('active');
801
+ if (customRange) {
802
+ this.chosenLabel = this.container.find('.ranges li:last')
803
+ .addClass('active').html();
804
+ }
645
805
  },
646
806
 
647
807
  buildCalendar: function (month, year, hour, minute, side) {
648
-
649
808
  var firstDay = moment([year, month, 1]);
650
809
  var lastMonth = moment(firstDay).subtract('month', 1).month();
651
810
  var lastYear = moment(firstDay).subtract('month', 1).year();
@@ -654,9 +813,11 @@
654
813
 
655
814
  var dayOfWeek = firstDay.day();
656
815
 
816
+ var i;
817
+
657
818
  //initialize a 6 rows x 7 columns array for the calendar
658
819
  var calendar = [];
659
- for (var i = 0; i < 6; i++) {
820
+ for (i = 0; i < 6; i++) {
660
821
  calendar[i] = [];
661
822
  }
662
823
 
@@ -669,8 +830,9 @@
669
830
  startDay = daysInLastMonth - 6;
670
831
 
671
832
  var curDate = moment([lastYear, lastMonth, startDay, 12, minute]);
672
- for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('hour', 24)) {
673
- if (i > 0 && col % 7 == 0) {
833
+ var col, row;
834
+ for (i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('hour', 24)) {
835
+ if (i > 0 && col % 7 === 0) {
674
836
  col = 0;
675
837
  row++;
676
838
  }
@@ -679,7 +841,6 @@
679
841
  }
680
842
 
681
843
  return calendar;
682
-
683
844
  },
684
845
 
685
846
  renderDropdowns: function (selected, minDate, maxDate) {
@@ -725,7 +886,7 @@
725
886
  html += '<th></th>';
726
887
 
727
888
  if (!minDate || minDate.isBefore(calendar[1][1])) {
728
- html += '<th class="prev available"><i class="icon-arrow-left glyphicon glyphicon-arrow-left"></i></th>';
889
+ html += '<th class="prev available"><i class="fa fa-arrow-left icon-arrow-left glyphicon glyphicon-arrow-left"></i></th>';
729
890
  } else {
730
891
  html += '<th></th>';
731
892
  }
@@ -736,9 +897,9 @@
736
897
  dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate);
737
898
  }
738
899
 
739
- html += '<th colspan="5" style="width: auto">' + dateHtml + '</th>';
900
+ html += '<th colspan="5" class="month">' + dateHtml + '</th>';
740
901
  if (!maxDate || maxDate.isAfter(calendar[1][1])) {
741
- html += '<th class="next available"><i class="icon-arrow-right glyphicon glyphicon-arrow-right"></i></th>';
902
+ html += '<th class="next available"><i class="fa fa-arrow-right icon-arrow-right glyphicon glyphicon-arrow-right"></i></th>';
742
903
  } else {
743
904
  html += '<th></th>';
744
905
  }
@@ -769,7 +930,7 @@
769
930
  var cname = 'available ';
770
931
  cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off';
771
932
 
772
- if ((minDate && calendar[row][col].isBefore(minDate)) || (maxDate && calendar[row][col].isAfter(maxDate))) {
933
+ if ((minDate && calendar[row][col].isBefore(minDate, 'day')) || (maxDate && calendar[row][col].isAfter(maxDate, 'day'))) {
773
934
  cname = ' off disabled ';
774
935
  } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) {
775
936
  cname += ' active ';
@@ -795,6 +956,7 @@
795
956
  html += '</table>';
796
957
  html += '</div>';
797
958
 
959
+ var i;
798
960
  if (this.timePicker) {
799
961
 
800
962
  html += '<div class="calendar-time">';
@@ -807,11 +969,11 @@
807
969
  end = 12;
808
970
  if (selected_hour >= 12)
809
971
  selected_hour -= 12;
810
- if (selected_hour == 0)
972
+ if (selected_hour === 0)
811
973
  selected_hour = 12;
812
974
  }
813
975
 
814
- for (var i = start; i <= end; i++) {
976
+ for (i = start; i <= end; i++) {
815
977
  if (i == selected_hour) {
816
978
  html += '<option value="' + i + '" selected="selected">' + i + '</option>';
817
979
  } else {
@@ -823,7 +985,7 @@
823
985
 
824
986
  html += '<select class="minuteselect">';
825
987
 
826
- for (var i = 0; i < 60; i += this.timePickerIncrement) {
988
+ for (i = 0; i < 60; i += this.timePickerIncrement) {
827
989
  var num = i;
828
990
  if (num < 10)
829
991
  num = '0' + num;
@@ -852,6 +1014,14 @@
852
1014
 
853
1015
  return html;
854
1016
 
1017
+ },
1018
+
1019
+ remove: function() {
1020
+
1021
+ this.container.remove();
1022
+ this.element.off('.daterangepicker');
1023
+ this.element.removeData('daterangepicker');
1024
+
855
1025
  }
856
1026
 
857
1027
  };
@@ -859,10 +1029,11 @@
859
1029
  $.fn.daterangepicker = function (options, cb) {
860
1030
  this.each(function () {
861
1031
  var el = $(this);
862
- if (!el.data('daterangepicker'))
863
- el.data('daterangepicker', new DateRangePicker(el, options, cb));
1032
+ if (el.data('daterangepicker'))
1033
+ el.data('daterangepicker').remove();
1034
+ el.data('daterangepicker', new DateRangePicker(el, options, cb));
864
1035
  });
865
1036
  return this;
866
1037
  };
867
1038
 
868
- }(window.jQuery);
1039
+ }(window.jQuery, window.moment);