effective_form_inputs 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }));