xdan-datetimepicker-rails 2.5.1 → 2.5.2

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