bootstrap3-datetimepicker-rails 4.0.0 → 4.7.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d6e6ae4f217127f3562db4629ff366c6ef760c4
4
- data.tar.gz: 6f102779311ce6a65c1937ee2c64f64dc6a3ca35
3
+ metadata.gz: 2b9d7d21db6bacf96ec8077966448a038acd6d67
4
+ data.tar.gz: ca7423c5be979aaba72c6efac641388052295500
5
5
  SHA512:
6
- metadata.gz: b64abe901e720c6213d783b01ca4ed3f96edbb27bbb9475e36c7ff4f9351ae2f5d9e8fd54c5e6c24d759f2589210518e5b36e912b75fa0988d351ac466407983
7
- data.tar.gz: eed1390c3116875844a3e41bfdd3c2159ed2739f6138cee7dfca13466f74e3b04dfa395b4188dd2d941ed14971c5bdd92982e33a2b9fc6cca288188304a41ecc
6
+ metadata.gz: 62da4f1e8be61b478151235e2bf1db718403cf4f12a760fedd21dd15fd07a5a9dae016c1cce35400a8d12f04ac429fb029bbe7c096c155ba9b6116225c900c2b
7
+ data.tar.gz: 6918e1b85f676a0a0574cef9ea1361f6a7f647418d61d57e36799d3390124967989872021914dadd10ffe54e2133d6399a9d9bc76a09057c079a5a030925119d
data/README.md CHANGED
@@ -14,7 +14,7 @@ actively maintained and works with [Bootstrap3](http://getbootstrap.com).
14
14
  Add these lines to your application's Gemfile:
15
15
  ```ruby
16
16
  gem 'momentjs-rails', '>= 2.9.0'
17
- gem 'bootstrap3-datetimepicker-rails', '~> 4.0.0'
17
+ gem 'bootstrap3-datetimepicker-rails', '~> 4.7.14'
18
18
  ```
19
19
 
20
20
  And then execute:
@@ -1,5 +1,5 @@
1
1
  module Bootstrap3Datetimepicker
2
2
  module Rails
3
- VERSION = '4.0.0'
3
+ VERSION = '4.7.14'
4
4
  end
5
5
  end
@@ -1,9 +1,11 @@
1
- /*
2
- //! version : 4.0.0
1
+ /*! version : 4.7.14
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,
@@ -83,6 +90,37 @@
83
90
  verticalModes = ['top', 'bottom', 'auto'],
84
91
  horizontalModes = ['left', 'right', 'auto'],
85
92
  toolbarPlacements = ['default', 'top', 'bottom'],
93
+ keyMap = {
94
+ 'up': 38,
95
+ 38: 'up',
96
+ 'down': 40,
97
+ 40: 'down',
98
+ 'left': 37,
99
+ 37: 'left',
100
+ 'right': 39,
101
+ 39: 'right',
102
+ 'tab': 9,
103
+ 9: 'tab',
104
+ 'escape': 27,
105
+ 27: 'escape',
106
+ 'enter': 13,
107
+ 13: 'enter',
108
+ 'pageUp': 33,
109
+ 33: 'pageUp',
110
+ 'pageDown': 34,
111
+ 34: 'pageDown',
112
+ 'shift': 16,
113
+ 16: 'shift',
114
+ 'control': 17,
115
+ 17: 'control',
116
+ 'space': 32,
117
+ 32: 'space',
118
+ 't': 84,
119
+ 84: 't',
120
+ 'delete': 46,
121
+ 46: 'delete'
122
+ },
123
+ keyState = {},
86
124
 
87
125
  /********************************************************************************
88
126
  *
@@ -162,12 +200,12 @@
162
200
 
163
201
  if (isEnabled('h')) {
164
202
  topRow.append($('<td>')
165
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementHours')
203
+ .append($('<a>').attr({href: '#', tabindex: '-1'}).addClass('btn').attr('data-action', 'incrementHours')
166
204
  .append($('<span>').addClass(options.icons.up))));
167
205
  middleRow.append($('<td>')
168
206
  .append($('<span>').addClass('timepicker-hour').attr('data-time-component', 'hours').attr('data-action', 'showHours')));
169
207
  bottomRow.append($('<td>')
170
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementHours')
208
+ .append($('<a>').attr({href: '#', tabindex: '-1'}).addClass('btn').attr('data-action', 'decrementHours')
171
209
  .append($('<span>').addClass(options.icons.down))));
172
210
  }
173
211
  if (isEnabled('m')) {
@@ -177,12 +215,12 @@
177
215
  bottomRow.append($('<td>').addClass('separator'));
178
216
  }
179
217
  topRow.append($('<td>')
180
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementMinutes')
218
+ .append($('<a>').attr({href: '#', tabindex: '-1'}).addClass('btn').attr('data-action', 'incrementMinutes')
181
219
  .append($('<span>').addClass(options.icons.up))));
182
220
  middleRow.append($('<td>')
183
221
  .append($('<span>').addClass('timepicker-minute').attr('data-time-component', 'minutes').attr('data-action', 'showMinutes')));
184
222
  bottomRow.append($('<td>')
185
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementMinutes')
223
+ .append($('<a>').attr({href: '#', tabindex: '-1'}).addClass('btn').attr('data-action', 'decrementMinutes')
186
224
  .append($('<span>').addClass(options.icons.down))));
187
225
  }
188
226
  if (isEnabled('s')) {
@@ -192,12 +230,12 @@
192
230
  bottomRow.append($('<td>').addClass('separator'));
193
231
  }
194
232
  topRow.append($('<td>')
195
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementSeconds')
233
+ .append($('<a>').attr({href: '#', tabindex: '-1'}).addClass('btn').attr('data-action', 'incrementSeconds')
196
234
  .append($('<span>').addClass(options.icons.up))));
197
235
  middleRow.append($('<td>')
198
236
  .append($('<span>').addClass('timepicker-second').attr('data-time-component', 'seconds').attr('data-action', 'showSeconds')));
199
237
  bottomRow.append($('<td>')
200
- .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementSeconds')
238
+ .append($('<a>').attr({href: '#', tabindex: '-1'}).addClass('btn').attr('data-action', 'decrementSeconds')
201
239
  .append($('<span>').addClass(options.icons.down))));
202
240
  }
203
241
 
@@ -246,6 +284,9 @@
246
284
  if (options.showClear) {
247
285
  row.push($('<td>').append($('<a>').attr('data-action', 'clear').append($('<span>').addClass(options.icons.clear))));
248
286
  }
287
+ if (options.showClose) {
288
+ row.push($('<td>').append($('<a>').attr('data-action', 'close').append($('<span>').addClass(options.icons.close))));
289
+ }
249
290
  return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row)));
250
291
  },
251
292
 
@@ -256,6 +297,10 @@
256
297
  content = $('<ul>').addClass('list-unstyled'),
257
298
  toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar());
258
299
 
300
+ if (options.inline) {
301
+ template.removeClass('dropdown-menu');
302
+ }
303
+
259
304
  if (use24Hours) {
260
305
  template.addClass('usetwentyfour');
261
306
  }
@@ -289,9 +334,15 @@
289
334
  },
290
335
 
291
336
  dataToOptions = function () {
292
- var eData = element.data(),
337
+ var eData,
293
338
  dataOptions = {};
294
339
 
340
+ if (element.is('input') || options.inline) {
341
+ eData = element.data();
342
+ } else {
343
+ eData = element.find('input').data();
344
+ }
345
+
295
346
  if (eData.dateOptions && eData.dateOptions instanceof Object) {
296
347
  dataOptions = $.extend(true, dataOptions, eData.dateOptions);
297
348
  }
@@ -306,7 +357,8 @@
306
357
  },
307
358
 
308
359
  place = function () {
309
- var offset = (component || element).position(),
360
+ var position = (component || element).position(),
361
+ offset = (component || element).offset(),
310
362
  vertical = options.widgetPositioning.vertical,
311
363
  horizontal = options.widgetPositioning.horizontal,
312
364
  parent;
@@ -315,6 +367,9 @@
315
367
  parent = options.widgetParent.append(widget);
316
368
  } else if (element.is('input')) {
317
369
  parent = element.parent().append(widget);
370
+ } else if (options.inline) {
371
+ parent = element.append(widget);
372
+ return;
318
373
  } else {
319
374
  parent = element;
320
375
  element.children().first().after(widget);
@@ -322,8 +377,8 @@
322
377
 
323
378
  // Top and bottom logic
324
379
  if (vertical === 'auto') {
325
- if ((component || element).offset().top + widget.height() > $(window).height() + $(window).scrollTop() &&
326
- widget.height() + element.outerHeight() < (component || element).offset().top) {
380
+ if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() &&
381
+ widget.height() + element.outerHeight() < offset.top) {
327
382
  vertical = 'top';
328
383
  } else {
329
384
  vertical = 'bottom';
@@ -332,7 +387,8 @@
332
387
 
333
388
  // Left and right logic
334
389
  if (horizontal === 'auto') {
335
- if (parent.width() < offset.left + widget.outerWidth()) {
390
+ if (parent.width() < offset.left + widget.outerWidth() / 2 &&
391
+ offset.left + widget.outerWidth() > $(window).width()) {
336
392
  horizontal = 'right';
337
393
  } else {
338
394
  horizontal = 'left';
@@ -363,10 +419,10 @@
363
419
  }
364
420
 
365
421
  widget.css({
366
- top: vertical === 'top' ? 'auto' : offset.top + element.outerHeight(),
367
- bottom: vertical === 'top' ? offset.top + element.outerHeight() : 'auto',
422
+ top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(),
423
+ bottom: vertical === 'top' ? position.top + element.outerHeight() : 'auto',
368
424
  left: horizontal === 'left' ? parent.css('padding-left') : 'auto',
369
- right: horizontal === 'left' ? 'auto' : parent.css('padding-right')
425
+ right: horizontal === 'left' ? 'auto' : parent.width() - element.outerWidth()
370
426
  });
371
427
  },
372
428
 
@@ -402,29 +458,23 @@
402
458
  widget.find('.datepicker-days thead').append(row);
403
459
  },
404
460
 
405
- isInDisabledDates = function (date) {
406
- if (!options.disabledDates) {
407
- return false;
408
- }
409
- return options.disabledDates[date.format('YYYY-MM-DD')] === true;
461
+ isInDisabledDates = function (testDate) {
462
+ return options.disabledDates[testDate.format('YYYY-MM-DD')] === true;
410
463
  },
411
464
 
412
- isInEnabledDates = function (date) {
413
- if (!options.enabledDates) {
414
- return false;
415
- }
416
- return options.enabledDates[date.format('YYYY-MM-DD')] === true;
465
+ isInEnabledDates = function (testDate) {
466
+ return options.enabledDates[testDate.format('YYYY-MM-DD')] === true;
417
467
  },
418
468
 
419
469
  isValid = function (targetMoment, granularity) {
420
470
  if (!targetMoment.isValid()) {
421
471
  return false;
422
472
  }
423
- if (options.disabledDates && isInDisabledDates(targetMoment)) {
473
+ if (options.disabledDates && isInDisabledDates(targetMoment) && granularity !== 'M') {
424
474
  return false;
425
475
  }
426
- if (options.enabledDates && isInEnabledDates(targetMoment)) {
427
- return true;
476
+ if (options.enabledDates && !isInEnabledDates(targetMoment) && granularity !== 'M') {
477
+ return false;
428
478
  }
429
479
  if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) {
430
480
  return false;
@@ -432,7 +482,7 @@
432
482
  if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) {
433
483
  return false;
434
484
  }
435
- if (granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
485
+ if (granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) { //widget && widget.find('.datepicker-days').length > 0
436
486
  return false;
437
487
  }
438
488
  return true;
@@ -680,7 +730,9 @@
680
730
  oldDate: oldDate
681
731
  });
682
732
  } else {
683
- input.val(unset ? '' : date.format(actualFormat));
733
+ if (!options.keepInvalid) {
734
+ input.val(unset ? '' : date.format(actualFormat));
735
+ }
684
736
  notifyEvent({
685
737
  type: 'dp.error',
686
738
  date: targetMoment
@@ -700,6 +752,7 @@
700
752
  transitioning = true;
701
753
  return false;
702
754
  }
755
+ return true;
703
756
  });
704
757
  if (transitioning) {
705
758
  return picker;
@@ -723,6 +776,10 @@
723
776
  return picker;
724
777
  },
725
778
 
779
+ clear = function () {
780
+ setValue(null);
781
+ },
782
+
726
783
  /********************************************************************************
727
784
  *
728
785
  * Widget UI interaction functions
@@ -748,10 +805,13 @@
748
805
  viewDate.month(month);
749
806
  if (currentViewMode === minViewModeNumber) {
750
807
  setValue(date.clone().year(viewDate.year()).month(viewDate.month()));
751
- hide();
808
+ if (!options.inline) {
809
+ hide();
810
+ }
811
+ } else {
812
+ showMode(-1);
813
+ fillDate();
752
814
  }
753
- showMode(-1);
754
- fillDate();
755
815
  },
756
816
 
757
817
  selectYear: function (e) {
@@ -759,10 +819,13 @@
759
819
  viewDate.year(year);
760
820
  if (currentViewMode === minViewModeNumber) {
761
821
  setValue(date.clone().year(viewDate.year()));
762
- hide();
822
+ if (!options.inline) {
823
+ hide();
824
+ }
825
+ } else {
826
+ showMode(-1);
827
+ fillDate();
763
828
  }
764
- showMode(-1);
765
- fillDate();
766
829
  },
767
830
 
768
831
  selectDay: function (e) {
@@ -774,7 +837,7 @@
774
837
  day.add(1, 'M');
775
838
  }
776
839
  setValue(day.date(parseInt($(e.target).text(), 10)));
777
- if (!hasTime() && !options.keepOpen) {
840
+ if (!hasTime() && !options.keepOpen && !options.inline) {
778
841
  hide();
779
842
  }
780
843
  },
@@ -819,8 +882,13 @@
819
882
  if (collapseData && collapseData.transitioning) {
820
883
  return;
821
884
  }
822
- expanded.collapse('hide');
823
- closed.collapse('show');
885
+ if (expanded.collapse) { // if collapse plugin is available through bootstrap.js then use it
886
+ expanded.collapse('hide');
887
+ closed.collapse('show');
888
+ } else { // otherwise just toggle in class on the two views
889
+ expanded.removeClass('in');
890
+ closed.addClass('in');
891
+ }
824
892
  if ($this.is('span')) {
825
893
  $this.toggleClass(options.icons.time + ' ' + options.icons.date);
826
894
  } else {
@@ -882,13 +950,13 @@
882
950
  actions.showPicker.call(picker);
883
951
  },
884
952
 
885
- clear: function () {
886
- setValue(null);
887
- },
953
+ clear: clear,
888
954
 
889
955
  today: function () {
890
956
  setValue(moment());
891
- }
957
+ },
958
+
959
+ close: hide
892
960
  },
893
961
 
894
962
  doAction = function (e) {
@@ -919,10 +987,10 @@
919
987
  }
920
988
  };
921
989
 
922
- if (input.prop('disabled') || input.prop('readonly') || widget) {
990
+ if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) {
923
991
  return picker;
924
992
  }
925
- if (options.useCurrent && unset) { // && input.val().trim().length !== 0) { this broke the jasmine test
993
+ if (options.useCurrent && unset && ((input.is('input') && input.val().trim().length === 0) || options.inline)) {
926
994
  currentMoment = moment();
927
995
  if (typeof options.useCurrent === 'string') {
928
996
  currentMoment = useCurrentGranularity[options.useCurrent](currentMoment);
@@ -966,22 +1034,80 @@
966
1034
  return (widget ? hide() : show());
967
1035
  },
968
1036
 
969
- parseInputDate = function (date) {
970
- if (moment.isMoment(date) || date instanceof Date) {
971
- date = moment(date);
1037
+ parseInputDate = function (inputDate) {
1038
+ if (moment.isMoment(inputDate) || inputDate instanceof Date) {
1039
+ inputDate = moment(inputDate);
972
1040
  } else {
973
- date = moment(date, parseFormats, options.useStrict);
1041
+ inputDate = moment(inputDate, parseFormats, options.useStrict);
974
1042
  }
975
- date.locale(options.locale);
976
- return date;
1043
+ inputDate.locale(options.locale);
1044
+ return inputDate;
977
1045
  },
978
1046
 
979
1047
  keydown = function (e) {
980
- if (e.keyCode === 27) { // allow escape to hide picker
981
- hide();
1048
+ //if (e.keyCode === 27 && widget) { // allow escape to hide picker
1049
+ // hide();
1050
+ // return false;
1051
+ //}
1052
+ //if (e.keyCode === 40 && !widget) { // allow down to show picker
1053
+ // show();
1054
+ // e.preventDefault();
1055
+ //}
1056
+ //return true;
1057
+
1058
+ var handler = null,
1059
+ index,
1060
+ index2,
1061
+ pressedKeys = [],
1062
+ pressedModifiers = {},
1063
+ currentKey = e.which,
1064
+ keyBindKeys,
1065
+ allModifiersPressed,
1066
+ pressed = 'p';
1067
+
1068
+ keyState[currentKey] = pressed;
1069
+
1070
+ for (index in keyState) {
1071
+ if (keyState.hasOwnProperty(index) && keyState[index] === pressed) {
1072
+ pressedKeys.push(index);
1073
+ if (parseInt(index, 10) !== currentKey) {
1074
+ pressedModifiers[index] = true;
1075
+ }
1076
+ }
1077
+ }
1078
+
1079
+ for (index in options.keyBinds) {
1080
+ if (options.keyBinds.hasOwnProperty(index) && typeof (options.keyBinds[index]) === 'function') {
1081
+ keyBindKeys = index.split(' ');
1082
+ if (keyBindKeys.length === pressedKeys.length && keyMap[currentKey] === keyBindKeys[keyBindKeys.length - 1]) {
1083
+ allModifiersPressed = true;
1084
+ for (index2 = keyBindKeys.length - 2; index2 >= 0; index2--) {
1085
+ if (!(keyMap[keyBindKeys[index2]] in pressedModifiers)) {
1086
+ allModifiersPressed = false;
1087
+ break;
1088
+ }
1089
+ }
1090
+ if (allModifiersPressed) {
1091
+ handler = options.keyBinds[index];
1092
+ break;
1093
+ }
1094
+ }
1095
+ }
1096
+ }
1097
+
1098
+ if (handler) {
1099
+ handler.call(picker, widget);
1100
+ e.stopPropagation();
1101
+ e.preventDefault();
982
1102
  }
983
1103
  },
984
1104
 
1105
+ keyup = function (e) {
1106
+ keyState[e.which] = 'r';
1107
+ e.stopPropagation();
1108
+ e.preventDefault();
1109
+ },
1110
+
985
1111
  change = function (e) {
986
1112
  var val = $(e.target).val().trim(),
987
1113
  parsedDate = val ? parseInputDate(val) : null;
@@ -993,8 +1119,9 @@
993
1119
  attachDatePickerElementEvents = function () {
994
1120
  input.on({
995
1121
  'change': change,
996
- 'blur': hide,
997
- 'keydown': keydown
1122
+ 'blur': options.debug ? '' : hide,
1123
+ 'keydown': keydown,
1124
+ 'keyup': keyup
998
1125
  });
999
1126
 
1000
1127
  if (element.is('input')) {
@@ -1011,7 +1138,8 @@
1011
1138
  input.off({
1012
1139
  'change': change,
1013
1140
  'blur': hide,
1014
- 'keydown': keydown
1141
+ 'keydown': keydown,
1142
+ 'keyup': keyup
1015
1143
  });
1016
1144
 
1017
1145
  if (element.is('input')) {
@@ -1041,10 +1169,14 @@
1041
1169
  initFormatting = function () {
1042
1170
  var format = options.format || 'L LT';
1043
1171
 
1044
- actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (input) {
1045
- return date.localeData().longDateFormat(input) || input;
1172
+ actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput) {
1173
+ var newinput = date.localeData().longDateFormat(formatInput) || formatInput;
1174
+ return newinput.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput2) { //temp fix for #740
1175
+ return date.localeData().longDateFormat(formatInput2) || formatInput2;
1176
+ });
1046
1177
  });
1047
1178
 
1179
+
1048
1180
  parseFormats = options.extraFormats ? options.extraFormats.slice() : [];
1049
1181
  if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) {
1050
1182
  parseFormats.push(actualFormat);
@@ -1109,6 +1241,17 @@
1109
1241
  return picker;
1110
1242
  };
1111
1243
 
1244
+ picker.ignoreReadonly = function (ignoreReadonly) {
1245
+ if (arguments.length === 0) {
1246
+ return options.ignoreReadonly;
1247
+ }
1248
+ if (typeof ignoreReadonly !== 'boolean') {
1249
+ throw new TypeError('ignoreReadonly () expects a boolean parameter');
1250
+ }
1251
+ options.ignoreReadonly = ignoreReadonly;
1252
+ return picker;
1253
+ };
1254
+
1112
1255
  picker.options = function (newOptions) {
1113
1256
  if (arguments.length === 0) {
1114
1257
  return $.extend(true, {}, options);
@@ -1249,56 +1392,74 @@
1249
1392
  return picker;
1250
1393
  };
1251
1394
 
1252
- picker.maxDate = function (date) {
1395
+ picker.maxDate = function (maxDate) {
1253
1396
  if (arguments.length === 0) {
1254
1397
  return options.maxDate ? options.maxDate.clone() : options.maxDate;
1255
1398
  }
1256
1399
 
1257
- if ((typeof date === 'boolean') && date === false) {
1400
+ if ((typeof maxDate === 'boolean') && maxDate === false) {
1258
1401
  options.maxDate = false;
1259
1402
  update();
1260
1403
  return picker;
1261
1404
  }
1262
1405
 
1263
- var parsedDate = parseInputDate(date);
1406
+ if (typeof maxDate === 'string') {
1407
+ if (maxDate === 'now' || maxDate === 'moment') {
1408
+ maxDate = moment();
1409
+ }
1410
+ }
1411
+
1412
+ var parsedDate = parseInputDate(maxDate);
1264
1413
 
1265
1414
  if (!parsedDate.isValid()) {
1266
- throw new TypeError('maxDate() Could not parse date parameter: ' + date);
1415
+ throw new TypeError('maxDate() Could not parse date parameter: ' + maxDate);
1267
1416
  }
1268
1417
  if (options.minDate && parsedDate.isBefore(options.minDate)) {
1269
1418
  throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat));
1270
1419
  }
1271
1420
  options.maxDate = parsedDate;
1272
- if (options.maxDate.isBefore(date)) {
1421
+ if (options.maxDate.isBefore(maxDate)) {
1273
1422
  setValue(options.maxDate);
1274
1423
  }
1424
+ if (viewDate.isAfter(parsedDate)) {
1425
+ viewDate = parsedDate.clone();
1426
+ }
1275
1427
  update();
1276
1428
  return picker;
1277
1429
  };
1278
1430
 
1279
- picker.minDate = function (date) {
1431
+ picker.minDate = function (minDate) {
1280
1432
  if (arguments.length === 0) {
1281
1433
  return options.minDate ? options.minDate.clone() : options.minDate;
1282
1434
  }
1283
1435
 
1284
- if ((typeof date === 'boolean') && date === false) {
1436
+ if ((typeof minDate === 'boolean') && minDate === false) {
1285
1437
  options.minDate = false;
1286
1438
  update();
1287
1439
  return picker;
1288
1440
  }
1289
1441
 
1290
- var parsedDate = parseInputDate(date);
1442
+ if (typeof minDate === 'string') {
1443
+ if (minDate === 'now' || minDate === 'moment') {
1444
+ minDate = moment();
1445
+ }
1446
+ }
1447
+
1448
+ var parsedDate = parseInputDate(minDate);
1291
1449
 
1292
1450
  if (!parsedDate.isValid()) {
1293
- throw new TypeError('minDate() Could not parse date parameter: ' + date);
1451
+ throw new TypeError('minDate() Could not parse date parameter: ' + minDate);
1294
1452
  }
1295
1453
  if (options.maxDate && parsedDate.isAfter(options.maxDate)) {
1296
1454
  throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat));
1297
1455
  }
1298
1456
  options.minDate = parsedDate;
1299
- if (options.minDate.isAfter(date)) {
1457
+ if (options.minDate.isAfter(minDate)) {
1300
1458
  setValue(options.minDate);
1301
1459
  }
1460
+ if (viewDate.isBefore(parsedDate)) {
1461
+ viewDate = parsedDate.clone();
1462
+ }
1302
1463
  update();
1303
1464
  return picker;
1304
1465
  };
@@ -1311,6 +1472,13 @@
1311
1472
  options.defaultDate = false;
1312
1473
  return picker;
1313
1474
  }
1475
+
1476
+ if (typeof defaultDate === 'string') {
1477
+ if (defaultDate === 'now' || defaultDate === 'moment') {
1478
+ defaultDate = moment();
1479
+ }
1480
+ }
1481
+
1314
1482
  var parsedDate = parseInputDate(defaultDate);
1315
1483
  if (!parsedDate.isValid()) {
1316
1484
  throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate);
@@ -1321,7 +1489,7 @@
1321
1489
 
1322
1490
  options.defaultDate = parsedDate;
1323
1491
 
1324
- if (options.defaultDate && input.val().trim() === '') {
1492
+ if (options.defaultDate && input.val().trim() === '' && input.attr('placeholder') === undefined) {
1325
1493
  setValue(options.defaultDate);
1326
1494
  }
1327
1495
  return picker;
@@ -1442,21 +1610,21 @@
1442
1610
  return picker;
1443
1611
  };
1444
1612
 
1445
- picker.viewMode = function (newViewMode) {
1613
+ picker.viewMode = function (viewMode) {
1446
1614
  if (arguments.length === 0) {
1447
1615
  return options.viewMode;
1448
1616
  }
1449
1617
 
1450
- if (typeof newViewMode !== 'string') {
1618
+ if (typeof viewMode !== 'string') {
1451
1619
  throw new TypeError('viewMode() expects a string parameter');
1452
1620
  }
1453
1621
 
1454
- if (viewModes.indexOf(newViewMode) === -1) {
1622
+ if (viewModes.indexOf(viewMode) === -1) {
1455
1623
  throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value');
1456
1624
  }
1457
1625
 
1458
- options.viewMode = newViewMode;
1459
- currentViewMode = Math.max(viewModes.indexOf(newViewMode), minViewModeNumber);
1626
+ options.viewMode = viewMode;
1627
+ currentViewMode = Math.max(viewModes.indexOf(viewMode), minViewModeNumber);
1460
1628
 
1461
1629
  showMode();
1462
1630
  return picker;
@@ -1514,16 +1682,16 @@
1514
1682
  return picker;
1515
1683
  };
1516
1684
 
1517
- picker.calendarWeeks = function (showCalendarWeeks) {
1685
+ picker.calendarWeeks = function (calendarWeeks) {
1518
1686
  if (arguments.length === 0) {
1519
1687
  return options.calendarWeeks;
1520
1688
  }
1521
1689
 
1522
- if (typeof showCalendarWeeks !== 'boolean') {
1690
+ if (typeof calendarWeeks !== 'boolean') {
1523
1691
  throw new TypeError('calendarWeeks() expects parameter to be a boolean value');
1524
1692
  }
1525
1693
 
1526
- options.calendarWeeks = showCalendarWeeks;
1694
+ options.calendarWeeks = calendarWeeks;
1527
1695
  update();
1528
1696
  return picker;
1529
1697
  };
@@ -1571,7 +1739,7 @@
1571
1739
  widgetParent = $(widgetParent);
1572
1740
  }
1573
1741
 
1574
- if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof jQuery))) {
1742
+ if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof $))) {
1575
1743
  throw new TypeError('widgetParent() expects a string or a jQuery object parameter');
1576
1744
  }
1577
1745
 
@@ -1585,7 +1753,7 @@
1585
1753
 
1586
1754
  picker.keepOpen = function (keepOpen) {
1587
1755
  if (arguments.length === 0) {
1588
- return options.format;
1756
+ return options.keepOpen;
1589
1757
  }
1590
1758
 
1591
1759
  if (typeof keepOpen !== 'boolean') {
@@ -1596,15 +1764,85 @@
1596
1764
  return picker;
1597
1765
  };
1598
1766
 
1767
+ picker.inline = function (inline) {
1768
+ if (arguments.length === 0) {
1769
+ return options.inline;
1770
+ }
1771
+
1772
+ if (typeof inline !== 'boolean') {
1773
+ throw new TypeError('inline() expects a boolean parameter');
1774
+ }
1775
+
1776
+ options.inline = inline;
1777
+ return picker;
1778
+ };
1779
+
1780
+ picker.clear = function () {
1781
+ clear();
1782
+ return picker;
1783
+ };
1784
+
1785
+ picker.keyBinds = function (keyBinds) {
1786
+ options.keyBinds = keyBinds;
1787
+ return picker;
1788
+ };
1789
+
1790
+ picker.debug = function (debug) {
1791
+ if (typeof debug !== 'boolean') {
1792
+ throw new TypeError('debug() expects a boolean parameter');
1793
+ }
1794
+
1795
+ options.debug = debug;
1796
+ return picker;
1797
+ };
1798
+
1799
+ picker.showClose = function (showClose) {
1800
+ if (arguments.length === 0) {
1801
+ return options.showClose;
1802
+ }
1803
+
1804
+ if (typeof showClose !== 'boolean') {
1805
+ throw new TypeError('showClose() expects a boolean parameter');
1806
+ }
1807
+
1808
+ options.showClose = showClose;
1809
+ return picker;
1810
+ };
1811
+
1812
+ picker.keepInvalid = function (keepInvalid) {
1813
+ if (arguments.length === 0) {
1814
+ return options.keepInvalid;
1815
+ }
1816
+
1817
+ if (typeof keepInvalid !== 'boolean') {
1818
+ throw new TypeError('keepInvalid() expects a boolean parameter');
1819
+ }
1820
+ options.keepInvalid = keepInvalid;
1821
+ return picker;
1822
+ };
1823
+
1824
+ picker.datepickerInput = function (datepickerInput) {
1825
+ if (arguments.length === 0) {
1826
+ return options.datepickerInput;
1827
+ }
1828
+
1829
+ if (typeof datepickerInput !== 'string') {
1830
+ throw new TypeError('datepickerInput() expects a string parameter');
1831
+ }
1832
+
1833
+ options.datepickerInput = datepickerInput;
1834
+ return picker;
1835
+ };
1836
+
1599
1837
  // initializing element and component attributes
1600
1838
  if (element.is('input')) {
1601
1839
  input = element;
1602
1840
  } else {
1603
- input = element.find('.datepickerinput');
1841
+ input = element.find(options.datepickerInput);
1604
1842
  if (input.size() === 0) {
1605
1843
  input = element.find('input');
1606
1844
  } else if (!input.is('input')) {
1607
- throw new Error('CSS class "datepickerinput" cannot be applied to non input element');
1845
+ throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element');
1608
1846
  }
1609
1847
  }
1610
1848
 
@@ -1617,7 +1855,7 @@
1617
1855
  }
1618
1856
  }
1619
1857
 
1620
- if (!input.is('input')) {
1858
+ if (!options.inline && !input.is('input')) {
1621
1859
  throw new Error('Could not initialize DateTimePicker without an input element');
1622
1860
  }
1623
1861
 
@@ -1632,13 +1870,15 @@
1632
1870
  if (input.prop('disabled')) {
1633
1871
  picker.disable();
1634
1872
  }
1635
-
1636
- if (input.val().trim().length !== 0) {
1873
+ if (input.is('input') && input.val().trim().length !== 0) {
1637
1874
  setValue(parseInputDate(input.val().trim()));
1638
- } else if (options.defaultDate) {
1875
+ }
1876
+ else if (options.defaultDate && input.attr('placeholder') === undefined) {
1639
1877
  setValue(options.defaultDate);
1640
1878
  }
1641
-
1879
+ if (options.inline) {
1880
+ show();
1881
+ }
1642
1882
  return picker;
1643
1883
  };
1644
1884
 
@@ -1680,7 +1920,8 @@
1680
1920
  previous: 'glyphicon glyphicon-chevron-left',
1681
1921
  next: 'glyphicon glyphicon-chevron-right',
1682
1922
  today: 'glyphicon glyphicon-screenshot',
1683
- clear: 'glyphicon glyphicon-trash'
1923
+ clear: 'glyphicon glyphicon-trash',
1924
+ close: 'glyphicon glyphicon-remove'
1684
1925
  },
1685
1926
  useStrict: false,
1686
1927
  sideBySide: false,
@@ -1690,11 +1931,121 @@
1690
1931
  toolbarPlacement: 'default',
1691
1932
  showTodayButton: false,
1692
1933
  showClear: false,
1934
+ showClose: false,
1693
1935
  widgetPositioning: {
1694
1936
  horizontal: 'auto',
1695
1937
  vertical: 'auto'
1696
1938
  },
1697
1939
  widgetParent: null,
1698
- keepOpen: false
1940
+ ignoreReadonly: false,
1941
+ keepOpen: false,
1942
+ inline: false,
1943
+ keepInvalid: false,
1944
+ datepickerInput: '.datepickerinput',
1945
+ keyBinds: {
1946
+ up: function (widget) {
1947
+ if (!widget) {
1948
+ return;
1949
+ }
1950
+ var d = this.date() || moment();
1951
+ if (widget.find('.datepicker').is(':visible')) {
1952
+ this.date(d.clone().subtract(7, 'd'));
1953
+ } else {
1954
+ this.date(d.clone().add(1, 'm'));
1955
+ }
1956
+ },
1957
+ down: function (widget) {
1958
+ if (!widget) {
1959
+ this.show();
1960
+ return;
1961
+ }
1962
+ var d = this.date() || moment();
1963
+ if (widget.find('.datepicker').is(':visible')) {
1964
+ this.date(d.clone().add(7, 'd'));
1965
+ } else {
1966
+ this.date(d.clone().subtract(1, 'm'));
1967
+ }
1968
+ },
1969
+ 'control up': function (widget) {
1970
+ if (!widget) {
1971
+ return;
1972
+ }
1973
+ var d = this.date() || moment();
1974
+ if (widget.find('.datepicker').is(':visible')) {
1975
+ this.date(d.clone().subtract(1, 'y'));
1976
+ } else {
1977
+ this.date(d.clone().add(1, 'h'));
1978
+ }
1979
+ },
1980
+ 'control down': function (widget) {
1981
+ if (!widget) {
1982
+ return;
1983
+ }
1984
+ var d = this.date() || moment();
1985
+ if (widget.find('.datepicker').is(':visible')) {
1986
+ this.date(d.clone().add(1, 'y'));
1987
+ } else {
1988
+ this.date(d.clone().subtract(1, 'h'));
1989
+ }
1990
+ },
1991
+ left: function (widget) {
1992
+ if (!widget) {
1993
+ return;
1994
+ }
1995
+ var d = this.date() || moment();
1996
+ if (widget.find('.datepicker').is(':visible')) {
1997
+ this.date(d.clone().subtract(1, 'd'));
1998
+ }
1999
+ },
2000
+ right: function (widget) {
2001
+ if (!widget) {
2002
+ return;
2003
+ }
2004
+ var d = this.date() || moment();
2005
+ if (widget.find('.datepicker').is(':visible')) {
2006
+ this.date(d.clone().add(1, 'd'));
2007
+ }
2008
+ },
2009
+ pageUp: function (widget) {
2010
+ if (!widget) {
2011
+ return;
2012
+ }
2013
+ var d = this.date() || moment();
2014
+ if (widget.find('.datepicker').is(':visible')) {
2015
+ this.date(d.clone().subtract(1, 'M'));
2016
+ }
2017
+ },
2018
+ pageDown: function (widget) {
2019
+ if (!widget) {
2020
+ return;
2021
+ }
2022
+ var d = this.date() || moment();
2023
+ if (widget.find('.datepicker').is(':visible')) {
2024
+ this.date(d.clone().add(1, 'M'));
2025
+ }
2026
+ },
2027
+ enter: function () {
2028
+ this.hide();
2029
+ },
2030
+ escape: function () {
2031
+ this.hide();
2032
+ },
2033
+ //tab: function (widget) { //this break the flow of the form. disabling for now
2034
+ // var toggle = widget.find('.picker-switch a[data-action="togglePicker"]');
2035
+ // if(toggle.length > 0) toggle.click();
2036
+ //},
2037
+ 'control space': function (widget) {
2038
+ if (widget.find('.timepicker').is(':visible')) {
2039
+ widget.find('.btn[data-action="togglePeriod"]').click();
2040
+ }
2041
+ },
2042
+ t: function () {
2043
+ this.date(moment());
2044
+ },
2045
+ 'delete': function () {
2046
+ this.clear();
2047
+ }
2048
+ },
2049
+ debug: false
1699
2050
  };
1700
2051
  }));