xdan-datetimepicker-rails 2.5.1 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @preserve jQuery DateTimePicker plugin v2.5.1
2
+ * @preserve jQuery DateTimePicker plugin v2.5.2
3
3
  * @homepage http://xdsoft.net/jqplugins/datetimepicker/
4
4
  * @author Chupurnov Valeriy (<chupurnov@gmail.com>)
5
5
  */
@@ -515,6 +515,15 @@
515
515
  "Dumengia", "Glindesdi", "Mardi", "Mesemna", "Gievgia", "Venderdi", "Sonda"
516
516
  ]
517
517
  },
518
+ ka: { // Georgian
519
+ months: [
520
+ 'იანვარი', 'თებერვალი', 'მარტი', 'აპრილი', 'მაისი', 'ივნისი', 'ივლისი', 'აგვისტო', 'სექტემბერი', 'ოქტომბერი', 'ნოემბერი', 'დეკემბერი'
521
+ ],
522
+ dayOfWeekShort: [
523
+ "კვ", "ორშ", "სამშ", "ოთხ", "ხუთ", "პარ", "შაბ"
524
+ ],
525
+ dayOfWeek: ["კვირა", "ორშაბათი", "სამშაბათი", "ოთხშაბათი", "ხუთშაბათი", "პარასკევი", "შაბათი"]
526
+ },
518
527
  },
519
528
  value: '',
520
529
  rtl: false,
@@ -604,31 +613,31 @@
604
613
  beforeShowDay: null,
605
614
 
606
615
  enterLikeTab: true,
607
- showApplyButton: false
616
+ showApplyButton: false
608
617
  };
609
618
 
610
619
  var dateHelper = null,
611
620
  globalLocaleDefault = 'en',
612
621
  globalLocale = 'en';
613
-
622
+
614
623
  var dateFormatterOptionsDefault = {
615
624
  meridiem: ['AM', 'PM']
616
625
  };
617
-
626
+
618
627
  var initDateFormatter = function(){
619
628
  var locale = default_options.i18n[globalLocale],
620
629
  opts = {
621
630
  days: locale.dayOfWeek,
622
631
  daysShort: locale.dayOfWeekShort,
623
632
  months: locale.months,
624
- monthsShort: $.map(locale.months, function(n){ return n.substring(0, 3) }),
633
+ monthsShort: $.map(locale.months, function(n){ return n.substring(0, 3) }),
625
634
  };
626
-
635
+
627
636
  dateHelper = new DateFormatter({
628
637
  dateSettings: $.extend({}, dateFormatterOptionsDefault, opts)
629
638
  });
630
639
  };
631
-
640
+
632
641
  // for locale settings
633
642
  $.datetimepicker = {
634
643
  setLocale: function(locale){
@@ -639,6 +648,9 @@
639
648
  initDateFormatter();
640
649
  }
641
650
  },
651
+ setDateFormatter: function(dateFormatter) {
652
+ dateHelper = dateFormatter;
653
+ },
642
654
  RFC_2822: 'D, d M Y H:i:s O',
643
655
  ATOM: 'Y-m-d\TH:i:sP',
644
656
  ISO_8601: 'Y-m-d\TH:i:sO',
@@ -649,7 +661,7 @@
649
661
  RSS: 'D, d M Y H:i:s O',
650
662
  W3C: 'Y-m-d\TH:i:sP'
651
663
  };
652
-
664
+
653
665
  // first init date formatter
654
666
  initDateFormatter();
655
667
 
@@ -700,7 +712,6 @@
700
712
  }
701
713
  return out;
702
714
  },
703
- move = 0,
704
715
  timebox,
705
716
  parentHeight,
706
717
  height,
@@ -770,7 +781,7 @@
770
781
  calcOffset(event);
771
782
  }
772
783
  })
773
- .on('touchend touchcancel', function (event) {
784
+ .on('touchend touchcancel', function () {
774
785
  touchStart = false;
775
786
  startTopScroll = 0;
776
787
  });
@@ -832,7 +843,7 @@
832
843
  }
833
844
  });
834
845
 
