effective_form_inputs 0.6.3 → 0.6.4

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.
@@ -1,9 +1,11 @@
1
- /*
2
- //! version : 4.0.0
1
+ /*! version : 4.15.35
3
2
  =========================================================
4
3
  bootstrap-datetimejs
5
4
  https://github.com/Eonasdan/bootstrap-datetimepicker
5
+ Copyright (c) 2015 Jonathan Peterson
6
6
  =========================================================
7
+ */
8
+ /*
7
9
  The MIT License (MIT)
8
10
 
9
11
  Copyright (c) 2015 Jonathan Peterson
@@ -26,6 +28,11 @@
26
28
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
29
  THE SOFTWARE.
28
30
  */
31
+ /*global define:false */
32
+ /*global exports:false */
33
+ /*global require:false */
34
+ /*global jQuery:false */
35
+ /*global moment:false */
29
36
  (function (factory) {
30
37
  'use strict';
31
38
  if (typeof define === 'function' && define.amd) {
@@ -35,10 +42,10 @@
35
42
  factory(require('jquery'), require('moment'));
36
43
  } else {
37
44
  // Neither AMD nor CommonJS used. Use global variables.
38
- if (!jQuery) {
45
+ if (typeof jQuery === 'undefined') {
39
46
  throw 'bootstrap-datetimepicker requires jQuery to be loaded first';
40
47
  }
41
- if (!moment) {
48
+ if (typeof moment === 'undefined') {
42
49
  throw 'bootstrap-datetimepicker requires Moment.js to be loaded first';
43
50
  }
44
51
  factory(jQuery, moment);
@@ -51,7 +58,7 @@
51
58
 
52
59
  var dateTimePicker = function (element, options) {
53
60
  var picker = {},
54
- date = moment(),
61
+ date = moment().startOf('d'),
55
62
  viewDate = date.clone(),
56
63
  unset = true,
57
64
  input,
@@ -77,12 +84,48 @@
77
84
  clsName: 'years',
78
85
  navFnc: 'y',
79
86
  navStep: 10
87
+ },
88
+ {
89
+ clsName: 'decades',
90
+ navFnc: 'y',
91
+ navStep: 100
80
92
  }
81
93
  ],
82
- viewModes = ['days', 'months', 'years'],
94
+ viewModes = ['days', 'months', 'years', 'decades'],
83
95
  verticalModes = ['top', 'bottom', 'auto'],
84
96
  horizontalModes = ['left', 'right', 'auto'],
85
97
  toolbarPlacements = ['default', 'top', 'bottom'],
98
+ keyMap = {
99
+ 'up': 38,
100
+ 38: 'up',
101
+ 'down': 40,
102
+ 40: 'down',
103
+ 'left': 37,
104
+ 37: 'left',
105
+ 'right': 39,
106
+ 39: 'right',
107
+ 'tab': 9,
108
+ 9: 'tab',
109
+ 'escape': 27,
110
+ 27: 'escape',
111
+ 'enter': 13,
112
+ 13: 'enter',
113
+ 'pageUp': 33,
114
+ 33: 'pageUp',
115
+ 'pageDown': 34,
116
+ 34: 'pageDown',
117
+ 'shift': 16,
118
+ 16: 'shift',
119
+ 'control': 17,
120
+ 17: 'control',
121
+ 'space': 32,
122
+ 32: 'space',
123
+ 't': 84,
124
+ 84: 't',
125
+ 'delete': 46,
126
+ 46: 'delete'
127
+ },
128
+ keyState = {},
86
129
 
87
130
  /********************************************************************************
88
131
  *
@@ -111,7 +154,6 @@
111
154
  return false;
112
155
  }
113
156
  },
114
-
115
157
  hasTime = function () {
116
158
  return (isEnabled('h') || isEnabled('m') || isEnabled('s'));
117
159
  },
@@ -148,6 +190,11 @@
148
190
  .append(contTemplate.clone())
149
191
  ),
150
192
  $('<div>').addClass('datepicker-years')
193
+ .append($('<table>').addClass('table-condensed')
194
+ .append(headTemplate.clone())
195
+ .append(contTemplate.clone())
196
+ ),
197
+ $('<div>').addClass('datepicker-decades')
151
198
  .append($('<table>').addClass('table-condensed')
152
199
  .append(headTemplate.clone())
153
200
  .append(contTemplate.clone())
@@ -162,12 +209,12 @@
162
209
 
163
210
  if (isEnabled('h')) {
164
211
  topRow.append($('<td>')
165
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementHours')
212
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Increment Hour'}).addClass('btn').attr('data-action', 'incrementHours')
166
213
  .append($('<span>').addClass(options.icons.up))));
167
214
  middleRow.append($('<td>')
168
- .append($('<span>').addClass('timepicker-hour').attr('data-time-component', 'hours').attr('data-action', 'showHours')));
215
+ .append($('<span>').addClass('timepicker-hour').attr({'data-time-component':'hours', 'title':'Pick Hour'}).attr('data-action', 'showHours')));
169
216
  bottomRow.append($('<td>')
170
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementHours')
217
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Decrement Hour'}).addClass('btn').attr('data-action', 'decrementHours')
171
218
  .append($('<span>').addClass(options.icons.down))));
172
219
  }
173
220
  if (isEnabled('m')) {
@@ -177,12 +224,12 @@
177
224
  bottomRow.append($('<td>').addClass('separator'));
178
225
  }
179
226
  topRow.append($('<td>')
180
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementMinutes')
227
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Increment Minute'}).addClass('btn').attr('data-action', 'incrementMinutes')
181
228
  .append($('<span>').addClass(options.icons.up))));
182
229
  middleRow.append($('<td>')
183
- .append($('<span>').addClass('timepicker-minute').attr('data-time-component', 'minutes').attr('data-action', 'showMinutes')));
230
+ .append($('<span>').addClass('timepicker-minute').attr({'data-time-component': 'minutes', 'title':'Pick Minute'}).attr('data-action', 'showMinutes')));
184
231
  bottomRow.append($('<td>')
185
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementMinutes')
232
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Decrement Minute'}).addClass('btn').attr('data-action', 'decrementMinutes')
186
233
  .append($('<span>').addClass(options.icons.down))));
187
234
  }
188
235
  if (isEnabled('s')) {
@@ -192,19 +239,19 @@
192
239
  bottomRow.append($('<td>').addClass('separator'));
193
240
  }
194
241
  topRow.append($('<td>')
195
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementSeconds')
242
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Increment Second'}).addClass('btn').attr('data-action', 'incrementSeconds')
196
243
  .append($('<span>').addClass(options.icons.up))));
197
244
  middleRow.append($('<td>')
198
- .append($('<span>').addClass('timepicker-second').attr('data-time-component', 'seconds').attr('data-action', 'showSeconds')));
245
+ .append($('<span>').addClass('timepicker-second').attr({'data-time-component': 'seconds', 'title':'Pick Second'}).attr('data-action', 'showSeconds')));
199
246
  bottomRow.append($('<td>')
200
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementSeconds')
247
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title':'Decrement Second'}).addClass('btn').attr('data-action', 'decrementSeconds')
201
248
  .append($('<span>').addClass(options.icons.down))));
202
249
  }
203
250
 
204
251
  if (!use24Hours) {
205
252
  topRow.append($('<td>').addClass('separator'));
206
253
  middleRow.append($('<td>')
207
- .append($('<button>').addClass('btn btn-primary').attr('data-action', 'togglePeriod')));
254
+ .append($('<button>').addClass('btn btn-primary').attr({'data-action': 'togglePeriod', tabindex: '-1', 'title':'Toggle Period'})));
208
255
  bottomRow.append($('<td>').addClass('separator'));
209
256
  }
210
257
 
@@ -238,13 +285,16 @@
238
285
  getToolbar = function () {
239
286
  var row = [];
240
287
  if (options.showTodayButton) {
241
- row.push($('<td>').append($('<a>').attr('data-action', 'today').append($('<span>').addClass(options.icons.today))));
288
+ row.push($('<td>').append($('<a>').attr({'data-action':'today', 'title': options.tooltips.today}).append($('<span>').addClass(options.icons.today))));
242
289
  }
243
290
  if (!options.sideBySide && hasDate() && hasTime()) {
244
- row.push($('<td>').append($('<a>').attr('data-action', 'togglePicker').append($('<span>').addClass(options.icons.time))));
291
+ row.push($('<td>').append($('<a>').attr({'data-action':'togglePicker', 'title':'Select Time'}).append($('<span>').addClass(options.icons.time))));
245
292
  }
246
293
  if (options.showClear) {
247
- row.push($('<td>').append($('<a>').attr('data-action', 'clear').append($('<span>').addClass(options.icons.clear))));
294
+ row.push($('<td>').append($('<a>').attr({'data-action':'clear', 'title': options.tooltips.clear}).append($('<span>').addClass(options.icons.clear))));
295
+ }
296
+ if (options.showClose) {
297
+ row.push($('<td>').append($('<a>').attr({'data-action':'close', 'title': options.tooltips.close}).append($('<span>').addClass(options.icons.close))));
248
298
  }
249
299
  return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row)));
250
300
  },
@@ -256,17 +306,30 @@
256
306
  content = $('<ul>').addClass('list-unstyled'),
257
307
  toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar());
258
308
 
309
+ if (options.inline) {
310
+ template.removeClass('dropdown-menu');
311
+ }
312
+
259
313
  if (use24Hours) {
260
314
  template.addClass('usetwentyfour');
261
315
  }
316
+ if (isEnabled('s') && !use24Hours) {
317
+ template.addClass('wider');
318
+ }
319
+
262
320
  if (options.sideBySide && hasDate() && hasTime()) {
263
321
  template.addClass('timepicker-sbs');
322
+ if (options.toolbarPlacement === 'top') {
323
+ template.append(toolbar);
324
+ }
264
325
  template.append(
265
326
  $('<div>').addClass('row')
266
- .append(dateView.addClass('col-sm-6'))
267
- .append(timeView.addClass('col-sm-6'))
327
+ .append(dateView.addClass('col-md-6'))
328
+ .append(timeView.addClass('col-md-6'))
268
329
  );
269
- template.append(toolbar);
330
+ if (options.toolbarPlacement === 'bottom') {
331
+ template.append(toolbar);
332
+ }
270
333
  return template;
271
334
  }
272
335
 
@@ -289,9 +352,15 @@
289
352
  },
290
353
 
291
354
  dataToOptions = function () {
292
- var eData = element.data(),
355
+ var eData,
293
356
  dataOptions = {};
294
357
 
358
+ if (element.is('input') || options.inline) {
359
+ eData = element.data();
360
+ } else {
361
+ eData = element.find('input').data();
362
+ }
363
+
295
364
  if (eData.dateOptions && eData.dateOptions instanceof Object) {
296
365
  dataOptions = $.extend(true, dataOptions, eData.dateOptions);
297
366
  }
@@ -306,7 +375,8 @@
306
375
  },
307
376
 
308
377
  place = function () {
309
- var offset = (component || element).position(),
378
+ var position = (component || element).position(),
379
+ offset = (component || element).offset(),
310
380
  vertical = options.widgetPositioning.vertical,
311
381
  horizontal = options.widgetPositioning.horizontal,
312
382
  parent;
@@ -314,7 +384,10 @@
314
384
  if (options.widgetParent) {
315
385
  parent = options.widgetParent.append(widget);
316
386
  } else if (element.is('input')) {
317
- parent = element.parent().append(widget);
387
+ parent = element.after(widget).parent();
388
+ } else if (options.inline) {
389
+ parent = element.append(widget);
390
+ return;
318
391
  } else {
319
392
  parent = element;
320
393
  element.children().first().after(widget);
@@ -322,8 +395,8 @@
322
395
 
323
396
  // Top and bottom logic
324
397
  if (vertical === 'auto') {
325
- if ((component || element).offset().top + widget.height() > $(window).height() + $(window).scrollTop() &&
326
- widget.height() + element.outerHeight() < (component || element).offset().top) {
398
+ if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() &&
399
+ widget.height() + element.outerHeight() < offset.top) {
327
400
  vertical = 'top';
328
401
  } else {
329
402
  vertical = 'bottom';
@@ -332,7 +405,8 @@
332
405
 
333
406
  // Left and right logic
334
407
  if (horizontal === 'auto') {
335
- if (parent.width() < offset.left + widget.outerWidth()) {
408
+ if (parent.width() < offset.left + widget.outerWidth() / 2 &&
409
+ offset.left + widget.outerWidth() > $(window).width()) {
336
410
  horizontal = 'right';
337
411
  } else {
338
412
  horizontal = 'left';
@@ -363,10 +437,10 @@
363
437
  }
364
438
 
365
439
  widget.css({
366
- top: vertical === 'top' ? 'auto' : offset.top + element.outerHeight(),
367
- bottom: vertical === 'top' ? offset.top + element.outerHeight() : 'auto',
368
- left: horizontal === 'left' ? parent.css('padding-left') : 'auto',
369
- right: horizontal === 'left' ? 'auto' : parent.css('padding-right')
440
+ top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(),
441
+ bottom: vertical === 'top' ? position.top + element.outerHeight() : 'auto',
442
+ left: horizontal === 'left' ? (parent === element ? 0 : position.left) : 'auto',
443
+ right: horizontal === 'left' ? 'auto' : parent.outerWidth() - element.outerWidth() - (parent === element ? 0 : position.left)
370
444
  });
371
445
  },
372
446
 
@@ -377,19 +451,30 @@
377
451
  element.trigger(e);
378
452
  },
379
453
 
454
+ viewUpdate = function (e) {
455
+ if (e === 'y') {
456
+ e = 'YYYY';
457
+ }
458
+ notifyEvent({
459
+ type: 'dp.update',
460
+ change: e,
461
+ viewDate: viewDate.clone()
462
+ });
463
+ },
464
+
380
465
  showMode = function (dir) {
381
466
  if (!widget) {
382
467
  return;
383
468
  }
384
469
  if (dir) {
385
- currentViewMode = Math.max(minViewModeNumber, Math.min(2, currentViewMode + dir));
470
+ currentViewMode = Math.max(minViewModeNumber, Math.min(3, currentViewMode + dir));
386
471
  }
387
472
  widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show();
388
473
  },
389
474
 
390
475
  fillDow = function () {
391
476
  var row = $('<tr>'),
392
- currentDate = viewDate.clone().startOf('w');
477
+ currentDate = viewDate.clone().startOf('w').startOf('d');
393
478
 
394
479
  if (options.calendarWeeks === true) {
395
480
  row.append($('<th>').addClass('cw').text('#'));
@@ -402,29 +487,31 @@
402
487
  widget.find('.datepicker-days thead').append(row);
403
488
  },
404
489
 
405
- isInDisabledDates = function (date) {
406
- if (!options.disabledDates) {
407
- return false;
408
- }
409
- return options.disabledDates[date.format('YYYY-MM-DD')] === true;
490
+ isInDisabledDates = function (testDate) {
491
+ return options.disabledDates[testDate.format('YYYY-MM-DD')] === true;
410
492
  },
411
493
 
412
- isInEnabledDates = function (date) {
413
- if (!options.enabledDates) {
414
- return false;
415
- }
416
- return options.enabledDates[date.format('YYYY-MM-DD')] === true;
494
+ isInEnabledDates = function (testDate) {
495
+ return options.enabledDates[testDate.format('YYYY-MM-DD')] === true;
496
+ },
497
+
498
+ isInDisabledHours = function (testDate) {
499
+ return options.disabledHours[testDate.format('H')] === true;
500
+ },
501
+
502
+ isInEnabledHours = function (testDate) {
503
+ return options.enabledHours[testDate.format('H')] === true;
417
504
  },
418
505
 
419
506
  isValid = function (targetMoment, granularity) {
420
507
  if (!targetMoment.isValid()) {
421
508
  return false;
422
509
  }
423
- if (options.disabledDates && isInDisabledDates(targetMoment)) {
510
+ if (options.disabledDates && granularity === 'd' && isInDisabledDates(targetMoment)) {
424
511
  return false;
425
512
  }
426
- if (options.enabledDates && isInEnabledDates(targetMoment)) {
427
- return true;
513
+ if (options.enabledDates && granularity === 'd' && !isInEnabledDates(targetMoment)) {
514
+ return false;
428
515
  }
429
516
  if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) {
430
517
  return false;
@@ -432,15 +519,33 @@
432
519
  if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) {
433
520
  return false;
434
521
  }
435
- if (granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
522
+ if (options.daysOfWeekDisabled && granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
523
+ return false;
524
+ }
525
+ if (options.disabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && isInDisabledHours(targetMoment)) {
526
+ return false;
527
+ }
528
+ if (options.enabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && !isInEnabledHours(targetMoment)) {
436
529
  return false;
437
530
  }
531
+ if (options.disabledTimeIntervals && (granularity === 'h' || granularity === 'm' || granularity === 's')) {
532
+ var found = false;
533
+ $.each(options.disabledTimeIntervals, function () {
534
+ if (targetMoment.isBetween(this[0], this[1])) {
535
+ found = true;
536
+ return false;
537
+ }
538
+ });
539
+ if (found) {
540
+ return false;
541
+ }
542
+ }
438
543
  return true;
439
544
  },
440
545
 
441
546
  fillMonths = function () {
442
547
  var spans = [],
443
- monthsShort = viewDate.clone().startOf('y').hour(12); // hour is changed to avoid DST issues in some browsers
548
+ monthsShort = viewDate.clone().startOf('y').startOf('d');
444
549
  while (monthsShort.isSame(viewDate, 'y')) {
445
550
  spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM')));
446
551
  monthsShort.add(1, 'M');
@@ -453,6 +558,10 @@
453
558
  monthsViewHeader = monthsView.find('th'),
454
559
  months = monthsView.find('tbody').find('span');
455
560
 
561
+ monthsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevYear);
562
+ monthsViewHeader.eq(1).attr('title', options.tooltips.selectYear);
563
+ monthsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextYear);
564
+
456
565
  monthsView.find('.disabled').removeClass('disabled');
457
566
 
458
567
  if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) {
@@ -466,7 +575,7 @@
466
575
  }
467
576
 
468
577
  months.removeClass('active');
469
- if (date.isSame(viewDate, 'y')) {
578
+ if (date.isSame(viewDate, 'y') && !unset) {
470
579
  months.eq(date.month()).addClass('active');
471
580
  }
472
581
 
@@ -484,6 +593,10 @@
484
593
  endYear = viewDate.clone().add(6, 'y'),
485
594
  html = '';
486
595
 
596
+ yearsViewHeader.eq(0).find('span').attr('title', options.tooltips.nextDecade);
597
+ yearsViewHeader.eq(1).attr('title', options.tooltips.selectDecade);
598
+ yearsViewHeader.eq(2).find('span').attr('title', options.tooltips.prevDecade);
599
+
487
600
  yearsView.find('.disabled').removeClass('disabled');
488
601
 
489
602
  if (options.minDate && options.minDate.isAfter(startYear, 'y')) {
@@ -497,25 +610,62 @@
497
610
  }
498
611
 
499
612
  while (!startYear.isAfter(endYear, 'y')) {
500
- html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>';
613
+ html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') && !unset ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>';
501
614
  startYear.add(1, 'y');
502
615
  }
503
616
 
504
617
  yearsView.find('td').html(html);
505
618
  },
506
619
 
620
+ updateDecades = function () {
621
+ var decadesView = widget.find('.datepicker-decades'),
622
+ decadesViewHeader = decadesView.find('th'),
623
+ startDecade = viewDate.isBefore(moment({y: 1999})) ? moment({y: 1899}) : moment({y: 1999}),
624
+ endDecade = startDecade.clone().add(100, 'y'),
625
+ html = '';
626
+
627
+ decadesViewHeader.eq(0).find('span').attr('title', options.tooltips.prevCentury);
628
+ decadesViewHeader.eq(2).find('span').attr('title', options.tooltips.nextCentury);
629
+
630
+ decadesView.find('.disabled').removeClass('disabled');
631
+
632
+ if (startDecade.isSame(moment({y: 1900})) || (options.minDate && options.minDate.isAfter(startDecade, 'y'))) {
633
+ decadesViewHeader.eq(0).addClass('disabled');
634
+ }
635
+
636
+ decadesViewHeader.eq(1).text(startDecade.year() + '-' + endDecade.year());
637
+
638
+ if (startDecade.isSame(moment({y: 2000})) || (options.maxDate && options.maxDate.isBefore(endDecade, 'y'))) {
639
+ decadesViewHeader.eq(2).addClass('disabled');
640
+ }
641
+
642
+ while (!startDecade.isAfter(endDecade, 'y')) {
643
+ html += '<span data-action="selectDecade" class="decade' + (startDecade.isSame(date, 'y') ? ' active' : '') +
644
+ (!isValid(startDecade, 'y') ? ' disabled' : '') + '" data-selection="' + (startDecade.year() + 6) + '">' + (startDecade.year() + 1) + ' - ' + (startDecade.year() + 12) + '</span>';
645
+ startDecade.add(12, 'y');
646
+ }
647
+ html += '<span></span><span></span><span></span>'; //push the dangling block over, at least this way it's even
648
+
649
+ decadesView.find('td').html(html);
650
+ },
651
+
507
652
  fillDate = function () {
508
653
  var daysView = widget.find('.datepicker-days'),
509
654
  daysViewHeader = daysView.find('th'),
510
655
  currentDate,
511
656
  html = [],
512
657
  row,
513
- clsName;
658
+ clsName,
659
+ i;
514
660
 
515
661
  if (!hasDate()) {
516
662
  return;
517
663
  }
518
664
 
665
+ daysViewHeader.eq(0).find('span').attr('title', options.tooltips.prevMonth);
666
+ daysViewHeader.eq(1).attr('title', options.tooltips.selectMonth);
667
+ daysViewHeader.eq(2).find('span').attr('title', options.tooltips.nextMonth);
668
+
519
669
  daysView.find('.disabled').removeClass('disabled');
520
670
  daysViewHeader.eq(1).text(viewDate.format(options.dayViewHeaderFormat));
521
671
 
@@ -526,9 +676,9 @@
526
676
  daysViewHeader.eq(2).addClass('disabled');
527
677
  }
528
678
 
529
- currentDate = viewDate.clone().startOf('M').startOf('week');
679
+ currentDate = viewDate.clone().startOf('M').startOf('w').startOf('d');
530
680
 
531
- while (!viewDate.clone().endOf('M').endOf('w').isBefore(currentDate, 'd')) {
681
+ for (i = 0; i < 42; i++) { //always display 42 days (should show 6 weeks)
532
682
  if (currentDate.weekday() === 0) {
533
683
  row = $('<tr>');
534
684
  if (options.calendarWeeks) {
@@ -555,7 +705,7 @@
555
705
  if (currentDate.day() === 0 || currentDate.day() === 6) {
556
706
  clsName += ' weekend';
557
707
  }
558
- row.append('<td data-action="selectDay" class="day' + clsName + '">' + currentDate.date() + '</td>');
708
+ row.append('<td data-action="selectDay" data-day="' + currentDate.format('L') + '" class="day' + clsName + '">' + currentDate.date() + '</td>');
559
709
  currentDate.add(1, 'd');
560
710
  }
561
711
 
@@ -564,6 +714,8 @@
564
714
  updateMonths();
565
715
 
566
716
  updateYears();
717
+
718
+ updateDecades();
567
719
  },
568
720
 
569
721
  fillHours = function () {
@@ -623,9 +775,19 @@
623
775
  },
624
776
 
625
777
  fillTime = function () {
626
- var timeComponents = widget.find('.timepicker span[data-time-component]');
778
+ var toggle, newDate, timeComponents = widget.find('.timepicker span[data-time-component]');
779
+
627
780
  if (!use24Hours) {
628
- widget.find('.timepicker [data-action=togglePeriod]').text(date.format('A'));
781
+ toggle = widget.find('.timepicker [data-action=togglePeriod]');
782
+ newDate = date.clone().add((date.hours() >= 12) ? -12 : 12, 'h');
783
+
784
+ toggle.text(date.format('A'));
785
+
786
+ if (isValid(newDate, 'h')) {
787
+ toggle.removeClass('disabled');
788
+ } else {
789
+ toggle.addClass('disabled');
790
+ }
629
791
  }
630
792
  timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh'));
631
793
  timeComponents.filter('[data-time-component=minutes]').text(date.format('mm'));
@@ -654,7 +816,7 @@
654
816
  element.data('date', '');
655
817
  notifyEvent({
656
818
  type: 'dp.change',
657
- date: null,
819
+ date: false,
658
820
  oldDate: oldDate
659
821
  });
660
822
  update();
@@ -672,15 +834,17 @@
672
834
  viewDate = date.clone();
673
835
  input.val(date.format(actualFormat));
674
836
  element.data('date', date.format(actualFormat));
675
- update();
676
837
  unset = false;
838
+ update();
677
839
  notifyEvent({
678
840
  type: 'dp.change',
679
841
  date: date.clone(),
680
842
  oldDate: oldDate
681
843
  });
682
844
  } else {
683
- input.val(unset ? '' : date.format(actualFormat));
845
+ if (!options.keepInvalid) {
846
+ input.val(unset ? '' : date.format(actualFormat));
847
+ }
684
848
  notifyEvent({
685
849
  type: 'dp.error',
686
850
  date: targetMoment
@@ -689,6 +853,7 @@
689
853
  },
690
854
 
691
855
  hide = function () {
856
+ ///<summary>Hides the widget. Possibly will emit dp.hide</summary>
692
857
  var transitioning = false;
693
858
  if (!widget) {
694
859
  return picker;
@@ -700,6 +865,7 @@
700
865
  transitioning = true;
701
866
  return false;
702
867
  }
868
+ return true;
703
869
  });
704
870
  if (transitioning) {
705
871
  return picker;
@@ -720,9 +886,16 @@
720
886
  type: 'dp.hide',
721
887
  date: date.clone()
722
888
  });
889
+
890
+ input.blur();
891
+
723
892
  return picker;
724
893
  },
725
894
 
895
+ clear = function () {
896
+ setValue(null);
897
+ },
898
+
726
899
  /********************************************************************************
727
900
  *
728
901
  * Widget UI interaction functions
@@ -730,13 +903,17 @@
730
903
  ********************************************************************************/
731
904
  actions = {
732
905
  next: function () {
733
- viewDate.add(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc);
906
+ var navFnc = datePickerModes[currentViewMode].navFnc;
907
+ viewDate.add(datePickerModes[currentViewMode].navStep, navFnc);
734
908
  fillDate();
909
+ viewUpdate(navFnc);
735
910
  },
736
911
 
737
912
  previous: function () {
738
- viewDate.subtract(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc);
913
+ var navFnc = datePickerModes[currentViewMode].navFnc;
914
+ viewDate.subtract(datePickerModes[currentViewMode].navStep, navFnc);
739
915
  fillDate();
916
+ viewUpdate(navFnc);
740
917
  },
741
918
 
742
919
  pickerSwitch: function () {
@@ -748,10 +925,14 @@
748
925
  viewDate.month(month);
749
926
  if (currentViewMode === minViewModeNumber) {
750
927
  setValue(date.clone().year(viewDate.year()).month(viewDate.month()));
751
- hide();
928
+ if (!options.inline) {
929
+ hide();
930
+ }
931
+ } else {
932
+ showMode(-1);
933
+ fillDate();
752
934
  }
753
- showMode(-1);
754
- fillDate();
935
+ viewUpdate('M');
755
936
  },
756
937
 
757
938
  selectYear: function (e) {
@@ -759,10 +940,29 @@
759
940
  viewDate.year(year);
760
941
  if (currentViewMode === minViewModeNumber) {
761
942
  setValue(date.clone().year(viewDate.year()));
762
- hide();
943
+ if (!options.inline) {
944
+ hide();
945
+ }
946
+ } else {
947
+ showMode(-1);
948
+ fillDate();
763
949
  }
764
- showMode(-1);
765
- fillDate();
950
+ viewUpdate('YYYY');
951
+ },
952
+
953
+ selectDecade: function (e) {
954
+ var year = parseInt($(e.target).data('selection'), 10) || 0;
955
+ viewDate.year(year);
956
+ if (currentViewMode === minViewModeNumber) {
957
+ setValue(date.clone().year(viewDate.year()));
958
+ if (!options.inline) {
959
+ hide();
960
+ }
961
+ } else {
962
+ showMode(-1);
963
+ fillDate();
964
+ }
965
+ viewUpdate('YYYY');
766
966
  },
767
967
 
768
968
  selectDay: function (e) {
@@ -774,33 +974,51 @@
774
974
  day.add(1, 'M');
775
975
  }
776
976
  setValue(day.date(parseInt($(e.target).text(), 10)));
777
- if (!hasTime() && !options.keepOpen) {
977
+ if (!hasTime() && !options.keepOpen && !options.inline) {
778
978
  hide();
779
979
  }
780
980
  },
781
981
 
782
982
  incrementHours: function () {
783
- setValue(date.clone().add(1, 'h'));
983
+ var newDate = date.clone().add(1, 'h');
984
+ if (isValid(newDate, 'h')) {
985
+ setValue(newDate);
986
+ }
784
987
  },
785
988
 
786
989
  incrementMinutes: function () {
787
- setValue(date.clone().add(options.stepping, 'm'));
990
+ var newDate = date.clone().add(options.stepping, 'm');
991
+ if (isValid(newDate, 'm')) {
992
+ setValue(newDate);
993
+ }
788
994
  },
789
995
 
790
996
  incrementSeconds: function () {
791
- setValue(date.clone().add(1, 's'));
997
+ var newDate = date.clone().add(1, 's');
998
+ if (isValid(newDate, 's')) {
999
+ setValue(newDate);
1000
+ }
792
1001
  },
793
1002
 
794
1003
  decrementHours: function () {
795
- setValue(date.clone().subtract(1, 'h'));
1004
+ var newDate = date.clone().subtract(1, 'h');
1005
+ if (isValid(newDate, 'h')) {
1006
+ setValue(newDate);
1007
+ }
796
1008
  },
797
1009
 
798
1010
  decrementMinutes: function () {
799
- setValue(date.clone().subtract(options.stepping, 'm'));
1011
+ var newDate = date.clone().subtract(options.stepping, 'm');
1012
+ if (isValid(newDate, 'm')) {
1013
+ setValue(newDate);
1014
+ }
800
1015
  },
801
1016
 
802
1017
  decrementSeconds: function () {
803
- setValue(date.clone().subtract(1, 's'));
1018
+ var newDate = date.clone().subtract(1, 's');
1019
+ if (isValid(newDate, 's')) {
1020
+ setValue(newDate);
1021
+ }
804
1022
  },
805
1023
 
806
1024
  togglePeriod: function () {
@@ -819,8 +1037,13 @@
819
1037
  if (collapseData && collapseData.transitioning) {
820
1038
  return;
821
1039
  }
822
- expanded.collapse('hide');
823
- closed.collapse('show');
1040
+ if (expanded.collapse) { // if collapse plugin is available through bootstrap.js then use it
1041
+ expanded.collapse('hide');
1042
+ closed.collapse('show');
1043
+ } else { // otherwise just toggle in class on the two views
1044
+ expanded.removeClass('in');
1045
+ closed.addClass('in');
1046
+ }
824
1047
  if ($this.is('span')) {
825
1048
  $this.toggleClass(options.icons.time + ' ' + options.icons.date);
826
1049
  } else {
@@ -882,13 +1105,15 @@
882
1105
  actions.showPicker.call(picker);
883
1106
  },
884
1107
 
885
- clear: function () {
886
- setValue(null);
887
- },
1108
+ clear: clear,
888
1109
 
889
1110
  today: function () {
890
- setValue(moment());
891
- }
1111
+ if (isValid(moment(), 'd')) {
1112
+ setValue(moment());
1113
+ }
1114
+ },
1115
+
1116
+ close: hide
892
1117
  },
893
1118
 
894
1119
  doAction = function (e) {
@@ -900,6 +1125,7 @@
900
1125
  },
901
1126
 
902
1127
  show = function () {
1128
+ ///<summary>Shows the widget. Possibly will emit dp.show and dp.change</summary>
903
1129
  var currentMoment,
904
1130
  useCurrentGranularity = {
905
1131
  'year': function (m) {
@@ -919,10 +1145,12 @@
919
1145
  }
920
1146
  };
921
1147
 
922
- if (input.prop('disabled') || input.prop('readonly') || widget) {
1148
+ if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) {
923
1149
  return picker;
924
1150
  }
925
- if (options.useCurrent && unset) { // && input.val().trim().length !== 0) { this broke the jasmine test
1151
+ if (input.val() !== undefined && input.val().trim().length !== 0) {
1152
+ setValue(parseInputDate(input.val().trim()));
1153
+ } else if (options.useCurrent && unset && ((input.is('input') && input.val().trim().length === 0) || options.inline)) {
926
1154
  currentMoment = moment();
927
1155
  if (typeof options.useCurrent === 'string') {
928
1156
  currentMoment = useCurrentGranularity[options.useCurrent](currentMoment);
@@ -952,7 +1180,7 @@
952
1180
  widget.show();
953
1181
  place();
954
1182
 
955
- if (!input.is(':focus')) {
1183
+ if (options.focusOnShow && !input.is(':focus')) {
956
1184
  input.focus();
957
1185
  }
958
1186
 
@@ -963,25 +1191,78 @@
963
1191
  },
964
1192
 
965
1193
  toggle = function () {
1194
+ /// <summary>Shows or hides the widget</summary>
966
1195
  return (widget ? hide() : show());
967
1196
  },
968
1197
 
969
- parseInputDate = function (date) {
970
- if (moment.isMoment(date) || date instanceof Date) {
971
- date = moment(date);
1198
+ parseInputDate = function (inputDate) {
1199
+ if (options.parseInputDate === undefined) {
1200
+ if (moment.isMoment(inputDate) || inputDate instanceof Date) {
1201
+ inputDate = moment(inputDate);
1202
+ } else {
1203
+ inputDate = moment(inputDate, parseFormats, options.useStrict);
1204
+ }
972
1205
  } else {
973
- date = moment(date, parseFormats, options.useStrict);
1206
+ inputDate = options.parseInputDate(inputDate);
974
1207
  }
975
- date.locale(options.locale);
976
- return date;
1208
+ inputDate.locale(options.locale);
1209
+ return inputDate;
977
1210
  },
978
1211
 
979
1212
  keydown = function (e) {
980
- if (e.keyCode === 27) { // allow escape to hide picker
981
- hide();
1213
+ var handler = null,
1214
+ index,
1215
+ index2,
1216
+ pressedKeys = [],
1217
+ pressedModifiers = {},
1218
+ currentKey = e.which,
1219
+ keyBindKeys,
1220
+ allModifiersPressed,
1221
+ pressed = 'p';
1222
+
1223
+ keyState[currentKey] = pressed;
1224
+
1225
+ for (index in keyState) {
1226
+ if (keyState.hasOwnProperty(index) && keyState[index] === pressed) {
1227
+ pressedKeys.push(index);
1228
+ if (parseInt(index, 10) !== currentKey) {
1229
+ pressedModifiers[index] = true;
1230
+ }
1231
+ }
1232
+ }
1233
+
1234
+ for (index in options.keyBinds) {
1235
+ if (options.keyBinds.hasOwnProperty(index) && typeof (options.keyBinds[index]) === 'function') {
1236
+ keyBindKeys = index.split(' ');
1237
+ if (keyBindKeys.length === pressedKeys.length && keyMap[currentKey] === keyBindKeys[keyBindKeys.length - 1]) {
1238
+ allModifiersPressed = true;
1239
+ for (index2 = keyBindKeys.length - 2; index2 >= 0; index2--) {
1240
+ if (!(keyMap[keyBindKeys[index2]] in pressedModifiers)) {
1241
+ allModifiersPressed = false;
1242
+ break;
1243
+ }
1244
+ }
1245
+ if (allModifiersPressed) {
1246
+ handler = options.keyBinds[index];
1247
+ break;
1248
+ }
1249
+ }
1250
+ }
1251
+ }
1252
+
1253
+ if (handler) {
1254
+ handler.call(picker, widget);
1255
+ e.stopPropagation();
1256
+ e.preventDefault();
982
1257
  }
983
1258
  },
984
1259
 
1260
+ keyup = function (e) {
1261
+ keyState[e.which] = 'r';
1262
+ e.stopPropagation();
1263
+ e.preventDefault();
1264
+ },
1265
+
985
1266
  change = function (e) {
986
1267
  var val = $(e.target).val().trim(),
987
1268
  parsedDate = val ? parseInputDate(val) : null;
@@ -993,8 +1274,10 @@
993
1274
  attachDatePickerElementEvents = function () {
994
1275
  input.on({
995
1276
  'change': change,
996
- 'blur': hide,
997
- 'keydown': keydown
1277
+ 'blur': options.debug ? '' : hide,
1278
+ 'keydown': keydown,
1279
+ 'keyup': keyup,
1280
+ 'focus': options.allowInputToggle ? show : ''
998
1281
  });
999
1282
 
1000
1283
  if (element.is('input')) {
@@ -1010,8 +1293,10 @@
1010
1293
  detachDatePickerElementEvents = function () {
1011
1294
  input.off({
1012
1295
  'change': change,
1013
- 'blur': hide,
1014
- 'keydown': keydown
1296
+ 'blur': blur,
1297
+ 'keydown': keydown,
1298
+ 'keyup': keyup,
1299
+ 'focus': options.allowInputToggle ? hide : ''
1015
1300
  });
1016
1301
 
1017
1302
  if (element.is('input')) {
@@ -1038,19 +1323,34 @@
1038
1323
  return (Object.keys(givenDatesIndexed).length) ? givenDatesIndexed : false;
1039
1324
  },
1040
1325
 
1326
+ indexGivenHours = function (givenHoursArray) {
1327
+ // Store given enabledHours and disabledHours as keys.
1328
+ // This way we can check their existence in O(1) time instead of looping through whole array.
1329
+ // (for example: options.enabledHours['2014-02-27'] === true)
1330
+ var givenHoursIndexed = {};
1331
+ $.each(givenHoursArray, function () {
1332
+ givenHoursIndexed[this] = true;
1333
+ });
1334
+ return (Object.keys(givenHoursIndexed).length) ? givenHoursIndexed : false;
1335
+ },
1336
+
1041
1337
  initFormatting = function () {
1042
1338
  var format = options.format || 'L LT';
1043
1339
 
1044
- actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (input) {
1045
- return date.localeData().longDateFormat(input) || input;
1340
+ actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput) {
1341
+ var newinput = date.localeData().longDateFormat(formatInput) || formatInput;
1342
+ return newinput.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput2) { //temp fix for #740
1343
+ return date.localeData().longDateFormat(formatInput2) || formatInput2;
1344
+ });
1046
1345
  });
1047
1346
 
1347
+
1048
1348
  parseFormats = options.extraFormats ? options.extraFormats.slice() : [];
1049
1349
  if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) {
1050
1350
  parseFormats.push(actualFormat);
1051
1351
  }
1052
1352
 
1053
- use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.indexOf('h') < 1);
1353
+ use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.replace(/\[.*?\]/g, '').indexOf('h') < 1);
1054
1354
 
1055
1355
  if (isEnabled('y')) {
1056
1356
  minViewModeNumber = 2;
@@ -1080,6 +1380,7 @@
1080
1380
  *
1081
1381
  ********************************************************************************/
1082
1382
  picker.destroy = function () {
1383
+ ///<summary>Destroys the widget and removes all attached event listeners</summary>
1083
1384
  hide();
1084
1385
  detachDatePickerElementEvents();
1085
1386
  element.removeData('DateTimePicker');
@@ -1093,6 +1394,8 @@
1093
1394
  picker.hide = hide;
1094
1395
 
1095
1396
  picker.disable = function () {
1397
+ ///<summary>Disables the input element, the component is attached to, by adding a disabled="true" attribute to it.
1398
+ ///If the widget was visible before that call it is hidden. Possibly emits dp.hide</summary>
1096
1399
  hide();
1097
1400
  if (component && component.hasClass('btn')) {
1098
1401
  component.addClass('disabled');
@@ -1102,6 +1405,7 @@
1102
1405
  };
1103
1406
 
1104
1407
  picker.enable = function () {
1408
+ ///<summary>Enables the input element, the component is attached to, by removing disabled attribute from it.</summary>
1105
1409
  if (component && component.hasClass('btn')) {
1106
1410
  component.removeClass('disabled');
1107
1411
  }
@@ -1109,6 +1413,17 @@
1109
1413
  return picker;
1110
1414
  };
1111
1415
 
1416
+ picker.ignoreReadonly = function (ignoreReadonly) {
1417
+ if (arguments.length === 0) {
1418
+ return options.ignoreReadonly;
1419
+ }
1420
+ if (typeof ignoreReadonly !== 'boolean') {
1421
+ throw new TypeError('ignoreReadonly () expects a boolean parameter');
1422
+ }
1423
+ options.ignoreReadonly = ignoreReadonly;
1424
+ return picker;
1425
+ };
1426
+
1112
1427
  picker.options = function (newOptions) {
1113
1428
  if (arguments.length === 0) {
1114
1429
  return $.extend(true, {}, options);
@@ -1129,6 +1444,14 @@
1129
1444
  };
1130
1445
 
1131
1446
  picker.date = function (newDate) {
1447
+ ///<signature helpKeyword="$.fn.datetimepicker.date">
1448
+ ///<summary>Returns the component's model current date, a moment object or null if not set.</summary>
1449
+ ///<returns type="Moment">date.clone()</returns>
1450
+ ///</signature>
1451
+ ///<signature>
1452
+ ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary>
1453
+ ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, Date, moment, null parameter.</param>
1454
+ ///</signature>
1132
1455
  if (arguments.length === 0) {
1133
1456
  if (unset) {
1134
1457
  return null;
@@ -1145,6 +1468,9 @@
1145
1468
  };
1146
1469
 
1147
1470
  picker.format = function (newFormat) {
1471
+ ///<summary>test su</summary>
1472
+ ///<param name="newFormat">info about para</param>
1473
+ ///<returns type="string|boolean">returns foo</returns>
1148
1474
  if (arguments.length === 0) {
1149
1475
  return options.format;
1150
1476
  }
@@ -1190,6 +1516,15 @@
1190
1516
  };
1191
1517
 
1192
1518
  picker.disabledDates = function (dates) {
1519
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledDates">
1520
+ ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
1521
+ ///<returns type="array">options.disabledDates</returns>
1522
+ ///</signature>
1523
+ ///<signature>
1524
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
1525
+ ///options.enabledDates if such exist.</summary>
1526
+ ///<param name="dates" locid="$.fn.datetimepicker.disabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
1527
+ ///</signature>
1193
1528
  if (arguments.length === 0) {
1194
1529
  return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates);
1195
1530
  }
@@ -1209,6 +1544,14 @@
1209
1544
  };
1210
1545
 
1211
1546
  picker.enabledDates = function (dates) {
1547
+ ///<signature helpKeyword="$.fn.datetimepicker.enabledDates">
1548
+ ///<summary>Returns an array with the currently set enabled dates on the component.</summary>
1549
+ ///<returns type="array">options.enabledDates</returns>
1550
+ ///</signature>
1551
+ ///<signature>
1552
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledDates if such exist.</summary>
1553
+ ///<param name="dates" locid="$.fn.datetimepicker.enabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
1554
+ ///</signature>
1212
1555
  if (arguments.length === 0) {
1213
1556
  return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates);
1214
1557
  }
@@ -1232,6 +1575,12 @@
1232
1575
  return options.daysOfWeekDisabled.splice(0);
1233
1576
  }
1234
1577
 
1578
+ if ((typeof daysOfWeekDisabled === 'boolean') && !daysOfWeekDisabled) {
1579
+ options.daysOfWeekDisabled = false;
1580
+ update();
1581
+ return picker;
1582
+ }
1583
+
1235
1584
  if (!(daysOfWeekDisabled instanceof Array)) {
1236
1585
  throw new TypeError('daysOfWeekDisabled() expects an array parameter');
1237
1586
  }
@@ -1245,65 +1594,102 @@
1245
1594
  }
1246
1595
  return previousValue;
1247
1596
  }, []).sort();
1597
+ if (options.useCurrent && !options.keepInvalid) {
1598
+ var tries = 0;
1599
+ while (!isValid(date, 'd')) {
1600
+ date.add(1, 'd');
1601
+ if (tries === 7) {
1602
+ throw 'Tried 7 times to find a valid date';
1603
+ }
1604
+ tries++;
1605
+ }
1606
+ setValue(date);
1607
+ }
1248
1608
  update();
1249
1609
  return picker;
1250
1610
  };
1251
1611
 
1252
- picker.maxDate = function (date) {
1612
+ picker.maxDate = function (maxDate) {
1253
1613
  if (arguments.length === 0) {
1254
1614
  return options.maxDate ? options.maxDate.clone() : options.maxDate;
1255
1615
  }
1256
1616
 
1257
- if ((typeof date === 'boolean') && date === false) {
1617
+ if ((typeof maxDate === 'boolean') && maxDate === false) {
1258
1618
  options.maxDate = false;
1259
1619
  update();
1260
1620
  return picker;
1261
1621
  }
1262
1622
 
1263
- var parsedDate = parseInputDate(date);
1623
+ if (typeof maxDate === 'string') {
1624
+ if (maxDate === 'now' || maxDate === 'moment') {
1625
+ maxDate = moment();
1626
+ }
1627
+ }
1628
+
1629
+ var parsedDate = parseInputDate(maxDate);
1264
1630
 
1265
1631
  if (!parsedDate.isValid()) {
1266
- throw new TypeError('maxDate() Could not parse date parameter: ' + date);
1632
+ throw new TypeError('maxDate() Could not parse date parameter: ' + maxDate);
1267
1633
  }
1268
1634
  if (options.minDate && parsedDate.isBefore(options.minDate)) {
1269
1635
  throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat));
1270
1636
  }
1271
1637
  options.maxDate = parsedDate;
1272
- if (options.maxDate.isBefore(date)) {
1638
+ if (options.useCurrent && !options.keepInvalid && date.isAfter(maxDate)) {
1273
1639
  setValue(options.maxDate);
1274
1640
  }
1641
+ if (viewDate.isAfter(parsedDate)) {
1642
+ viewDate = parsedDate.clone().subtract(options.stepping, 'm');
1643
+ }
1275
1644
  update();
1276
1645
  return picker;
1277
1646
  };
1278
1647
 
1279
- picker.minDate = function (date) {
1648
+ picker.minDate = function (minDate) {
1280
1649
  if (arguments.length === 0) {
1281
1650
  return options.minDate ? options.minDate.clone() : options.minDate;
1282
1651
  }
1283
1652
 
1284
- if ((typeof date === 'boolean') && date === false) {
1653
+ if ((typeof minDate === 'boolean') && minDate === false) {
1285
1654
  options.minDate = false;
1286
1655
  update();
1287
1656
  return picker;
1288
1657
  }
1289
1658
 
1290
- var parsedDate = parseInputDate(date);
1659
+ if (typeof minDate === 'string') {
1660
+ if (minDate === 'now' || minDate === 'moment') {
1661
+ minDate = moment();
1662
+ }
1663
+ }
1664
+
1665
+ var parsedDate = parseInputDate(minDate);
1291
1666
 
1292
1667
  if (!parsedDate.isValid()) {
1293
- throw new TypeError('minDate() Could not parse date parameter: ' + date);
1668
+ throw new TypeError('minDate() Could not parse date parameter: ' + minDate);
1294
1669
  }
1295
1670
  if (options.maxDate && parsedDate.isAfter(options.maxDate)) {
1296
1671
  throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat));
1297
1672
  }
1298
1673
  options.minDate = parsedDate;
1299
- if (options.minDate.isAfter(date)) {
1674
+ if (options.useCurrent && !options.keepInvalid && date.isBefore(minDate)) {
1300
1675
  setValue(options.minDate);
1301
1676
  }
1677
+ if (viewDate.isBefore(parsedDate)) {
1678
+ viewDate = parsedDate.clone().add(options.stepping, 'm');
1679
+ }
1302
1680
  update();
1303
1681
  return picker;
1304
1682
  };
1305
1683
 
1306
1684
  picker.defaultDate = function (defaultDate) {
1685
+ ///<signature helpKeyword="$.fn.datetimepicker.defaultDate">
1686
+ ///<summary>Returns a moment with the options.defaultDate option configuration or false if not set</summary>
1687
+ ///<returns type="Moment">date.clone()</returns>
1688
+ ///</signature>
1689
+ ///<signature>
1690
+ ///<summary>Will set the picker's inital date. If a boolean:false value is passed the options.defaultDate parameter is cleared.</summary>
1691
+ ///<param name="defaultDate" locid="$.fn.datetimepicker.defaultDate_p:defaultDate">Takes a string, Date, moment, boolean:false</param>
1692
+ ///</signature>
1307
1693
  if (arguments.length === 0) {
1308
1694
  return options.defaultDate ? options.defaultDate.clone() : options.defaultDate;
1309
1695
  }
@@ -1311,6 +1697,13 @@
1311
1697
  options.defaultDate = false;
1312
1698
  return picker;
1313
1699
  }
1700
+
1701
+ if (typeof defaultDate === 'string') {
1702
+ if (defaultDate === 'now' || defaultDate === 'moment') {
1703
+ defaultDate = moment();
1704
+ }
1705
+ }
1706
+
1314
1707
  var parsedDate = parseInputDate(defaultDate);
1315
1708
  if (!parsedDate.isValid()) {
1316
1709
  throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate);
@@ -1321,7 +1714,7 @@
1321
1714
 
1322
1715
  options.defaultDate = parsedDate;
1323
1716
 
1324
- if (options.defaultDate && input.val().trim() === '') {
1717
+ if (options.defaultDate && options.inline || (input.val().trim() === '' && input.attr('placeholder') === undefined)) {
1325
1718
  setValue(options.defaultDate);
1326
1719
  }
1327
1720
  return picker;
@@ -1414,6 +1807,22 @@
1414
1807
  return picker;
1415
1808
  };
1416
1809
 
1810
+ picker.tooltips = function (tooltips) {
1811
+ if (arguments.length === 0) {
1812
+ return $.extend({}, options.tooltips);
1813
+ }
1814
+
1815
+ if (!(tooltips instanceof Object)) {
1816
+ throw new TypeError('tooltips() expects parameter to be an Object');
1817
+ }
1818
+ $.extend(options.tooltips, tooltips);
1819
+ if (widget) {
1820
+ hide();
1821
+ show();
1822
+ }
1823
+ return picker;
1824
+ };
1825
+
1417
1826
  picker.useStrict = function (useStrict) {
1418
1827
  if (arguments.length === 0) {
1419
1828
  return options.useStrict;
@@ -1442,21 +1851,21 @@
1442
1851
  return picker;
1443
1852
  };
1444
1853
 
1445
- picker.viewMode = function (newViewMode) {
1854
+ picker.viewMode = function (viewMode) {
1446
1855
  if (arguments.length === 0) {
1447
1856
  return options.viewMode;
1448
1857
  }
1449
1858
 
1450
- if (typeof newViewMode !== 'string') {
1859
+ if (typeof viewMode !== 'string') {
1451
1860
  throw new TypeError('viewMode() expects a string parameter');
1452
1861
  }
1453
1862
 
1454
- if (viewModes.indexOf(newViewMode) === -1) {
1863
+ if (viewModes.indexOf(viewMode) === -1) {
1455
1864
  throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value');
1456
1865
  }
1457
1866
 
1458
- options.viewMode = newViewMode;
1459
- currentViewMode = Math.max(viewModes.indexOf(newViewMode), minViewModeNumber);
1867
+ options.viewMode = viewMode;
1868
+ currentViewMode = Math.max(viewModes.indexOf(viewMode), minViewModeNumber);
1460
1869
 
1461
1870
  showMode();
1462
1871
  return picker;
@@ -1514,16 +1923,16 @@
1514
1923
  return picker;
1515
1924
  };
1516
1925
 
1517
- picker.calendarWeeks = function (showCalendarWeeks) {
1926
+ picker.calendarWeeks = function (calendarWeeks) {
1518
1927
  if (arguments.length === 0) {
1519
1928
  return options.calendarWeeks;
1520
1929
  }
1521
1930
 
1522
- if (typeof showCalendarWeeks !== 'boolean') {
1931
+ if (typeof calendarWeeks !== 'boolean') {
1523
1932
  throw new TypeError('calendarWeeks() expects parameter to be a boolean value');
1524
1933
  }
1525
1934
 
1526
- options.calendarWeeks = showCalendarWeeks;
1935
+ options.calendarWeeks = calendarWeeks;
1527
1936
  update();
1528
1937
  return picker;
1529
1938
  };
@@ -1571,7 +1980,7 @@
1571
1980
  widgetParent = $(widgetParent);
1572
1981
  }
1573
1982
 
1574
- if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof jQuery))) {
1983
+ if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof $))) {
1575
1984
  throw new TypeError('widgetParent() expects a string or a jQuery object parameter');
1576
1985
  }
1577
1986
 
@@ -1585,7 +1994,7 @@
1585
1994
 
1586
1995
  picker.keepOpen = function (keepOpen) {
1587
1996
  if (arguments.length === 0) {
1588
- return options.format;
1997
+ return options.keepOpen;
1589
1998
  }
1590
1999
 
1591
2000
  if (typeof keepOpen !== 'boolean') {
@@ -1596,28 +2005,269 @@
1596
2005
  return picker;
1597
2006
  };
1598
2007
 
2008
+ picker.focusOnShow = function (focusOnShow) {
2009
+ if (arguments.length === 0) {
2010
+ return options.focusOnShow;
2011
+ }
2012
+
2013
+ if (typeof focusOnShow !== 'boolean') {
2014
+ throw new TypeError('focusOnShow() expects a boolean parameter');
2015
+ }
2016
+
2017
+ options.focusOnShow = focusOnShow;
2018
+ return picker;
2019
+ };
2020
+
2021
+ picker.inline = function (inline) {
2022
+ if (arguments.length === 0) {
2023
+ return options.inline;
2024
+ }
2025
+
2026
+ if (typeof inline !== 'boolean') {
2027
+ throw new TypeError('inline() expects a boolean parameter');
2028
+ }
2029
+
2030
+ options.inline = inline;
2031
+ return picker;
2032
+ };
2033
+
2034
+ picker.clear = function () {
2035
+ clear();
2036
+ return picker;
2037
+ };
2038
+
2039
+ picker.keyBinds = function (keyBinds) {
2040
+ options.keyBinds = keyBinds;
2041
+ return picker;
2042
+ };
2043
+
2044
+ picker.debug = function (debug) {
2045
+ if (typeof debug !== 'boolean') {
2046
+ throw new TypeError('debug() expects a boolean parameter');
2047
+ }
2048
+
2049
+ options.debug = debug;
2050
+ return picker;
2051
+ };
2052
+
2053
+ picker.allowInputToggle = function (allowInputToggle) {
2054
+ if (arguments.length === 0) {
2055
+ return options.allowInputToggle;
2056
+ }
2057
+
2058
+ if (typeof allowInputToggle !== 'boolean') {
2059
+ throw new TypeError('allowInputToggle() expects a boolean parameter');
2060
+ }
2061
+
2062
+ options.allowInputToggle = allowInputToggle;
2063
+ return picker;
2064
+ };
2065
+
2066
+ picker.showClose = function (showClose) {
2067
+ if (arguments.length === 0) {
2068
+ return options.showClose;
2069
+ }
2070
+
2071
+ if (typeof showClose !== 'boolean') {
2072
+ throw new TypeError('showClose() expects a boolean parameter');
2073
+ }
2074
+
2075
+ options.showClose = showClose;
2076
+ return picker;
2077
+ };
2078
+
2079
+ picker.keepInvalid = function (keepInvalid) {
2080
+ if (arguments.length === 0) {
2081
+ return options.keepInvalid;
2082
+ }
2083
+
2084
+ if (typeof keepInvalid !== 'boolean') {
2085
+ throw new TypeError('keepInvalid() expects a boolean parameter');
2086
+ }
2087
+ options.keepInvalid = keepInvalid;
2088
+ return picker;
2089
+ };
2090
+
2091
+ picker.datepickerInput = function (datepickerInput) {
2092
+ if (arguments.length === 0) {
2093
+ return options.datepickerInput;
2094
+ }
2095
+
2096
+ if (typeof datepickerInput !== 'string') {
2097
+ throw new TypeError('datepickerInput() expects a string parameter');
2098
+ }
2099
+
2100
+ options.datepickerInput = datepickerInput;
2101
+ return picker;
2102
+ };
2103
+
2104
+ picker.parseInputDate = function (parseInputDate) {
2105
+ if (arguments.length === 0) {
2106
+ return options.parseInputDate;
2107
+ }
2108
+
2109
+ if (typeof parseInputDate !== 'function') {
2110
+ throw new TypeError('parseInputDate() sholud be as function');
2111
+ }
2112
+
2113
+ options.parseInputDate = parseInputDate;
2114
+
2115
+ return picker;
2116
+ };
2117
+
2118
+ picker.disabledTimeIntervals = function (disabledTimeIntervals) {
2119
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledTimeIntervals">
2120
+ ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
2121
+ ///<returns type="array">options.disabledTimeIntervals</returns>
2122
+ ///</signature>
2123
+ ///<signature>
2124
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
2125
+ ///options.enabledDates if such exist.</summary>
2126
+ ///<param name="dates" locid="$.fn.datetimepicker.disabledTimeIntervals_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
2127
+ ///</signature>
2128
+ if (arguments.length === 0) {
2129
+ return (options.disabledTimeIntervals ? $.extend({}, options.disabledTimeIntervals) : options.disabledTimeIntervals);
2130
+ }
2131
+
2132
+ if (!disabledTimeIntervals) {
2133
+ options.disabledTimeIntervals = false;
2134
+ update();
2135
+ return picker;
2136
+ }
2137
+ if (!(disabledTimeIntervals instanceof Array)) {
2138
+ throw new TypeError('disabledTimeIntervals() expects an array parameter');
2139
+ }
2140
+ options.disabledTimeIntervals = disabledTimeIntervals;
2141
+ update();
2142
+ return picker;
2143
+ };
2144
+
2145
+ picker.disabledHours = function (hours) {
2146
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledHours">
2147
+ ///<summary>Returns an array with the currently set disabled hours on the component.</summary>
2148
+ ///<returns type="array">options.disabledHours</returns>
2149
+ ///</signature>
2150
+ ///<signature>
2151
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
2152
+ ///options.enabledHours if such exist.</summary>
2153
+ ///<param name="hours" locid="$.fn.datetimepicker.disabledHours_p:hours">Takes an [ int ] of values and disallows the user to select only from those hours.</param>
2154
+ ///</signature>
2155
+ if (arguments.length === 0) {
2156
+ return (options.disabledHours ? $.extend({}, options.disabledHours) : options.disabledHours);
2157
+ }
2158
+
2159
+ if (!hours) {
2160
+ options.disabledHours = false;
2161
+ update();
2162
+ return picker;
2163
+ }
2164
+ if (!(hours instanceof Array)) {
2165
+ throw new TypeError('disabledHours() expects an array parameter');
2166
+ }
2167
+ options.disabledHours = indexGivenHours(hours);
2168
+ options.enabledHours = false;
2169
+ if (options.useCurrent && !options.keepInvalid) {
2170
+ var tries = 0;
2171
+ while (!isValid(date, 'h')) {
2172
+ date.add(1, 'h');
2173
+ if (tries === 24) {
2174
+ throw 'Tried 24 times to find a valid date';
2175
+ }
2176
+ tries++;
2177
+ }
2178
+ setValue(date);
2179
+ }
2180
+ update();
2181
+ return picker;
2182
+ };
2183
+
2184
+ picker.enabledHours = function (hours) {
2185
+ ///<signature helpKeyword="$.fn.datetimepicker.enabledHours">
2186
+ ///<summary>Returns an array with the currently set enabled hours on the component.</summary>
2187
+ ///<returns type="array">options.enabledHours</returns>
2188
+ ///</signature>
2189
+ ///<signature>
2190
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledHours if such exist.</summary>
2191
+ ///<param name="hours" locid="$.fn.datetimepicker.enabledHours_p:hours">Takes an [ int ] of values and allows the user to select only from those hours.</param>
2192
+ ///</signature>
2193
+ if (arguments.length === 0) {
2194
+ return (options.enabledHours ? $.extend({}, options.enabledHours) : options.enabledHours);
2195
+ }
2196
+
2197
+ if (!hours) {
2198
+ options.enabledHours = false;
2199
+ update();
2200
+ return picker;
2201
+ }
2202
+ if (!(hours instanceof Array)) {
2203
+ throw new TypeError('enabledHours() expects an array parameter');
2204
+ }
2205
+ options.enabledHours = indexGivenHours(hours);
2206
+ options.disabledHours = false;
2207
+ if (options.useCurrent && !options.keepInvalid) {
2208
+ var tries = 0;
2209
+ while (!isValid(date, 'h')) {
2210
+ date.add(1, 'h');
2211
+ if (tries === 24) {
2212
+ throw 'Tried 24 times to find a valid date';
2213
+ }
2214
+ tries++;
2215
+ }
2216
+ setValue(date);
2217
+ }
2218
+ update();
2219
+ return picker;
2220
+ };
2221
+
2222
+ picker.viewDate = function (newDate) {
2223
+ ///<signature helpKeyword="$.fn.datetimepicker.viewDate">
2224
+ ///<summary>Returns the component's model current viewDate, a moment object or null if not set.</summary>
2225
+ ///<returns type="Moment">viewDate.clone()</returns>
2226
+ ///</signature>
2227
+ ///<signature>
2228
+ ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary>
2229
+ ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, viewDate, moment, null parameter.</param>
2230
+ ///</signature>
2231
+ if (arguments.length === 0) {
2232
+ return viewDate.clone();
2233
+ }
2234
+
2235
+ if (!newDate) {
2236
+ viewDate = date.clone();
2237
+ return picker;
2238
+ }
2239
+
2240
+ if (typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
2241
+ throw new TypeError('viewDate() parameter must be one of [string, moment or Date]');
2242
+ }
2243
+
2244
+ viewDate = parseInputDate(newDate);
2245
+ viewUpdate();
2246
+ return picker;
2247
+ };
2248
+
1599
2249
  // initializing element and component attributes
1600
2250
  if (element.is('input')) {
1601
2251
  input = element;
1602
2252
  } else {
1603
- input = element.find('.datepickerinput');
2253
+ input = element.find(options.datepickerInput);
1604
2254
  if (input.size() === 0) {
1605
2255
  input = element.find('input');
1606
2256
  } else if (!input.is('input')) {
1607
- throw new Error('CSS class "datepickerinput" cannot be applied to non input element');
2257
+ throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element');
1608
2258
  }
1609
2259
  }
1610
2260
 
1611
2261
  if (element.hasClass('input-group')) {
1612
2262
  // in case there is more then one 'input-group-addon' Issue #48
1613
2263
  if (element.find('.datepickerbutton').size() === 0) {
1614
- component = element.find('[class^="input-group-"]');
2264
+ component = element.find('.input-group-addon');
1615
2265
  } else {
1616
2266
  component = element.find('.datepickerbutton');
1617
2267
  }
1618
2268
  }
1619
2269
 
1620
- if (!input.is('input')) {
2270
+ if (!options.inline && !input.is('input')) {
1621
2271
  throw new Error('Could not initialize DateTimePicker without an input element');
1622
2272
  }
1623
2273
 
@@ -1632,13 +2282,15 @@
1632
2282
  if (input.prop('disabled')) {
1633
2283
  picker.disable();
1634
2284
  }
1635
-
1636
- if (input.val().trim().length !== 0) {
2285
+ if (input.is('input') && input.val().trim().length !== 0) {
1637
2286
  setValue(parseInputDate(input.val().trim()));
1638
- } else if (options.defaultDate) {
2287
+ }
2288
+ else if (options.defaultDate && input.attr('placeholder') === undefined) {
1639
2289
  setValue(options.defaultDate);
1640
2290
  }
1641
-
2291
+ if (options.inline) {
2292
+ show();
2293
+ }
1642
2294
  return picker;
1643
2295
  };
1644
2296
 
@@ -1680,21 +2332,154 @@
1680
2332
  previous: 'glyphicon glyphicon-chevron-left',
1681
2333
  next: 'glyphicon glyphicon-chevron-right',
1682
2334
  today: 'glyphicon glyphicon-screenshot',
1683
- clear: 'glyphicon glyphicon-trash'
2335
+ clear: 'glyphicon glyphicon-trash',
2336
+ close: 'glyphicon glyphicon-remove'
2337
+ },
2338
+ tooltips: {
2339
+ today: 'Go to today',
2340
+ clear: 'Clear selection',
2341
+ close: 'Close the picker',
2342
+ selectMonth: 'Select Month',
2343
+ prevMonth: 'Previous Month',
2344
+ nextMonth: 'Next Month',
2345
+ selectYear: 'Select Year',
2346
+ prevYear: 'Previous Year',
2347
+ nextYear: 'Next Year',
2348
+ selectDecade: 'Select Decade',
2349
+ prevDecade: 'Previous Decade',
2350
+ nextDecade: 'Next Decade',
2351
+ prevCentury: 'Previous Century',
2352
+ nextCentury: 'Next Century'
1684
2353
  },
1685
2354
  useStrict: false,
1686
2355
  sideBySide: false,
1687
- daysOfWeekDisabled: [],
2356
+ daysOfWeekDisabled: false,
1688
2357
  calendarWeeks: false,
1689
2358
  viewMode: 'days',
1690
2359
  toolbarPlacement: 'default',
1691
2360
  showTodayButton: false,
1692
2361
  showClear: false,
2362
+ showClose: false,
1693
2363
  widgetPositioning: {
1694
2364
  horizontal: 'auto',
1695
2365
  vertical: 'auto'
1696
2366
  },
1697
2367
  widgetParent: null,
1698
- keepOpen: false
2368
+ ignoreReadonly: false,
2369
+ keepOpen: false,
2370
+ focusOnShow: true,
2371
+ inline: false,
2372
+ keepInvalid: false,
2373
+ datepickerInput: '.datepickerinput',
2374
+ keyBinds: {
2375
+ up: function (widget) {
2376
+ if (!widget) {
2377
+ return;
2378
+ }
2379
+ var d = this.date() || moment();
2380
+ if (widget.find('.datepicker').is(':visible')) {
2381
+ this.date(d.clone().subtract(7, 'd'));
2382
+ } else {
2383
+ this.date(d.clone().add(this.stepping(), 'm'));
2384
+ }
2385
+ },
2386
+ down: function (widget) {
2387
+ if (!widget) {
2388
+ this.show();
2389
+ return;
2390
+ }
2391
+ var d = this.date() || moment();
2392
+ if (widget.find('.datepicker').is(':visible')) {
2393
+ this.date(d.clone().add(7, 'd'));
2394
+ } else {
2395
+ this.date(d.clone().subtract(this.stepping(), 'm'));
2396
+ }
2397
+ },
2398
+ 'control up': function (widget) {
2399
+ if (!widget) {
2400
+ return;
2401
+ }
2402
+ var d = this.date() || moment();
2403
+ if (widget.find('.datepicker').is(':visible')) {
2404
+ this.date(d.clone().subtract(1, 'y'));
2405
+ } else {
2406
+ this.date(d.clone().add(1, 'h'));
2407
+ }
2408
+ },
2409
+ 'control down': function (widget) {
2410
+ if (!widget) {
2411
+ return;
2412
+ }
2413
+ var d = this.date() || moment();
2414
+ if (widget.find('.datepicker').is(':visible')) {
2415
+ this.date(d.clone().add(1, 'y'));
2416
+ } else {
2417
+ this.date(d.clone().subtract(1, 'h'));
2418
+ }
2419
+ },
2420
+ left: function (widget) {
2421
+ if (!widget) {
2422
+ return;
2423
+ }
2424
+ var d = this.date() || moment();
2425
+ if (widget.find('.datepicker').is(':visible')) {
2426
+ this.date(d.clone().subtract(1, 'd'));
2427
+ }
2428
+ },
2429
+ right: function (widget) {
2430
+ if (!widget) {
2431
+ return;
2432
+ }
2433
+ var d = this.date() || moment();
2434
+ if (widget.find('.datepicker').is(':visible')) {
2435
+ this.date(d.clone().add(1, 'd'));
2436
+ }
2437
+ },
2438
+ pageUp: function (widget) {
2439
+ if (!widget) {
2440
+ return;
2441
+ }
2442
+ var d = this.date() || moment();
2443
+ if (widget.find('.datepicker').is(':visible')) {
2444
+ this.date(d.clone().subtract(1, 'M'));
2445
+ }
2446
+ },
2447
+ pageDown: function (widget) {
2448
+ if (!widget) {
2449
+ return;
2450
+ }
2451
+ var d = this.date() || moment();
2452
+ if (widget.find('.datepicker').is(':visible')) {
2453
+ this.date(d.clone().add(1, 'M'));
2454
+ }
2455
+ },
2456
+ enter: function () {
2457
+ this.hide();
2458
+ },
2459
+ escape: function () {
2460
+ this.hide();
2461
+ },
2462
+ //tab: function (widget) { //this break the flow of the form. disabling for now
2463
+ // var toggle = widget.find('.picker-switch a[data-action="togglePicker"]');
2464
+ // if(toggle.length > 0) toggle.click();
2465
+ //},
2466
+ 'control space': function (widget) {
2467
+ if (widget.find('.timepicker').is(':visible')) {
2468
+ widget.find('.btn[data-action="togglePeriod"]').click();
2469
+ }
2470
+ },
2471
+ t: function () {
2472
+ this.date(moment());
2473
+ },
2474
+ 'delete': function () {
2475
+ this.clear();
2476
+ }
2477
+ },
2478
+ debug: false,
2479
+ allowInputToggle: false,
2480
+ disabledTimeIntervals: false,
2481
+ disabledHours: false,
2482
+ enabledHours: false,
2483
+ viewDate: false
1699
2484
  };
1700
2485
  }));