daterangepicker-rails 0.0.2

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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ODFmNDFiMmRmMjcyNWU0MmQ0YThmOTM1Y2M1OTQ2ZWEzY2YxM2NhYQ==
5
+ data.tar.gz: !binary |-
6
+ Y2NjYzQ3MWY3MjEwZDdkZDVjMGVlNDk4ODVkNTM3ZWNlM2YzNzg0YQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NTBmODNkNDhhZWQ2MzQ5ODA3ZTk4ZjExZTJiNDQ1M2Q2OGVkZTRhZjIzMzk0
10
+ MjFkY2YwNmRjMDQ5NWViNjFjYWVmZGQ3MzQ2M2QzNGEwNzRjNTQ1NTU5ZTdm
11
+ YTEzZjdkOTlhMTFhMWM0Mzk5MDA2OWRiZTk5MjdjMWE0OTNkMDc=
12
+ data.tar.gz: !binary |-
13
+ ZGExOGQ3NjQ3OTcxNTRkM2NlMGRkMzZhOGVmNzNhMDRmMmVhZjA4ZDAzY2Zh
14
+ YmYwZWVmOWRhNDEwYTQ3Mzk0MzA4OGUwN2YyNjA1YTM4ZDk1NmYxZDJhYzE4
15
+ MTViYzIwNDVkNjZhZmQzMmZhMTYzOTBiMzc0Y2M2MjE3MjFkM2Y=
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in daterangepicker-rails.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Venkata Reddy Bhavanam
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Daterangepicker::Rails
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'daterangepicker-rails'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install daterangepicker-rails
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/daterangepicker-rails/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'daterangepicker/rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "daterangepicker-rails"
8
+ spec.version = Daterangepicker::Rails::VERSION
9
+ spec.authors = ["Venkata Reddy Bhavanam"]
10
+ spec.email = ["venkatareddy.cs@gmail.com"]
11
+ spec.summary = %q{bootstrap css, moment js, datarangepicker js.}
12
+ spec.description = %q{Include Dan Grossman's Bootstrap DateRangePicker Easily in your rails app}
13
+ spec.homepage = "https://github.com/rubystar/daterangepicker-rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,8 @@
1
+ require "daterangepicker/rails/version"
2
+
3
+ module Daterangepicker
4
+ module Rails
5
+ class Engine < Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Daterangepicker
2
+ module Rails
3
+ VERSION = "0.0.2"
4
+ end
5
+ end
@@ -0,0 +1,1017 @@
1
+ /**
2
+ * @version: 1.3.6
3
+ * @author: Dan Grossman http://www.dangrossman.info/
4
+ * @date: 2014-04-29
5
+ * @copyright: Copyright (c) 2012-2014 Dan Grossman. All rights reserved.
6
+ * @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0
7
+ * @website: http://www.improvely.com/
8
+ */
9
+ !function ($, moment) {
10
+
11
+ var DateRangePicker = function (element, options, cb) {
12
+
13
+ // by default, the daterangepicker element is placed at the bottom of HTML body
14
+ this.parentEl = 'body';
15
+
16
+ //element that triggered the date range picker
17
+ this.element = $(element);
18
+
19
+ //create the picker HTML object
20
+ var DRPTemplate = '<div class="daterangepicker dropdown-menu">' +
21
+ '<div class="calendar left"></div>' +
22
+ '<div class="calendar right"></div>' +
23
+ '<div class="ranges">' +
24
+ '<div class="range_inputs">' +
25
+ '<div class="daterangepicker_start_input">' +
26
+ '<label for="daterangepicker_start"></label>' +
27
+ '<input class="input-mini" type="text" name="daterangepicker_start" value="" disabled="disabled" />' +
28
+ '</div>' +
29
+ '<div class="daterangepicker_end_input">' +
30
+ '<label for="daterangepicker_end"></label>' +
31
+ '<input class="input-mini" type="text" name="daterangepicker_end" value="" disabled="disabled" />' +
32
+ '</div>' +
33
+ '<button class="applyBtn" disabled="disabled"></button>&nbsp;' +
34
+ '<button class="cancelBtn"></button>' +
35
+ '</div>' +
36
+ '</div>' +
37
+ '</div>';
38
+
39
+ //custom options
40
+ if (typeof options !== 'object' || options === null)
41
+ options = {};
42
+
43
+ this.parentEl = (typeof options === 'object' && options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
44
+ this.container = $(DRPTemplate).appendTo(this.parentEl);
45
+
46
+ this.setOptions(options, cb);
47
+
48
+ //apply CSS classes and labels to buttons
49
+ var c = this.container;
50
+ $.each(this.buttonClasses, function (idx, val) {
51
+ c.find('button').addClass(val);
52
+ });
53
+ this.container.find('.daterangepicker_start_input label').html(this.locale.fromLabel);
54
+ this.container.find('.daterangepicker_end_input label').html(this.locale.toLabel);
55
+ if (this.applyClass.length)
56
+ this.container.find('.applyBtn').addClass(this.applyClass);
57
+ if (this.cancelClass.length)
58
+ this.container.find('.cancelBtn').addClass(this.cancelClass);
59
+ this.container.find('.applyBtn').html(this.locale.applyLabel);
60
+ this.container.find('.cancelBtn').html(this.locale.cancelLabel);
61
+
62
+ //event listeners
63
+
64
+ this.container.find('.calendar')
65
+ .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
66
+ .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
67
+ .on('click.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
68
+ .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.enterDate, this))
69
+ .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))
70
+ .on('change.daterangepicker', 'select.yearselect', $.proxy(this.updateMonthYear, this))
71
+ .on('change.daterangepicker', 'select.monthselect', $.proxy(this.updateMonthYear, this))
72
+ .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.ampmselect', $.proxy(this.updateTime, this));
73
+
74
+ this.container.find('.ranges')
75
+ .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
76
+ .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
77
+ .on('click.daterangepicker', '.daterangepicker_start_input,.daterangepicker_end_input', $.proxy(this.showCalendars, this))
78
+ .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
79
+ .on('mouseenter.daterangepicker', 'li', $.proxy(this.enterRange, this))
80
+ .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));
81
+
82
+ if (this.element.is('input')) {
83
+ this.element.on({
84
+ 'click.daterangepicker': $.proxy(this.show, this),
85
+ 'focus.daterangepicker': $.proxy(this.show, this),
86
+ 'keyup.daterangepicker': $.proxy(this.updateFromControl, this)
87
+ });
88
+ } else {
89
+ this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
90
+ }
91
+
92
+ };
93
+
94
+ DateRangePicker.prototype = {
95
+
96
+ constructor: DateRangePicker,
97
+
98
+ setOptions: function(options, callback) {
99
+
100
+ this.startDate = moment().startOf('day');
101
+ this.endDate = moment().endOf('day');
102
+ this.minDate = false;
103
+ this.maxDate = false;
104
+ this.dateLimit = false;
105
+
106
+ this.showDropdowns = false;
107
+ this.showWeekNumbers = false;
108
+ this.timePicker = false;
109
+ this.timePickerIncrement = 30;
110
+ this.timePicker12Hour = true;
111
+ this.singleDatePicker = false;
112
+ this.ranges = {};
113
+
114
+ this.opens = 'right';
115
+ if (this.element.hasClass('pull-right'))
116
+ this.opens = 'left';
117
+
118
+ this.buttonClasses = ['btn', 'btn-small'];
119
+ this.applyClass = 'btn-success';
120
+ this.cancelClass = 'btn-default';
121
+
122
+ this.format = 'MM/DD/YYYY';
123
+ this.separator = ' - ';
124
+
125
+ this.locale = {
126
+ applyLabel: 'Apply',
127
+ cancelLabel: 'Cancel',
128
+ fromLabel: 'From',
129
+ toLabel: 'To',
130
+ weekLabel: 'W',
131
+ customRangeLabel: 'Custom Range',
132
+ daysOfWeek: moment()._lang._weekdaysMin.slice(),
133
+ monthNames: moment()._lang._monthsShort.slice(),
134
+ firstDay: 0
135
+ };
136
+
137
+ this.cb = function () { };
138
+
139
+ if (typeof options.format === 'string')
140
+ this.format = options.format;
141
+
142
+ if (typeof options.separator === 'string')
143
+ this.separator = options.separator;
144
+
145
+ if (typeof options.startDate === 'string')
146
+ this.startDate = moment(options.startDate, this.format);
147
+
148
+ if (typeof options.endDate === 'string')
149
+ this.endDate = moment(options.endDate, this.format);
150
+
151
+ if (typeof options.minDate === 'string')
152
+ this.minDate = moment(options.minDate, this.format);
153
+
154
+ if (typeof options.maxDate === 'string')
155
+ this.maxDate = moment(options.maxDate, this.format);
156
+
157
+ if (typeof options.startDate === 'object')
158
+ this.startDate = moment(options.startDate);
159
+
160
+ if (typeof options.endDate === 'object')
161
+ this.endDate = moment(options.endDate);
162
+
163
+ if (typeof options.minDate === 'object')
164
+ this.minDate = moment(options.minDate);
165
+
166
+ if (typeof options.maxDate === 'object')
167
+ this.maxDate = moment(options.maxDate);
168
+
169
+ if (typeof options.applyClass === 'string')
170
+ this.applyClass = options.applyClass;
171
+
172
+ if (typeof options.cancelClass === 'string')
173
+ this.cancelClass = options.cancelClass;
174
+
175
+ if (typeof options.dateLimit === 'object')
176
+ this.dateLimit = options.dateLimit;
177
+
178
+ // update day names order to firstDay
179
+ if (typeof options.locale === 'object') {
180
+
181
+ if (typeof options.locale.daysOfWeek === 'object') {
182
+ // Create a copy of daysOfWeek to avoid modification of original
183
+ // options object for reusability in multiple daterangepicker instances
184
+ this.locale.daysOfWeek = options.locale.daysOfWeek.slice();
185
+ }
186
+
187
+ if (typeof options.locale.monthNames === 'object') {
188
+ this.locale.monthNames = options.locale.monthNames.slice();
189
+ }
190
+
191
+ if (typeof options.locale.firstDay === 'number') {
192
+ this.locale.firstDay = options.locale.firstDay;
193
+ var iterator = options.locale.firstDay;
194
+ while (iterator > 0) {
195
+ this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
196
+ iterator--;
197
+ }
198
+ }
199
+
200
+ if (typeof options.locale.applyLabel === 'string') {
201
+ this.locale.applyLabel = options.locale.applyLabel;
202
+ }
203
+
204
+ if (typeof options.locale.cancelLabel === 'string') {
205
+ this.locale.cancelLabel = options.locale.cancelLabel;
206
+ }
207
+
208
+ if (typeof options.locale.fromLabel === 'string') {
209
+ this.locale.fromLabel = options.locale.fromLabel;
210
+ }
211
+
212
+ if (typeof options.locale.toLabel === 'string') {
213
+ this.locale.toLabel = options.locale.toLabel;
214
+ }
215
+
216
+ if (typeof options.locale.weekLabel === 'string') {
217
+ this.locale.weekLabel = options.locale.weekLabel;
218
+ }
219
+
220
+ if (typeof options.locale.customRangeLabel === 'string') {
221
+ this.locale.customRangeLabel = options.locale.customRangeLabel;
222
+ }
223
+ }
224
+
225
+ if (typeof options.opens === 'string')
226
+ this.opens = options.opens;
227
+
228
+ if (typeof options.showWeekNumbers === 'boolean') {
229
+ this.showWeekNumbers = options.showWeekNumbers;
230
+ }
231
+
232
+ if (typeof options.buttonClasses === 'string') {
233
+ this.buttonClasses = [options.buttonClasses];
234
+ }
235
+
236
+ if (typeof options.buttonClasses === 'object') {
237
+ this.buttonClasses = options.buttonClasses;
238
+ }
239
+
240
+ if (typeof options.showDropdowns === 'boolean') {
241
+ this.showDropdowns = options.showDropdowns;
242
+ }
243
+
244
+ if (typeof options.singleDatePicker === 'boolean') {
245
+ this.singleDatePicker = options.singleDatePicker;
246
+ }
247
+
248
+ if (typeof options.timePicker === 'boolean') {
249
+ this.timePicker = options.timePicker;
250
+ }
251
+
252
+ if (typeof options.timePickerIncrement === 'number') {
253
+ this.timePickerIncrement = options.timePickerIncrement;
254
+ }
255
+
256
+ if (typeof options.timePicker12Hour === 'boolean') {
257
+ this.timePicker12Hour = options.timePicker12Hour;
258
+ }
259
+
260
+ var start, end, range;
261
+
262
+ //if no start/end dates set, check if an input element contains initial values
263
+ if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
264
+ if ($(this.element).is('input[type=text]')) {
265
+ var val = $(this.element).val();
266
+ var split = val.split(this.separator);
267
+ start = end = null;
268
+ if (split.length == 2) {
269
+ start = moment(split[0], this.format);
270
+ end = moment(split[1], this.format);
271
+ } else if (this.singleDatePicker) {
272
+ start = moment(val, this.format);
273
+ end = moment(val, this.format);
274
+ }
275
+ if (start !== null && end !== null) {
276
+ this.startDate = start;
277
+ this.endDate = end;
278
+ }
279
+ }
280
+ }
281
+
282
+ if (typeof options.ranges === 'object') {
283
+ for (range in options.ranges) {
284
+
285
+ start = moment(options.ranges[range][0]);
286
+ end = moment(options.ranges[range][1]);
287
+
288
+ // If we have a min/max date set, bound this range
289
+ // to it, but only if it would otherwise fall
290
+ // outside of the min/max.
291
+ if (this.minDate && start.isBefore(this.minDate))
292
+ start = moment(this.minDate);
293
+
294
+ if (this.maxDate && end.isAfter(this.maxDate))
295
+ end = moment(this.maxDate);
296
+
297
+ // If the end of the range is before the minimum (if min is set) OR
298
+ // the start of the range is after the max (also if set) don't display this
299
+ // range option.
300
+ if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) {
301
+ continue;
302
+ }
303
+
304
+ this.ranges[range] = [start, end];
305
+ }
306
+
307
+ var list = '<ul>';
308
+ for (range in this.ranges) {
309
+ list += '<li>' + range + '</li>';
310
+ }
311
+ list += '<li>' + this.locale.customRangeLabel + '</li>';
312
+ list += '</ul>';
313
+ this.container.find('.ranges ul').remove();
314
+ this.container.find('.ranges').prepend(list);
315
+ }
316
+
317
+ if (typeof callback === 'function') {
318
+ this.cb = callback;
319
+ }
320
+
321
+ if (!this.timePicker) {
322
+ this.startDate = this.startDate.startOf('day');
323
+ this.endDate = this.endDate.endOf('day');
324
+ }
325
+
326
+ if (this.singleDatePicker) {
327
+ this.opens = 'right';
328
+ this.container.find('.calendar.right').show();
329
+ this.container.find('.calendar.left').hide();
330
+ this.container.find('.ranges').hide();
331
+ if (!this.container.find('.calendar.right').hasClass('single'))
332
+ this.container.find('.calendar.right').addClass('single');
333
+ } else {
334
+ this.container.find('.calendar.right').removeClass('single');
335
+ this.container.find('.ranges').show();
336
+ }
337
+
338
+ this.oldStartDate = this.startDate.clone();
339
+ this.oldEndDate = this.endDate.clone();
340
+ this.oldChosenLabel = this.chosenLabel;
341
+
342
+ this.leftCalendar = {
343
+ month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]),
344
+ calendar: []
345
+ };
346
+
347
+ this.rightCalendar = {
348
+ month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]),
349
+ calendar: []
350
+ };
351
+
352
+ if (this.opens == 'right') {
353
+ //swap calendar positions
354
+ var left = this.container.find('.calendar.left');
355
+ var right = this.container.find('.calendar.right');
356
+ left.removeClass('left').addClass('right');
357
+ right.removeClass('right').addClass('left');
358
+ }
359
+
360
+ if (typeof options.ranges === 'undefined' && !this.singleDatePicker) {
361
+ this.container.addClass('show-calendar');
362
+ }
363
+
364
+ this.container.addClass('opens' + this.opens);
365
+
366
+ this.updateView();
367
+ this.updateCalendars();
368
+
369
+ },
370
+
371
+ setStartDate: function(startDate) {
372
+ if (typeof startDate === 'string')
373
+ this.startDate = moment(startDate, this.format);
374
+
375
+ if (typeof startDate === 'object')
376
+ this.startDate = moment(startDate);
377
+
378
+ if (!this.timePicker)
379
+ this.startDate = this.startDate.startOf('day');
380
+
381
+ this.oldStartDate = this.startDate.clone();
382
+
383
+ this.updateView();
384
+ this.updateCalendars();
385
+ },
386
+
387
+ setEndDate: function(endDate) {
388
+ if (typeof endDate === 'string')
389
+ this.endDate = moment(endDate, this.format);
390
+
391
+ if (typeof endDate === 'object')
392
+ this.endDate = moment(endDate);
393
+
394
+ if (!this.timePicker)
395
+ this.endDate = this.endDate.endOf('day');
396
+
397
+ this.oldEndDate = this.endDate.clone();
398
+
399
+ this.updateView();
400
+ this.updateCalendars();
401
+ },
402
+
403
+ updateView: function () {
404
+ this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
405
+ this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
406
+ this.updateFormInputs();
407
+ },
408
+
409
+ updateFormInputs: function () {
410
+ this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format));
411
+ this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format));
412
+
413
+ if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) {
414
+ this.container.find('button.applyBtn').removeAttr('disabled');
415
+ } else {
416
+ this.container.find('button.applyBtn').attr('disabled', 'disabled');
417
+ }
418
+ },
419
+
420
+ updateFromControl: function () {
421
+ if (!this.element.is('input')) return;
422
+ if (!this.element.val().length) return;
423
+
424
+ var dateString = this.element.val().split(this.separator),
425
+ start = null,
426
+ end = null;
427
+
428
+ if(dateString.length === 2) {
429
+ start = moment(dateString[0], this.format);
430
+ end = moment(dateString[1], this.format);
431
+ }
432
+
433
+ if (this.singleDatePicker || start === null || end === null) {
434
+ start = moment(this.element.val(), this.format);
435
+ end = start;
436
+ }
437
+
438
+ if (end.isBefore(start)) return;
439
+
440
+ this.oldStartDate = this.startDate.clone();
441
+ this.oldEndDate = this.endDate.clone();
442
+
443
+ this.startDate = start;
444
+ this.endDate = end;
445
+
446
+ if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
447
+ this.notify();
448
+
449
+ this.updateCalendars();
450
+ },
451
+
452
+ notify: function () {
453
+ this.updateView();
454
+ this.cb(this.startDate, this.endDate, this.chosenLabel);
455
+ },
456
+
457
+ move: function () {
458
+ var parentOffset = { top: 0, left: 0 };
459
+ if (!this.parentEl.is('body')) {
460
+ parentOffset = {
461
+ top: this.parentEl.offset().top - this.parentEl.scrollTop(),
462
+ left: this.parentEl.offset().left - this.parentEl.scrollLeft()
463
+ };
464
+ }
465
+
466
+ if (this.opens == 'left') {
467
+ this.container.css({
468
+ top: this.element.offset().top + this.element.outerHeight() - parentOffset.top,
469
+ right: $(window).width() - this.element.offset().left - this.element.outerWidth() - parentOffset.left,
470
+ left: 'auto'
471
+ });
472
+ if (this.container.offset().left < 0) {
473
+ this.container.css({
474
+ right: 'auto',
475
+ left: 9
476
+ });
477
+ }
478
+ } else {
479
+ this.container.css({
480
+ top: this.element.offset().top + this.element.outerHeight() - parentOffset.top,
481
+ left: this.element.offset().left - parentOffset.left,
482
+ right: 'auto'
483
+ });
484
+ if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
485
+ this.container.css({
486
+ left: 'auto',
487
+ right: 0
488
+ });
489
+ }
490
+ }
491
+ },
492
+
493
+ toggle: function (e) {
494
+ if (this.element.hasClass('active')) {
495
+ this.hide();
496
+ } else {
497
+ this.show();
498
+ }
499
+ },
500
+
501
+ show: function (e) {
502
+ this.element.addClass('active');
503
+ this.container.show();
504
+ this.move();
505
+
506
+ $(document).on('click.daterangepicker', $.proxy(this.outsideClick, this));
507
+ // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them
508
+ $(document).on('click.daterangepicker', '[data-toggle=dropdown]', $.proxy(this.outsideClick, this));
509
+
510
+ this.element.trigger('show.daterangepicker', this);
511
+ },
512
+
513
+ outsideClick: function (e) {
514
+ var target = $(e.target);
515
+ // if the page is clicked anywhere except within the daterangerpicker/button
516
+ // itself then call this.hide()
517
+ if (
518
+ target.closest(this.element).length ||
519
+ target.closest(this.container).length ||
520
+ target.closest('.calendar-date').length
521
+ ) return;
522
+ this.hide();
523
+ },
524
+
525
+ hide: function (e) {
526
+ $(document).off('click.daterangepicker', this.outsideClick);
527
+
528
+ this.element.removeClass('active');
529
+ this.container.hide();
530
+
531
+ if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
532
+ this.notify();
533
+
534
+ this.oldStartDate = this.startDate.clone();
535
+ this.oldEndDate = this.endDate.clone();
536
+
537
+ this.element.trigger('hide.daterangepicker', this);
538
+ },
539
+
540
+ enterRange: function (e) {
541
+ // mouse pointer has entered a range label
542
+ var label = e.target.innerHTML;
543
+ if (label == this.locale.customRangeLabel) {
544
+ this.updateView();
545
+ } else {
546
+ var dates = this.ranges[label];
547
+ this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format));
548
+ this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format));
549
+ }
550
+ },
551
+
552
+ showCalendars: function() {
553
+ this.container.addClass('show-calendar');
554
+ this.move();
555
+ },
556
+
557
+ hideCalendars: function() {
558
+ this.container.removeClass('show-calendar');
559
+ },
560
+
561
+ updateInputText: function() {
562
+ if (this.element.is('input') && !this.singleDatePicker) {
563
+ this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format));
564
+ } else if (this.element.is('input')) {
565
+ this.element.val(this.startDate.format(this.format));
566
+ }
567
+ },
568
+
569
+ clickRange: function (e) {
570
+ var label = e.target.innerHTML;
571
+ this.chosenLabel = label;
572
+ if (label == this.locale.customRangeLabel) {
573
+ this.showCalendars();
574
+ } else {
575
+ var dates = this.ranges[label];
576
+
577
+ this.startDate = dates[0];
578
+ this.endDate = dates[1];
579
+
580
+ if (!this.timePicker) {
581
+ this.startDate.startOf('day');
582
+ this.endDate.endOf('day');
583
+ }
584
+
585
+ this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute());
586
+ this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute());
587
+ this.updateCalendars();
588
+
589
+ this.updateInputText();
590
+
591
+ this.hideCalendars();
592
+ this.hide();
593
+ this.element.trigger('apply.daterangepicker', this);
594
+ }
595
+ },
596
+
597
+ clickPrev: function (e) {
598
+ var cal = $(e.target).parents('.calendar');
599
+ if (cal.hasClass('left')) {
600
+ this.leftCalendar.month.subtract('month', 1);
601
+ } else {
602
+ this.rightCalendar.month.subtract('month', 1);
603
+ }
604
+ this.updateCalendars();
605
+ },
606
+
607
+ clickNext: function (e) {
608
+ var cal = $(e.target).parents('.calendar');
609
+ if (cal.hasClass('left')) {
610
+ this.leftCalendar.month.add('month', 1);
611
+ } else {
612
+ this.rightCalendar.month.add('month', 1);
613
+ }
614
+ this.updateCalendars();
615
+ },
616
+
617
+ enterDate: function (e) {
618
+
619
+ var title = $(e.target).attr('data-title');
620
+ var row = title.substr(1, 1);
621
+ var col = title.substr(3, 1);
622
+ var cal = $(e.target).parents('.calendar');
623
+
624
+ if (cal.hasClass('left')) {
625
+ this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format));
626
+ } else {
627
+ this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format));
628
+ }
629
+
630
+ },
631
+
632
+ clickDate: function (e) {
633
+ var title = $(e.target).attr('data-title');
634
+ var row = title.substr(1, 1);
635
+ var col = title.substr(3, 1);
636
+ var cal = $(e.target).parents('.calendar');
637
+
638
+ var startDate, endDate;
639
+ if (cal.hasClass('left')) {
640
+ startDate = this.leftCalendar.calendar[row][col];
641
+ endDate = this.endDate;
642
+ if (typeof this.dateLimit === 'object') {
643
+ var maxDate = moment(startDate).add(this.dateLimit).startOf('day');
644
+ if (endDate.isAfter(maxDate)) {
645
+ endDate = maxDate;
646
+ }
647
+ }
648
+ } else {
649
+ startDate = this.startDate;
650
+ endDate = this.rightCalendar.calendar[row][col];
651
+ if (typeof this.dateLimit === 'object') {
652
+ var minDate = moment(endDate).subtract(this.dateLimit).startOf('day');
653
+ if (startDate.isBefore(minDate)) {
654
+ startDate = minDate;
655
+ }
656
+ }
657
+ }
658
+
659
+ if (this.singleDatePicker && cal.hasClass('left')) {
660
+ endDate = startDate.clone();
661
+ } else if (this.singleDatePicker && cal.hasClass('right')) {
662
+ startDate = endDate.clone();
663
+ }
664
+
665
+ cal.find('td').removeClass('active');
666
+
667
+ if (startDate.isSame(endDate) || startDate.isBefore(endDate)) {
668
+ $(e.target).addClass('active');
669
+ this.startDate = startDate;
670
+ this.endDate = endDate;
671
+ this.chosenLabel = this.locale.customRangeLabel;
672
+ } else if (startDate.isAfter(endDate)) {
673
+ $(e.target).addClass('active');
674
+ var difference = this.endDate.diff(this.startDate);
675
+ this.startDate = startDate;
676
+ this.endDate = moment(startDate).add('ms', difference);
677
+ this.chosenLabel = this.locale.customRangeLabel;
678
+ }
679
+
680
+ this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year());
681
+ this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year());
682
+ this.updateCalendars();
683
+
684
+ if (!this.timePicker)
685
+ endDate.endOf('day');
686
+
687
+ if (this.singleDatePicker)
688
+ this.clickApply();
689
+ },
690
+
691
+ clickApply: function (e) {
692
+ this.updateInputText();
693
+ this.hide();
694
+ this.element.trigger('apply.daterangepicker', this);
695
+ },
696
+
697
+ clickCancel: function (e) {
698
+ this.startDate = this.oldStartDate;
699
+ this.endDate = this.oldEndDate;
700
+ this.chosenLabel = this.oldChosenLabel;
701
+ this.updateView();
702
+ this.updateCalendars();
703
+ this.hide();
704
+ this.element.trigger('cancel.daterangepicker', this);
705
+ },
706
+
707
+ updateMonthYear: function (e) {
708
+ var isLeft = $(e.target).closest('.calendar').hasClass('left'),
709
+ leftOrRight = isLeft ? 'left' : 'right',
710
+ cal = this.container.find('.calendar.'+leftOrRight);
711
+
712
+ // Month must be Number for new moment versions
713
+ var month = parseInt(cal.find('.monthselect').val(), 10);
714
+ var year = cal.find('.yearselect').val();
715
+
716
+ this[leftOrRight+'Calendar'].month.month(month).year(year);
717
+ this.updateCalendars();
718
+ },
719
+
720
+ updateTime: function(e) {
721
+ var isLeft = $(e.target).closest('.calendar').hasClass('left'),
722
+ leftOrRight = isLeft ? 'left' : 'right',
723
+ cal = this.container.find('.calendar.'+leftOrRight);
724
+
725
+ var hour = parseInt(cal.find('.hourselect').val(), 10);
726
+ var minute = parseInt(cal.find('.minuteselect').val(), 10);
727
+
728
+ if (this.timePicker12Hour) {
729
+ var ampm = cal.find('.ampmselect').val();
730
+ if (ampm === 'PM' && hour < 12)
731
+ hour += 12;
732
+ if (ampm === 'AM' && hour === 12)
733
+ hour = 0;
734
+ }
735
+
736
+ if (isLeft) {
737
+ var start = this.startDate.clone();
738
+ start.hour(hour);
739
+ start.minute(minute);
740
+ this.startDate = start;
741
+ this.leftCalendar.month.hour(hour).minute(minute);
742
+ } else {
743
+ var end = this.endDate.clone();
744
+ end.hour(hour);
745
+ end.minute(minute);
746
+ this.endDate = end;
747
+ this.rightCalendar.month.hour(hour).minute(minute);
748
+ }
749
+
750
+ this.updateCalendars();
751
+ },
752
+
753
+ updateCalendars: function () {
754
+ this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), 'left');
755
+ this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), 'right');
756
+ this.container.find('.calendar.left').empty().html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate));
757
+ this.container.find('.calendar.right').empty().html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate));
758
+
759
+ this.container.find('.ranges li').removeClass('active');
760
+ var customRange = true;
761
+ var i = 0;
762
+ for (var range in this.ranges) {
763
+ if (this.timePicker) {
764
+ if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {
765
+ customRange = false;
766
+ this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')
767
+ .addClass('active').html();
768
+ }
769
+ } else {
770
+ //ignore times when comparing dates if time picker is not enabled
771
+ 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')) {
772
+ customRange = false;
773
+ this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')')
774
+ .addClass('active').html();
775
+ }
776
+ }
777
+ i++;
778
+ }
779
+ if (customRange) {
780
+ this.chosenLabel = this.container.find('.ranges li:last')
781
+ .addClass('active').html();
782
+ }
783
+ },
784
+
785
+ buildCalendar: function (month, year, hour, minute, side) {
786
+ var firstDay = moment([year, month, 1]);
787
+ var lastMonth = moment(firstDay).subtract('month', 1).month();
788
+ var lastYear = moment(firstDay).subtract('month', 1).year();
789
+
790
+ var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
791
+
792
+ var dayOfWeek = firstDay.day();
793
+
794
+ var i;
795
+
796
+ //initialize a 6 rows x 7 columns array for the calendar
797
+ var calendar = [];
798
+ for (i = 0; i < 6; i++) {
799
+ calendar[i] = [];
800
+ }
801
+
802
+ //populate the calendar with date objects
803
+ var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;
804
+ if (startDay > daysInLastMonth)
805
+ startDay -= 7;
806
+
807
+ if (dayOfWeek == this.locale.firstDay)
808
+ startDay = daysInLastMonth - 6;
809
+
810
+ var curDate = moment([lastYear, lastMonth, startDay, 12, minute]);
811
+ var col, row;
812
+ for (i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('hour', 24)) {
813
+ if (i > 0 && col % 7 === 0) {
814
+ col = 0;
815
+ row++;
816
+ }
817
+ calendar[row][col] = curDate.clone().hour(hour);
818
+ curDate.hour(12);
819
+ }
820
+
821
+ return calendar;
822
+ },
823
+
824
+ renderDropdowns: function (selected, minDate, maxDate) {
825
+ var currentMonth = selected.month();
826
+ var monthHtml = '<select class="monthselect">';
827
+ var inMinYear = false;
828
+ var inMaxYear = false;
829
+
830
+ for (var m = 0; m < 12; m++) {
831
+ if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
832
+ monthHtml += "<option value='" + m + "'" +
833
+ (m === currentMonth ? " selected='selected'" : "") +
834
+ ">" + this.locale.monthNames[m] + "</option>";
835
+ }
836
+ }
837
+ monthHtml += "</select>";
838
+
839
+ var currentYear = selected.year();
840
+ var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);
841
+ var minYear = (minDate && minDate.year()) || (currentYear - 50);
842
+ var yearHtml = '<select class="yearselect">';
843
+
844
+ for (var y = minYear; y <= maxYear; y++) {
845
+ yearHtml += '<option value="' + y + '"' +
846
+ (y === currentYear ? ' selected="selected"' : '') +
847
+ '>' + y + '</option>';
848
+ }
849
+
850
+ yearHtml += '</select>';
851
+
852
+ return monthHtml + yearHtml;
853
+ },
854
+
855
+ renderCalendar: function (calendar, selected, minDate, maxDate) {
856
+
857
+ var html = '<div class="calendar-date">';
858
+ html += '<table class="table-condensed">';
859
+ html += '<thead>';
860
+ html += '<tr>';
861
+
862
+ // add empty cell for week number
863
+ if (this.showWeekNumbers)
864
+ html += '<th></th>';
865
+
866
+ if (!minDate || minDate.isBefore(calendar[1][1])) {
867
+ html += '<th class="prev available"><i class="fa fa-arrow-left icon-arrow-left glyphicon glyphicon-arrow-left"></i></th>';
868
+ } else {
869
+ html += '<th></th>';
870
+ }
871
+
872
+ var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");
873
+
874
+ if (this.showDropdowns) {
875
+ dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate);
876
+ }
877
+
878
+ html += '<th colspan="5" class="month">' + dateHtml + '</th>';
879
+ if (!maxDate || maxDate.isAfter(calendar[1][1])) {
880
+ html += '<th class="next available"><i class="fa fa-arrow-right icon-arrow-right glyphicon glyphicon-arrow-right"></i></th>';
881
+ } else {
882
+ html += '<th></th>';
883
+ }
884
+
885
+ html += '</tr>';
886
+ html += '<tr>';
887
+
888
+ // add week number label
889
+ if (this.showWeekNumbers)
890
+ html += '<th class="week">' + this.locale.weekLabel + '</th>';
891
+
892
+ $.each(this.locale.daysOfWeek, function (index, dayOfWeek) {
893
+ html += '<th>' + dayOfWeek + '</th>';
894
+ });
895
+
896
+ html += '</tr>';
897
+ html += '</thead>';
898
+ html += '<tbody>';
899
+
900
+ for (var row = 0; row < 6; row++) {
901
+ html += '<tr>';
902
+
903
+ // add week number
904
+ if (this.showWeekNumbers)
905
+ html += '<td class="week">' + calendar[row][0].week() + '</td>';
906
+
907
+ for (var col = 0; col < 7; col++) {
908
+ var cname = 'available ';
909
+ cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off';
910
+
911
+ if ((minDate && calendar[row][col].isBefore(minDate)) || (maxDate && calendar[row][col].isAfter(maxDate))) {
912
+ cname = ' off disabled ';
913
+ } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) {
914
+ cname += ' active ';
915
+ if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) {
916
+ cname += ' start-date ';
917
+ }
918
+ if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) {
919
+ cname += ' end-date ';
920
+ }
921
+ } else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) {
922
+ cname += ' in-range ';
923
+ if (calendar[row][col].isSame(this.startDate)) { cname += ' start-date '; }
924
+ if (calendar[row][col].isSame(this.endDate)) { cname += ' end-date '; }
925
+ }
926
+
927
+ var title = 'r' + row + 'c' + col;
928
+ html += '<td class="' + cname.replace(/\s+/g, ' ').replace(/^\s?(.*?)\s?$/, '$1') + '" data-title="' + title + '">' + calendar[row][col].date() + '</td>';
929
+ }
930
+ html += '</tr>';
931
+ }
932
+
933
+ html += '</tbody>';
934
+ html += '</table>';
935
+ html += '</div>';
936
+
937
+ var i;
938
+ if (this.timePicker) {
939
+
940
+ html += '<div class="calendar-time">';
941
+ html += '<select class="hourselect">';
942
+ var start = 0;
943
+ var end = 23;
944
+ var selected_hour = selected.hour();
945
+ if (this.timePicker12Hour) {
946
+ start = 1;
947
+ end = 12;
948
+ if (selected_hour >= 12)
949
+ selected_hour -= 12;
950
+ if (selected_hour === 0)
951
+ selected_hour = 12;
952
+ }
953
+
954
+ for (i = start; i <= end; i++) {
955
+ if (i == selected_hour) {
956
+ html += '<option value="' + i + '" selected="selected">' + i + '</option>';
957
+ } else {
958
+ html += '<option value="' + i + '">' + i + '</option>';
959
+ }
960
+ }
961
+
962
+ html += '</select> : ';
963
+
964
+ html += '<select class="minuteselect">';
965
+
966
+ for (i = 0; i < 60; i += this.timePickerIncrement) {
967
+ var num = i;
968
+ if (num < 10)
969
+ num = '0' + num;
970
+ if (i == selected.minute()) {
971
+ html += '<option value="' + i + '" selected="selected">' + num + '</option>';
972
+ } else {
973
+ html += '<option value="' + i + '">' + num + '</option>';
974
+ }
975
+ }
976
+
977
+ html += '</select> ';
978
+
979
+ if (this.timePicker12Hour) {
980
+ html += '<select class="ampmselect">';
981
+ if (selected.hour() >= 12) {
982
+ html += '<option value="AM">AM</option><option value="PM" selected="selected">PM</option>';
983
+ } else {
984
+ html += '<option value="AM" selected="selected">AM</option><option value="PM">PM</option>';
985
+ }
986
+ html += '</select>';
987
+ }
988
+
989
+ html += '</div>';
990
+
991
+ }
992
+
993
+ return html;
994
+
995
+ },
996
+
997
+ remove: function() {
998
+
999
+ this.container.remove();
1000
+ this.element.off('.daterangepicker');
1001
+ this.element.removeData('daterangepicker');
1002
+
1003
+ }
1004
+
1005
+ };
1006
+
1007
+ $.fn.daterangepicker = function (options, cb) {
1008
+ this.each(function () {
1009
+ var el = $(this);
1010
+ if (el.data('daterangepicker'))
1011
+ el.data('daterangepicker').remove();
1012
+ el.data('daterangepicker', new DateRangePicker(el, options, cb));
1013
+ });
1014
+ return this;
1015
+ };
1016
+
1017
+ }(window.jQuery, window.moment);