835
- timeboxparent.on('touchend touchcancel', function (event) {
846
+ timeboxparent.on('touchend touchcancel', function () {
836
847
  start = false;
837
848
  startTop = 0;
838
849
  });
@@ -843,7 +854,7 @@
843
854
 
844
855
  $.fn.datetimepicker = function (opt, opt2) {
845
856
  var result = this,
846
- KEY0 = 48,
857
+ KEY0 = 48,
847
858
  KEY9 = 57,
848
859
  _KEY0 = 96,
849
860
  _KEY9 = 105,
@@ -872,7 +883,7 @@
872
883
 
873
884
  lazyInit = function (input) {
874
885
  input
875
- .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function initOnActionCallback(event) {
886
+ .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function initOnActionCallback() {
876
887
  if (input.is(':disabled') || input.data('xdsoft_datetimepicker')) {
877
888
  return;
878
889
  }
@@ -901,20 +912,20 @@
901
912
  timepicker = $('<div class="xdsoft_timepicker active"><button type="button" class="xdsoft_prev"></button><div class="xdsoft_time_box"></div><button type="button" class="xdsoft_next"></button></div>'),
902
913
  timeboxparent = timepicker.find('.xdsoft_time_box').eq(0),
903
914
  timebox = $('<div class="xdsoft_time_variant"></div>'),
904
- applyButton = $('<button type="button" class="xdsoft_save_selected blue-gradient-button">Save Selected</button>'),
915
+ applyButton = $('<button type="button" class="xdsoft_save_selected blue-gradient-button">Save Selected</button>'),
905
916
 
906
917
  monthselect = $('<div class="xdsoft_select xdsoft_monthselect"><div></div></div>'),
907
918
  yearselect = $('<div class="xdsoft_select xdsoft_yearselect"><div></div></div>'),
908
919
  triggerAfterOpen = false,
909
920
  XDSoft_datetime,
910
-
921
+
911
922
  xchangeTimer,
912
923
  timerclick,
913
924
  current_time_index,
914
925
  setPos,
915
926
  timer = 0,
916
- timer1 = 0,
917
- _xdsoft_datetime;
927
+ _xdsoft_datetime,
928
+ forEachAncestorOf;
918
929
 
919
930
  if (options.id) {
920
931
  datetimepicker.attr('id', options.id);
@@ -977,7 +988,7 @@
977
988
  event.stopPropagation();
978
989
  event.preventDefault();
979
990
  })
980
- .on('touchstart mousedown.xdsoft', '.xdsoft_option', function (event) {
991
+ .on('touchstart mousedown.xdsoft', '.xdsoft_option', function () {
981
992
  if (_xdsoft_datetime.currentTime === undefined || _xdsoft_datetime.currentTime === null) {
982
993
  _xdsoft_datetime.currentTime = _xdsoft_datetime.now();
983
994
  }
@@ -1000,52 +1011,12 @@
1000
1011
  });
1001
1012
 
1002
1013
  datetimepicker.getValue = function () {
1003
- return _xdsoft_datetime.getCurrentTime();
1004
- };
1014
+ return _xdsoft_datetime.getCurrentTime();
1015
+ };
1005
1016
 
1006
1017
  datetimepicker.setOptions = function (_options) {
1007
- var highlightedDates = {},
1008
- getCaretPos = function (input) {
1009
- try {
1010
- if (document.selection && document.selection.createRange) {
1011
- var range = document.selection.createRange();
1012
- return range.getBookmark().charCodeAt(2) - 2;
1013
- }
1014
- if (input.setSelectionRange) {
1015
- return input.selectionStart;
1016
- }
1017
- } catch (e) {
1018
- return 0;
1019
- }
1020
- },
1021
- setCaretPos = function (node, pos) {
1022
- node = (typeof node === "string" || node instanceof String) ? document.getElementById(node) : node;
1023
- if (!node) {
1024
- return false;
1025
- }
1026
- if (node.createTextRange) {
1027
- var textRange = node.createTextRange();
1028
- textRange.collapse(true);
1029
- textRange.moveEnd('character', pos);
1030
- textRange.moveStart('character', pos);
1031
- textRange.select();
1032
- return true;
1033
- }
1034
- if (node.setSelectionRange) {
1035
- node.setSelectionRange(pos, pos);
1036
- return true;
1037
- }
1038
- return false;
1039
- },
1040
- isValidValue = function (mask, value) {
1041
- var reg = mask
1042
- .replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g, '\\$1')
1043
- .replace(/_/g, '{digit+}')
1044
- .replace(/([0-9]{1})/g, '{digit$1}')
1045
- .replace(/\{digit([0-9]{1})\}/g, '[0-$1_]{1}')
1046
- .replace(/\{digit[\+]\}/g, '[0-9_]{1}');
1047
- return (new RegExp(reg)).test(value);
1048
- };
1018
+ var highlightedDates = {};
1019
+
1049
1020
  options = $.extend(true, {}, options, _options);
1050
1021
 
1051
1022
  if (_options.allowTimes && $.isArray(_options.allowTimes) && _options.allowTimes.length) {
@@ -1063,7 +1034,7 @@
1063
1034
  if (_options.allowDateRe && Object.prototype.toString.call(_options.allowDateRe)==="[object String]") {
1064
1035
  options.allowDateRe = new RegExp(_options.allowDateRe);
1065
1036
  }
1066
-
1037
+
1067
1038
  if (_options.highlightedDates && $.isArray(_options.highlightedDates) && _options.highlightedDates.length) {
1068
1039
  $.each(_options.highlightedDates, function (index, value) {
1069
1040
  var splitData = $.map(value.split(','), $.trim),
@@ -1130,7 +1101,7 @@
1130
1101
  }
1131
1102
 
1132
1103
  if (_options.disabledWeekDays && $.isArray(_options.disabledWeekDays) && _options.disabledWeekDays.length) {
1133
- options.disabledWeekDays = $.extend(true, [], _options.disabledWeekDays);
1104
+ options.disabledWeekDays = $.extend(true, [], _options.disabledWeekDays);
1134
1105
  }
1135
1106
 
1136
1107
  if ((options.open || options.opened) && (!options.inline)) {
@@ -1199,84 +1170,13 @@
1199
1170
  .find('.' + options.next)
1200
1171
  .css('visibility', !options.nextButton ? 'hidden' : 'visible');
1201
1172
 
1202
- if (options.mask) {
1203
- input.off('keydown.xdsoft');
1204
-
1205
- if (options.mask === true) {
1206
- options.mask = options.format
1207
- .replace(/Y/g, '9999')
1208
- .replace(/F/g, '9999')
1209
- .replace(/m/g, '19')
1210
- .replace(/d/g, '39')
1211
- .replace(/H/g, '29')
1212
- .replace(/i/g, '59')
1213
- .replace(/s/g, '59');
1214
- }
1215
-
1216
- if ($.type(options.mask) === 'string') {
1217
- if (!isValidValue(options.mask, input.val())) {
1218
- input.val(options.mask.replace(/[0-9]/g, '_'));
1219
- setCaretPos(input[0], 0);
1220
- }
1221
-
1222
- input.on('keydown.xdsoft', function (event) {
1223
- var val = this.value,
1224
- key = event.which,
1225
- pos,
1226
- digit;
1227
-
1228
- if (((key >= KEY0 && key <= KEY9) || (key >= _KEY0 && key <= _KEY9)) || (key === BACKSPACE || key === DEL)) {
1229
- pos = getCaretPos(this);
1230
- digit = (key !== BACKSPACE && key !== DEL) ? String.fromCharCode((_KEY0 <= key && key <= _KEY9) ? key - KEY0 : key) : '_';
1231
-
1232
- if ((key === BACKSPACE || key === DEL) && pos) {
1233
- pos -= 1;
1234
- digit = '_';
1235
- }
1236
-
1237
- while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) {
1238
- pos += (key === BACKSPACE || key === DEL) ? -1 : 1;
1239
- }
1240
-
1241
- val = val.substr(0, pos) + digit + val.substr(pos + 1);
1242
- if ($.trim(val) === '') {
1243
- val = options.mask.replace(/[0-9]/g, '_');
1244
- } else {
1245
- if (pos === options.mask.length) {
1246
- event.preventDefault();
1247
- return false;
1248
- }
1249
- }
1250
-
1251
- pos += (key === BACKSPACE || key === DEL) ? 0 : 1;
1252
- while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) {
1253
- pos += (key === BACKSPACE || key === DEL) ? -1 : 1;
1254
- }
1255
-
1256
- if (isValidValue(options.mask, val)) {
1257
- this.value = val;
1258
- setCaretPos(this, pos);
1259
- } else if ($.trim(val) === '') {
1260
- this.value = options.mask.replace(/[0-9]/g, '_');
1261
- } else {
1262
- input.trigger('error_input.xdsoft');
1263
- }
1264
- } else {
1265
- if (([AKEY, CKEY, VKEY, ZKEY, YKEY].indexOf(key) !== -1 && ctrlDown) || [ESC, ARROWUP, ARROWDOWN, ARROWLEFT, ARROWRIGHT, F5, CTRLKEY, TAB, ENTER].indexOf(key) !== -1) {
1266
- return true;
1267
- }
1268
- }
1173
+ setMask(options);
1269
1174
 
1270
- event.preventDefault();
1271
- return false;
1272
- });
1273
- }
1274
- }
1275
1175
  if (options.validateOnBlur) {
1276
1176
  input
1277
1177
  .off('blur.xdsoft')
1278
1178
  .on('blur.xdsoft', function () {
1279
- if (options.allowBlank && !$.trim($(this).val()).length) {
1179
+ if (options.allowBlank && (!$.trim($(this).val()).length || (typeof options.mask == "string" && $.trim($(this).val()) === options.mask.replace(/[0-9]/g, '_')))) {
1280
1180
  $(this).val(null);
1281
1181
  datetimepicker.data('xdsoft_datetime').empty();
1282
1182
  } else if (!dateHelper.parseDate($(this).val(), options.format)) {
@@ -1298,6 +1198,7 @@
1298
1198
  }
1299
1199
 
1300
1200
  datetimepicker.trigger('changedatetime.xdsoft');
1201
+ datetimepicker.trigger('close.xdsoft');
1301
1202
  });
1302
1203
  }
1303
1204
  options.dayOfWeekStartPrev = (options.dayOfWeekStart === 0) ? 6 : options.dayOfWeekStart - 1;
@@ -1519,12 +1420,12 @@
1519
1420
  _xdsoft_datetime = new XDSoft_datetime();
1520
1421
 
1521
1422
  applyButton.on('touchend click', function (e) {//pathbrite
1522
- e.preventDefault();
1523
- datetimepicker.data('changed', true);
1524
- _xdsoft_datetime.setCurrentTime(getCurrentValue());
1525
- input.val(_xdsoft_datetime.str());
1526
- datetimepicker.trigger('close.xdsoft');
1527
- });
1423
+ e.preventDefault();
1424
+ datetimepicker.data('changed', true);
1425
+ _xdsoft_datetime.setCurrentTime(getCurrentValue());
1426
+ input.val(_xdsoft_datetime.str());
1427
+ datetimepicker.trigger('close.xdsoft');
1428
+ });
1528
1429
  mounth_picker
1529
1430
  .find('.xdsoft_today_button')
1530
1431
  .on('touchend mousedown.xdsoft', function () {
@@ -1591,7 +1492,20 @@
1591
1492
  } else if ($this.hasClass(options.prev) && top - options.timeHeightInTimePicker >= 0) {
1592
1493
  timebox.css('marginTop', '-' + (top - options.timeHeightInTimePicker) + 'px');
1593
1494
  }
1594
- timeboxparent.trigger('scroll_element.xdsoft_scroller', [Math.abs(parseInt(timebox.css('marginTop'), 10) / (height - pheight))]);
1495
+ /**
1496
+ * Fixed bug:
1497
+ * When using css3 transition, it will cause a bug that you cannot scroll the timepicker list.
1498
+ * The reason is that the transition-duration time, if you set it to 0, all things fine, otherwise, this
1499
+ * would cause a bug when you use jquery.css method.
1500
+ * Let's say: * { transition: all .5s ease; }
1501
+ * jquery timebox.css('marginTop') will return the original value which is before you clicking the next/prev button,
1502
+ * meanwhile the timebox[0].style.marginTop will return the right value which is after you clicking the
1503
+ * next/prev button.
1504
+ *
1505
+ * What we should do:
1506
+ * Replace timebox.css('marginTop') with timebox[0].style.marginTop.
1507
+ */
1508
+ timeboxparent.trigger('scroll_element.xdsoft_scroller', [Math.abs(parseInt(timebox[0].style.marginTop, 10) / (height - pheight))]);
1595
1509
  period = (period > 10) ? 10 : period - 10;
1596
1510
  if (!stop) {
1597
1511
  timer = setTimeout(arguments_callee4, v || period);
@@ -1684,11 +1598,11 @@
1684
1598
  }
1685
1599
 
1686
1600
  if(options.allowDateRe && Object.prototype.toString.call(options.allowDateRe) === "[object RegExp]"){
1687
- if(!options.allowDateRe.test(start.dateFormat(options.formatDate))){
1601
+ if(!options.allowDateRe.test(dateHelper.formatDate(start, options.formatDate))){
1688
1602
  classes.push('xdsoft_disabled');
1689
1603
  }
1690
1604
  } else if(options.allowDates && options.allowDates.length>0){
1691
- if(options.allowDates.indexOf(start.dateFormat(options.formatDate)) === -1){
1605
+ if(options.allowDates.indexOf(dateHelper.formatDate(start, options.formatDate)) === -1){
1692
1606
  classes.push('xdsoft_disabled');
1693
1607
  }
1694
1608
  } else if ((maxDate !== false && start > maxDate) || (minDate !== false && start < minDate) || (customDateSettings && customDateSettings[0] === false)) {
@@ -1696,7 +1610,9 @@
1696
1610
  } else if (options.disabledDates.indexOf(dateHelper.formatDate(start, options.formatDate)) !== -1) {
1697
1611
  classes.push('xdsoft_disabled');
1698
1612
  } else if (options.disabledWeekDays.indexOf(day) !== -1) {
1699
- classes.push('xdsoft_disabled');
1613
+ classes.push('xdsoft_disabled');
1614
+ }else if (input.is('[readonly]')) {
1615
+ classes.push('xdsoft_disabled');
1700
1616
  }
1701
1617
 
1702
1618
  if (customDateSettings && customDateSettings[1] !== "") {
@@ -1770,11 +1686,12 @@
1770
1686
  optionDateTime = new Date(_xdsoft_datetime.currentTime);
1771
1687
  optionDateTime.setHours(h);
1772
1688
  optionDateTime.setMinutes(m);
1773
- classes = [];
1689
+ classes = [];
1774
1690
  if ((options.minDateTime !== false && options.minDateTime > optionDateTime) || (options.maxTime !== false && _xdsoft_datetime.strtotime(options.maxTime).getTime() < now.getTime()) || (options.minTime !== false && _xdsoft_datetime.strtotime(options.minTime).getTime() > now.getTime())) {
1775
1691
  classes.push('xdsoft_disabled');
1776
- }
1777
- if ((options.minDateTime !== false && options.minDateTime > optionDateTime) || ((options.disabledMinTime !== false && now.getTime() > _xdsoft_datetime.strtotime(options.disabledMinTime).getTime()) && (options.disabledMaxTime !== false && now.getTime() < _xdsoft_datetime.strtotime(options.disabledMaxTime).getTime()))) {
1692
+ } else if ((options.minDateTime !== false && options.minDateTime > optionDateTime) || ((options.disabledMinTime !== false && now.getTime() > _xdsoft_datetime.strtotime(options.disabledMinTime).getTime()) && (options.disabledMaxTime !== false && now.getTime() < _xdsoft_datetime.strtotime(options.disabledMaxTime).getTime()))) {
1693
+ classes.push('xdsoft_disabled');
1694
+ } else if (input.is('[readonly]')) {
1778
1695
  classes.push('xdsoft_disabled');
1779
1696
  }
1780
1697
 
@@ -1928,7 +1845,6 @@
1928
1845
  }
1929
1846
  });
1930
1847
 
1931
-
1932
1848
  datepicker
1933
1849
  .on('mousewheel.xdsoft', function (event) {
1934
1850
  if (!options.scrollMonth) {
@@ -1991,59 +1907,131 @@
1991
1907
 
1992
1908
  current_time_index = 0;
1993
1909
 
1910
+ /**
1911
+ * Runs the callback for each of the specified node's ancestors.
1912
+ *
1913
+ * Return FALSE from the callback to stop ascending.
1914
+ *
1915
+ * @param {DOMNode} node
1916
+ * @param {Function} callback
1917
+ * @returns {undefined}
1918
+ */
1919
+ forEachAncestorOf = function (node, callback) {
1920
+ do {
1921
+ node = node.parentNode;
1922
+
1923
+ if (callback(node) === false) {
1924
+ break;
1925
+ }
1926
+ } while (node.nodeName !== 'HTML');
1927
+ };
1928
+
1929
+ /**
1930
+ * Sets the position of the picker.
1931
+ *
1932
+ * @returns {undefined}
1933
+ */
1994
1934
  setPos = function () {
1995
- /**
1996
- * 修复输入框在window最右边,且输入框的宽度小于日期控件宽度情况下,日期控件显示不全的bug。
1997
- * Bug fixed - The datetimepicker will overflow-y when the width of the date input less than its, which
1998
- * could causes part of the datetimepicker being hidden.
1999
- * by Soon start
2000
- */
2001
- var offset = datetimepicker.data('input').offset(),
2002
- datetimepickerelement = datetimepicker.data('input')[0],
2003
- top = offset.top + datetimepickerelement.offsetHeight - 1,
2004
- left = offset.left,
2005
- position = "absolute",
2006
- node;
2007
-
2008
- if ((document.documentElement.clientWidth - offset.left) < datepicker.parent().outerWidth(true)) {
2009
- var diff = datepicker.parent().outerWidth(true) - datetimepickerelement.offsetWidth;
2010
- left = left - diff;
2011
- }
2012
- /**
2013
- * by Soon end
2014
- */
2015
- if (datetimepicker.data('input').parent().css('direction') == 'rtl')
2016
- left -= (datetimepicker.outerWidth() - datetimepicker.data('input').outerWidth());
1935
+ var dateInputOffset,
1936
+ dateInputElem,
1937
+ verticalPosition,
1938
+ left,
1939
+ position,
1940
+ datetimepickerElem,
1941
+ dateInputHasFixedAncestor,
1942
+ $dateInput,
1943
+ windowWidth,
1944
+ verticalAnchorEdge,
1945
+ datetimepickerCss,
1946
+ windowHeight,
1947
+ windowScrollTop;
1948
+
1949
+ $dateInput = datetimepicker.data('input');
1950
+ dateInputOffset = $dateInput.offset();
1951
+ dateInputElem = $dateInput[0];
1952
+
1953
+ verticalAnchorEdge = 'top';
1954
+ verticalPosition = (dateInputOffset.top + dateInputElem.offsetHeight) - 1;
1955
+ left = dateInputOffset.left;
1956
+ position = "absolute";
1957
+
1958
+ windowWidth = $(window).width();
1959
+ windowHeight = $(window).height();
1960
+ windowScrollTop = $(window).scrollTop();
1961
+
1962
+ if ((document.documentElement.clientWidth - dateInputOffset.left) < datepicker.parent().outerWidth(true)) {
1963
+ var diff = datepicker.parent().outerWidth(true) - dateInputElem.offsetWidth;
1964
+ left = left - diff;
1965
+ }
1966
+
1967
+ if ($dateInput.parent().css('direction') === 'rtl') {
1968
+ left -= (datetimepicker.outerWidth() - $dateInput.outerWidth());
1969
+ }
1970
+
2017
1971
  if (options.fixed) {
2018
- top -= $(window).scrollTop();
1972
+ verticalPosition -= windowScrollTop;
2019
1973
  left -= $(window).scrollLeft();
2020
1974
  position = "fixed";
2021
1975
  } else {
2022
- if (top + datetimepickerelement.offsetHeight > $(window).height() + $(window).scrollTop()) {
2023
- top = offset.top - datetimepickerelement.offsetHeight + 1;
1976
+ dateInputHasFixedAncestor = false;
1977
+
1978
+ forEachAncestorOf(dateInputElem, function (ancestorNode) {
1979
+ if (window.getComputedStyle(ancestorNode).getPropertyValue('position') === 'fixed') {
1980
+ dateInputHasFixedAncestor = true;
1981
+ return false;
1982
+ }
1983
+ });
1984
+
1985
+ if (dateInputHasFixedAncestor) {
1986
+ position = 'fixed';
1987
+
1988
+ //If the picker won't fit entirely within the viewport then display it above the date input.
1989
+ if (verticalPosition + datetimepicker.outerHeight() > windowHeight + windowScrollTop) {
1990
+ verticalAnchorEdge = 'bottom';
1991
+ verticalPosition = (windowHeight + windowScrollTop) - dateInputOffset.top;
1992
+ } else {
1993
+ verticalPosition -= windowScrollTop;
1994
+ }
1995
+ } else {
1996
+ if (verticalPosition + dateInputElem.offsetHeight > windowHeight + windowScrollTop) {
1997
+ verticalPosition = dateInputOffset.top - dateInputElem.offsetHeight + 1;
1998
+ }
2024
1999
  }
2025
- if (top < 0) {
2026
- top = 0;
2000
+
2001
+ if (verticalPosition < 0) {
2002
+ verticalPosition = 0;
2027
2003
  }
2028
- if (left + datetimepickerelement.offsetWidth > $(window).width()) {
2029
- left = $(window).width() - datetimepickerelement.offsetWidth;
2004
+
2005
+ if (left + dateInputElem.offsetWidth > windowWidth) {
2006
+ left = windowWidth - dateInputElem.offsetWidth;
2030
2007
  }
2031
2008
  }
2032
2009
 
2033
- node = datetimepicker[0];
2034
- do {
2035
- node = node.parentNode;
2036
- if (window.getComputedStyle(node).getPropertyValue('position') === 'relative' && $(window).width() >= node.offsetWidth) {
2037
- left = left - (($(window).width() - node.offsetWidth) / 2);
2038
- break;
2010
+ datetimepickerElem = datetimepicker[0];
2011
+
2012
+ forEachAncestorOf(datetimepickerElem, function (ancestorNode) {
2013
+ var ancestorNodePosition;
2014
+
2015
+ ancestorNodePosition = window.getComputedStyle(ancestorNode).getPropertyValue('position');
2016
+
2017
+ if (ancestorNodePosition === 'relative' && windowWidth >= ancestorNode.offsetWidth) {
2018
+ left = left - ((windowWidth - ancestorNode.offsetWidth) / 2);
2019
+ return false;
2039
2020
  }
2040
- } while (node.nodeName !== 'HTML');
2041
- datetimepicker.css({
2042
- left: left,
2043
- top: top,
2044
- position: position
2045
2021
  });
2022
+
2023
+ datetimepickerCss = {
2024
+ position: position,
2025
+ left: left,
2026
+ top: '', //Initialize to prevent previous values interfering with new ones.
2027
+ bottom: '' //Initialize to prevent previous values interfering with new ones.
2028
+ };
2029
+
2030
+ datetimepickerCss[verticalAnchorEdge] = verticalPosition;
2031
+
2032
+ datetimepicker.css(datetimepickerCss);
2046
2033
  };
2034
+
2047
2035
  datetimepicker
2048
2036
  .on('open.xdsoft', function (event) {
2049
2037
  var onShow = true;
@@ -2079,7 +2067,7 @@
2079
2067
  }
2080
2068
  event.stopPropagation();
2081
2069
  })
2082
- .on('toggle.xdsoft', function (event) {
2070
+ .on('toggle.xdsoft', function () {
2083
2071
  if (datetimepicker.is(':visible')) {
2084
2072
  datetimepicker.trigger('close.xdsoft');
2085
2073
  } else {
@@ -2089,7 +2077,6 @@
2089
2077
  .data('input', input);
2090
2078
 
2091
2079
  timer = 0;
2092
- timer1 = 0;
2093
2080
 
2094
2081
  datetimepicker.data('xdsoft_datetime', _xdsoft_datetime);
2095
2082
  datetimepicker.setOptions(options);
@@ -2122,11 +2109,139 @@
2122
2109
  return ct || 0;
2123
2110
  }
2124
2111
 
2112
+ function setMask(options) {
2113
+
2114
+ var isValidValue = function (mask, value) {
2115
+ var reg = mask
2116
+ .replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g, '\\$1')
2117
+ .replace(/_/g, '{digit+}')
2118
+ .replace(/([0-9]{1})/g, '{digit$1}')
2119
+ .replace(/\{digit([0-9]{1})\}/g, '[0-$1_]{1}')
2120
+ .replace(/\{digit[\+]\}/g, '[0-9_]{1}');
2121
+ return (new RegExp(reg)).test(value);
2122
+ },
2123
+ getCaretPos = function (input) {
2124
+ try {
2125
+ if (document.selection && document.selection.createRange) {
2126
+ var range = document.selection.createRange();
2127
+ return range.getBookmark().charCodeAt(2) - 2;
2128
+ }
2129
+ if (input.setSelectionRange) {
2130
+ return input.selectionStart;
2131
+ }
2132
+ } catch (e) {
2133
+ return 0;
2134
+ }
2135
+ },
2136
+ setCaretPos = function (node, pos) {
2137
+ node = (typeof node === "string" || node instanceof String) ? document.getElementById(node) : node;
2138
+ if (!node) {
2139
+ return false;
2140
+ }
2141
+ if (node.createTextRange) {
2142
+ var textRange = node.createTextRange();
2143
+ textRange.collapse(true);
2144
+ textRange.moveEnd('character', pos);
2145
+ textRange.moveStart('character', pos);
2146
+ textRange.select();
2147
+ return true;
2148
+ }
2149
+ if (node.setSelectionRange) {
2150
+ node.setSelectionRange(pos, pos);
2151
+ return true;
2152
+ }
2153
+ return false;
2154
+ };
2155
+ if(options.mask) {
2156
+ input.off('keydown.xdsoft');
2157
+ }
2158
+ if (options.mask === true) {
2159
+ if (typeof moment != 'undefined') {
2160
+ options.mask = options.format
2161
+ .replace(/Y{4}/g, '9999')
2162
+ .replace(/Y{2}/g, '99')
2163
+ .replace(/M{2}/g, '19')
2164
+ .replace(/D{2}/g, '39')
2165
+ .replace(/H{2}/g, '29')
2166
+ .replace(/m{2}/g, '59')
2167
+ .replace(/s{2}/g, '59');
2168
+ } else {
2169
+ options.mask = options.format
2170
+ .replace(/Y/g, '9999')
2171
+ .replace(/F/g, '9999')
2172
+ .replace(/m/g, '19')
2173
+ .replace(/d/g, '39')
2174
+ .replace(/H/g, '29')
2175
+ .replace(/i/g, '59')
2176
+ .replace(/s/g, '59');
2177
+ }
2178
+ }
2179
+
2180
+ if ($.type(options.mask) === 'string') {
2181
+ if (!isValidValue(options.mask, input.val())) {
2182
+ input.val(options.mask.replace(/[0-9]/g, '_'));
2183
+ setCaretPos(input[0], 0);
2184
+ }
2185
+
2186
+ input.on('keydown.xdsoft', function (event) {
2187
+ var val = this.value,
2188
+ key = event.which,
2189
+ pos,
2190
+ digit;
2191
+
2192
+ if (((key >= KEY0 && key <= KEY9) || (key >= _KEY0 && key <= _KEY9)) || (key === BACKSPACE || key === DEL)) {
2193
+ pos = getCaretPos(this);
2194
+ digit = (key !== BACKSPACE && key !== DEL) ? String.fromCharCode((_KEY0 <= key && key <= _KEY9) ? key - KEY0 : key) : '_';
2195
+
2196
+ if ((key === BACKSPACE || key === DEL) && pos) {
2197
+ pos -= 1;
2198
+ digit = '_';
2199
+ }
2200
+
2201
+ while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) {
2202
+ pos += (key === BACKSPACE || key === DEL) ? -1 : 1;
2203
+ }
2204
+
2205
+ val = val.substr(0, pos) + digit + val.substr(pos + 1);
2206
+ if ($.trim(val) === '') {
2207
+ val = options.mask.replace(/[0-9]/g, '_');
2208
+ } else {
2209
+ if (pos === options.mask.length) {
2210
+ event.preventDefault();
2211
+ return false;
2212
+ }
2213
+ }
2214
+
2215
+ pos += (key === BACKSPACE || key === DEL) ? 0 : 1;
2216
+ while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) {
2217
+ pos += (key === BACKSPACE || key === DEL) ? -1 : 1;
2218
+ }
2219
+
2220
+ if (isValidValue(options.mask, val)) {
2221
+ this.value = val;
2222
+ setCaretPos(this, pos);
2223
+ } else if ($.trim(val) === '') {
2224
+ this.value = options.mask.replace(/[0-9]/g, '_');
2225
+ } else {
2226
+ input.trigger('error_input.xdsoft');
2227
+ }
2228
+ } else {
2229
+ if (([AKEY, CKEY, VKEY, ZKEY, YKEY].indexOf(key) !== -1 && ctrlDown) || [ESC, ARROWUP, ARROWDOWN, ARROWLEFT, ARROWRIGHT, F5, CTRLKEY, TAB, ENTER].indexOf(key) !== -1) {
2230
+ return true;
2231
+ }
2232
+ }
2233
+
2234
+ event.preventDefault();
2235
+ return false;
2236
+ });
2237
+ }
2238
+ }
2239
+
2125
2240
  _xdsoft_datetime.setCurrentTime(getCurrentValue());
2126
2241
 
2127
2242
  input
2128
2243
  .data('xdsoft_datetimepicker', datetimepicker)
2129
- .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function (event) {
2244
+ .on('open.xdsoft focusin.xdsoft mousedown.xdsoft touchstart', function () {
2130
2245
  if (input.is(':disabled') || (input.data('xdsoft_datetimepicker').is(':visible') && options.closeOnInputClick)) {
2131
2246
  return;
2132
2247
  }
@@ -2138,12 +2253,14 @@
2138
2253
 
2139
2254
  triggerAfterOpen = true;
2140
2255
  _xdsoft_datetime.setCurrentTime(getCurrentValue());
2141
-
2256
+ if(options.mask) {
2257
+ setMask(options);
2258
+ }
2142
2259
  datetimepicker.trigger('open.xdsoft');
2143
2260
  }, 100);
2144
2261
  })
2145
2262
  .on('keydown.xdsoft', function (event) {
2146
- var val = this.value, elementSelector,
2263
+ var elementSelector,
2147
2264
  key = event.which;
2148
2265
  if ([ENTER].indexOf(key) !== -1 && options.enterLikeTab) {
2149
2266
  elementSelector = $("input:visible,textarea:visible,button:visible,a:visible");
@@ -2155,6 +2272,9 @@
2155
2272
  datetimepicker.trigger('close.xdsoft');
2156
2273
  return true;
2157
2274
  }
2275
+ })
2276
+ .on('blur.xdsoft', function () {
2277
+ datetimepicker.trigger('close.xdsoft');
2158
2278
  });
2159
2279
  };
2160
2280
  destroyDateTimePicker = function (input) {
@@ -2184,8 +2304,8 @@
2184
2304
  ctrlDown = false;
2185
2305
  }
2186
2306
  });
2187
-
2188
- this.each(function () {
2307
+
2308
+ this.each(function () {
2189
2309
  var datetimepicker = $(this).data('xdsoft_datetimepicker'), $input;
2190
2310
  if (datetimepicker) {
2191
2311
  if ($.type(opt) === 'string') {
@@ -2214,10 +2334,10 @@
2214
2334
  $input = datetimepicker.data('input');
2215
2335
  $input.trigger('blur.xdsoft');
2216
2336
  break;
2217
- default:
2218
- if (datetimepicker[opt] && $.isFunction(datetimepicker[opt])) {
2219
- result = datetimepicker[opt](opt2);
2220
- }
2337
+ default:
2338
+ if (datetimepicker[opt] && $.isFunction(datetimepicker[opt])) {
2339
+ result = datetimepicker[opt](opt2);
2340
+ }
2221
2341
  }
2222
2342
  } else {
2223
2343
  datetimepicker
@@ -2234,8 +2354,9 @@
2234
2354
  }
2235
2355
  });
2236
2356
 
2237
- return result;
2357
+ return result;
2238
2358
  };
2359
+
2239
2360
  $.fn.datetimepicker.defaults = default_options;
2240
2361
 
2241
2362
  function HighlightedDate(date, desc, style) {
@@ -2244,5 +2365,4 @@
2244
2365
  this.desc = desc;
2245
2366
  this.style = style;
2246
2367
  }
2247
-
2248
2368
  }));