ui.date_box.mask.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. /**
  2. * DevExtreme (ui/date_box/ui.date_box.mask.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _utils = require("../../events/utils");
  11. var _type = require("../../core/utils/type");
  12. var _dom = require("../../core/utils/dom");
  13. var _extend = require("../../core/utils/extend");
  14. var _math = require("../../core/utils/math");
  15. var _events_engine = require("../../events/core/events_engine");
  16. var _events_engine2 = _interopRequireDefault(_events_engine);
  17. var _uiDate_boxMask = require("./ui.date_box.mask.parts");
  18. var _date = require("../../localization/date");
  19. var _date2 = _interopRequireDefault(_date);
  20. var _date3 = require("../../localization/ldml/date.parser");
  21. var _date4 = require("../../localization/ldml/date.format");
  22. var _uiDate_box = require("./ui.date_box.base");
  23. var _uiDate_box2 = _interopRequireDefault(_uiDate_box);
  24. var _devices = require("../../core/devices");
  25. var _devices2 = _interopRequireDefault(_devices);
  26. function _interopRequireDefault(obj) {
  27. return obj && obj.__esModule ? obj : {
  28. "default": obj
  29. }
  30. }
  31. var MASK_EVENT_NAMESPACE = "dateBoxMask";
  32. var FORWARD = 1;
  33. var BACKWARD = -1;
  34. var DateBoxMask = _uiDate_box2.default.inherit({
  35. _supportedKeys: function(e) {
  36. var _this = this;
  37. var originalHandlers = this.callBase(e);
  38. var callOriginalHandler = function(e) {
  39. var originalHandler = originalHandlers[(0, _utils.normalizeKeyName)(e)];
  40. return originalHandler && originalHandler.apply(_this, [e])
  41. };
  42. var applyHandler = function(e, maskHandler) {
  43. if (_this._shouldUseOriginalHandler(e)) {
  44. return callOriginalHandler.apply(_this, [e])
  45. } else {
  46. return maskHandler.apply(_this, [e])
  47. }
  48. };
  49. return (0, _extend.extend)({}, originalHandlers, {
  50. del: function(e) {
  51. return applyHandler(e, function(event) {
  52. _this._revertPart(FORWARD);
  53. _this._isAllSelected() || event.preventDefault()
  54. })
  55. },
  56. backspace: function(e) {
  57. return applyHandler(e, function(event) {
  58. _this._revertPart(BACKWARD);
  59. _this._isAllSelected() || event.preventDefault()
  60. })
  61. },
  62. home: function(e) {
  63. return applyHandler(e, function(event) {
  64. _this._selectFirstPart();
  65. event.preventDefault()
  66. })
  67. },
  68. end: function(e) {
  69. return applyHandler(e, function(event) {
  70. _this._selectLastPart();
  71. event.preventDefault()
  72. })
  73. },
  74. escape: function(e) {
  75. return applyHandler(e, function(event) {
  76. _this._revertChanges(event)
  77. })
  78. },
  79. enter: function(e) {
  80. return applyHandler(e, function(event) {
  81. _this._enterHandler(event)
  82. })
  83. },
  84. leftArrow: function(e) {
  85. return applyHandler(e, function(event) {
  86. _this._selectNextPart(BACKWARD);
  87. event.preventDefault()
  88. })
  89. },
  90. rightArrow: function(e) {
  91. return applyHandler(e, function(event) {
  92. _this._selectNextPart(FORWARD);
  93. event.preventDefault()
  94. })
  95. },
  96. upArrow: function(e) {
  97. return applyHandler(e, function(event) {
  98. _this._upDownArrowHandler(FORWARD);
  99. event.preventDefault()
  100. })
  101. },
  102. downArrow: function(e) {
  103. return applyHandler(e, function(event) {
  104. _this._upDownArrowHandler(BACKWARD);
  105. event.preventDefault()
  106. })
  107. }
  108. })
  109. },
  110. _shouldUseOriginalHandler: function(e) {
  111. return !this._useMaskBehavior() || this.option("opened") || e && e.altKey
  112. },
  113. _upDownArrowHandler: function(step) {
  114. this._setNewDateIfEmpty();
  115. var originalValue = this._getActivePartValue(this._initialMaskValue);
  116. var currentValue = this._getActivePartValue();
  117. var delta = currentValue - originalValue;
  118. this._loadMaskValue(this._initialMaskValue);
  119. this._partIncrease(delta + step, true)
  120. },
  121. _getDefaultOptions: function() {
  122. return (0, _extend.extend)(this.callBase(), {
  123. useMaskBehavior: false,
  124. emptyDateValue: new Date(2e3, 0, 1, 0, 0, 0),
  125. advanceCaret: true
  126. })
  127. },
  128. _isSingleCharKey: function(e) {
  129. var key = e.originalEvent.data || e.originalEvent.key;
  130. return "string" === typeof key && 1 === key.length && !e.ctrl && !e.alt
  131. },
  132. _useBeforeInputEvent: function() {
  133. var device = _devices2.default.real();
  134. return device.android && device.version[0] > 4
  135. },
  136. _keyboardHandler: function(e) {
  137. var key = e.originalEvent.key;
  138. var result = this.callBase(e);
  139. if (!this._useMaskBehavior() || this._useBeforeInputEvent() || !this._isSingleCharKey(e)) {
  140. return result
  141. }
  142. this._processInputKey(key);
  143. e.originalEvent.preventDefault();
  144. return result
  145. },
  146. _maskBeforeInputHandler: function(e) {
  147. var _this2 = this;
  148. this._maskInputHandler = null;
  149. var inputType = e.originalEvent.inputType;
  150. if ("insertCompositionText" === inputType) {
  151. this._maskInputHandler = function() {
  152. _this2._renderDisplayText(_this2._getDisplayedText(_this2._maskValue));
  153. _this2._selectNextPart()
  154. }
  155. }
  156. var isBackwardDeletion = "deleteContentBackward" === inputType;
  157. var isForwardDeletion = "deleteContentForward" === inputType;
  158. if (isBackwardDeletion || isForwardDeletion) {
  159. var direction = isBackwardDeletion ? BACKWARD : FORWARD;
  160. this._maskInputHandler = function() {
  161. _this2._revertPart();
  162. _this2._selectNextPart(direction)
  163. }
  164. }
  165. if (!this._useMaskBehavior() || !this._isSingleCharKey(e)) {
  166. return
  167. }
  168. var key = e.originalEvent.data;
  169. this._processInputKey(key);
  170. e.preventDefault();
  171. return true
  172. },
  173. _keyPressHandler: function(e) {
  174. this.callBase(e);
  175. if (this._maskInputHandler) {
  176. this._maskInputHandler();
  177. this._maskInputHandler = null
  178. }
  179. },
  180. _processInputKey: function(key) {
  181. if (this._isAllSelected()) {
  182. this._activePartIndex = 0
  183. }
  184. this._setNewDateIfEmpty();
  185. if (isNaN(parseInt(key))) {
  186. this._searchString(key)
  187. } else {
  188. this._searchNumber(key)
  189. }
  190. },
  191. _isAllSelected: function() {
  192. var caret = this._caret();
  193. return caret.end - caret.start === this.option("text").length
  194. },
  195. _getFormatPattern: function() {
  196. if (this._formatPattern) {
  197. return this._formatPattern
  198. }
  199. var format = this._strategy.getDisplayFormat(this.option("displayFormat"));
  200. var isLDMLPattern = (0, _type.isString)(format) && !_date2.default._getPatternByFormat(format);
  201. if (isLDMLPattern) {
  202. this._formatPattern = format
  203. } else {
  204. this._formatPattern = (0, _date4.getFormat)(function(value) {
  205. return _date2.default.format(value, format)
  206. })
  207. }
  208. return this._formatPattern
  209. },
  210. _setNewDateIfEmpty: function() {
  211. if (!this._maskValue) {
  212. var value = "time" === this.option("type") ? new Date(null) : new Date;
  213. this._maskValue = value;
  214. this._initialMaskValue = value;
  215. this._renderDateParts()
  216. }
  217. },
  218. _searchNumber: function(char) {
  219. var _this$_getActivePartL = this._getActivePartLimits(),
  220. max = _this$_getActivePartL.max;
  221. var maxLimitLength = String(max).length;
  222. var formatLength = this._getActivePartProp("pattern").length;
  223. this._searchValue = (this._searchValue + char).substr(-maxLimitLength);
  224. if (isNaN(this._searchValue)) {
  225. this._searchValue = char
  226. }
  227. this._setActivePartValue(this._searchValue);
  228. if (this.option("advanceCaret")) {
  229. var isShortFormat = 1 === formatLength;
  230. var maxSearchLength = isShortFormat ? maxLimitLength : Math.min(formatLength, maxLimitLength);
  231. var isLengthExceeded = this._searchValue.length === maxSearchLength;
  232. var isValueOverflowed = parseInt(this._searchValue + "0") > max;
  233. if (isLengthExceeded || isValueOverflowed) {
  234. this._selectNextPart(FORWARD)
  235. }
  236. }
  237. },
  238. _searchString: function(char) {
  239. if (!isNaN(parseInt(this._getActivePartProp("text")))) {
  240. return
  241. }
  242. var limits = this._getActivePartProp("limits")(this._maskValue);
  243. var startString = this._searchValue + char.toLowerCase();
  244. var endLimit = limits.max - limits.min;
  245. for (var i = 0; i <= endLimit; i++) {
  246. this._loadMaskValue(this._initialMaskValue);
  247. this._partIncrease(i + 1);
  248. if (0 === this._getActivePartProp("text").toLowerCase().indexOf(startString)) {
  249. this._searchValue = startString;
  250. return
  251. }
  252. }
  253. this._setNewDateIfEmpty();
  254. if (this._searchValue) {
  255. this._clearSearchValue();
  256. this._searchString(char)
  257. }
  258. },
  259. _clearSearchValue: function() {
  260. this._searchValue = ""
  261. },
  262. _revertPart: function(direction) {
  263. if (!this._isAllSelected()) {
  264. var actual = this._getActivePartValue(this.option("emptyDateValue"));
  265. this._setActivePartValue(actual);
  266. this._selectNextPart(direction)
  267. }
  268. this._clearSearchValue()
  269. },
  270. _useMaskBehavior: function() {
  271. return this.option("useMaskBehavior") && "text" === this.option("mode")
  272. },
  273. _initMaskState: function() {
  274. this._activePartIndex = 0;
  275. this._formatPattern = null;
  276. this._regExpInfo = (0, _date3.getRegExpInfo)(this._getFormatPattern(), _date2.default);
  277. this._loadMaskValue()
  278. },
  279. _renderMask: function() {
  280. this.callBase();
  281. this._detachMaskEvents();
  282. this._clearMaskState();
  283. if (this._useMaskBehavior()) {
  284. this._attachMaskEvents();
  285. this._initMaskState();
  286. this._renderDateParts()
  287. }
  288. },
  289. _renderDateParts: function() {
  290. if (!this._useMaskBehavior()) {
  291. return
  292. }
  293. var text = this.option("text") || this._getDisplayedText(this._maskValue);
  294. if (text) {
  295. this._dateParts = (0, _uiDate_boxMask.renderDateParts)(text, this._regExpInfo);
  296. this._isFocused() && this._selectNextPart()
  297. }
  298. },
  299. _detachMaskEvents: function() {
  300. _events_engine2.default.off(this._input(), "." + MASK_EVENT_NAMESPACE)
  301. },
  302. _attachMaskEvents: function() {
  303. var _this3 = this;
  304. _events_engine2.default.on(this._input(), (0, _utils.addNamespace)("dxclick", MASK_EVENT_NAMESPACE), this._maskClickHandler.bind(this));
  305. _events_engine2.default.on(this._input(), (0, _utils.addNamespace)("paste", MASK_EVENT_NAMESPACE), this._maskPasteHandler.bind(this));
  306. _events_engine2.default.on(this._input(), (0, _utils.addNamespace)("drop", MASK_EVENT_NAMESPACE), function() {
  307. _this3._renderDisplayText(_this3._getDisplayedText(_this3._maskValue));
  308. _this3._selectNextPart()
  309. });
  310. if (this._useBeforeInputEvent()) {
  311. _events_engine2.default.on(this._input(), (0, _utils.addNamespace)("beforeinput", MASK_EVENT_NAMESPACE), this._maskBeforeInputHandler.bind(this))
  312. }
  313. },
  314. _selectLastPart: function() {
  315. if (this.option("text")) {
  316. this._activePartIndex = this._dateParts.length;
  317. this._selectNextPart(BACKWARD)
  318. }
  319. },
  320. _selectFirstPart: function() {
  321. if (this.option("text")) {
  322. this._activePartIndex = -1;
  323. this._selectNextPart(FORWARD)
  324. }
  325. },
  326. _onMouseWheel: function(e) {
  327. if (this._useMaskBehavior()) {
  328. this._partIncrease(e.delta > 0 ? FORWARD : BACKWARD, e)
  329. }
  330. },
  331. _selectNextPart: function() {
  332. var step = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0;
  333. if (!this.option("text") || this._disposed) {
  334. return
  335. }
  336. if (step) {
  337. this._initialMaskValue = new Date(this._maskValue)
  338. }
  339. var index = (0, _math.fitIntoRange)(this._activePartIndex + step, 0, this._dateParts.length - 1);
  340. if (this._dateParts[index].isStub) {
  341. var isBoundaryIndex = 0 === index && step < 0 || index === this._dateParts.length - 1 && step > 0;
  342. if (!isBoundaryIndex) {
  343. this._selectNextPart(step >= 0 ? step + 1 : step - 1);
  344. return
  345. } else {
  346. index = this._activePartIndex
  347. }
  348. }
  349. if (this._activePartIndex !== index) {
  350. this._clearSearchValue()
  351. }
  352. this._activePartIndex = index;
  353. this._caret(this._getActivePartProp("caret"))
  354. },
  355. _getRealLimitsPattern: function() {
  356. if ("d" === this._getActivePartProp("pattern")[0]) {
  357. return "dM"
  358. }
  359. },
  360. _getActivePartLimits: function(lockOtherParts) {
  361. var limitFunction = this._getActivePartProp("limits");
  362. return limitFunction(this._maskValue, lockOtherParts && this._getRealLimitsPattern())
  363. },
  364. _getActivePartValue: function(dateValue) {
  365. dateValue = dateValue || this._maskValue;
  366. var getter = this._getActivePartProp("getter");
  367. return (0, _type.isFunction)(getter) ? getter(dateValue) : dateValue[getter]()
  368. },
  369. _addLeadingZeroes: function(value) {
  370. var zeroes = this._searchValue.match(/^0+/);
  371. var limits = this._getActivePartLimits();
  372. var maxLimitLength = String(limits.max).length;
  373. return ((zeroes && zeroes[0] || "") + String(value)).substr(-maxLimitLength)
  374. },
  375. _setActivePartValue: function(value, dateValue) {
  376. dateValue = dateValue || this._maskValue;
  377. var setter = this._getActivePartProp("setter");
  378. var limits = this._getActivePartLimits();
  379. value = (0, _math.inRange)(value, limits.min, limits.max) ? value : value % 10;
  380. value = this._addLeadingZeroes((0, _math.fitIntoRange)(value, limits.min, limits.max));
  381. (0, _type.isFunction)(setter) ? setter(dateValue, value): dateValue[setter](value);
  382. this._renderDisplayText(this._getDisplayedText(dateValue));
  383. this._renderDateParts()
  384. },
  385. _getActivePartProp: function(property) {
  386. if (!this._dateParts || !this._dateParts[this._activePartIndex]) {
  387. return
  388. }
  389. return this._dateParts[this._activePartIndex][property]
  390. },
  391. _loadMaskValue: function() {
  392. var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : this.dateOption("value");
  393. this._maskValue = value && new Date(value);
  394. this._initialMaskValue = value && new Date(value)
  395. },
  396. _saveMaskValue: function() {
  397. var value = this._maskValue && new Date(this._maskValue);
  398. this._initialMaskValue = new Date(value);
  399. this.dateOption("value", value)
  400. },
  401. _revertChanges: function() {
  402. this._loadMaskValue();
  403. this._renderDisplayText(this._getDisplayedText(this._maskValue));
  404. this._renderDateParts()
  405. },
  406. _renderDisplayText: function(text) {
  407. this.callBase(text);
  408. if (this._useMaskBehavior()) {
  409. this.option("text", text)
  410. }
  411. },
  412. _partIncrease: function(step, lockOtherParts) {
  413. this._setNewDateIfEmpty();
  414. var _this$_getActivePartL2 = this._getActivePartLimits(lockOtherParts),
  415. max = _this$_getActivePartL2.max,
  416. min = _this$_getActivePartL2.min;
  417. var limitDelta = max - min;
  418. if (1 === limitDelta) {
  419. limitDelta++
  420. }
  421. var newValue = step + this._getActivePartValue();
  422. if (newValue > max) {
  423. newValue = this._applyLimits(newValue, {
  424. limitBase: min,
  425. limitClosest: max,
  426. limitDelta: limitDelta
  427. })
  428. } else {
  429. if (newValue < min) {
  430. newValue = this._applyLimits(newValue, {
  431. limitBase: max,
  432. limitClosest: min,
  433. limitDelta: limitDelta
  434. })
  435. }
  436. }
  437. this._setActivePartValue(newValue)
  438. },
  439. _applyLimits: function(newValue, _ref) {
  440. var limitBase = _ref.limitBase,
  441. limitClosest = _ref.limitClosest,
  442. limitDelta = _ref.limitDelta;
  443. var delta = (newValue - limitClosest) % limitDelta;
  444. return delta ? limitBase + delta - 1 * (0, _math.sign)(delta) : limitClosest
  445. },
  446. _maskClickHandler: function() {
  447. if (this.option("text")) {
  448. this._activePartIndex = (0, _uiDate_boxMask.getDatePartIndexByPosition)(this._dateParts, this._caret().start);
  449. this._caret(this._getActivePartProp("caret"))
  450. }
  451. },
  452. _maskPasteHandler: function(e) {
  453. var newText = this._replaceSelectedText(this.option("text"), this._caret(), (0, _dom.clipboardText)(e));
  454. var date = _date2.default.parse(newText, this._getFormatPattern());
  455. if (date) {
  456. this._maskValue = date;
  457. this._renderDisplayText(this._getDisplayedText(this._maskValue));
  458. this._renderDateParts();
  459. this._selectNextPart()
  460. }
  461. e.preventDefault()
  462. },
  463. _isValueDirty: function() {
  464. var value = this.dateOption("value");
  465. return (this._maskValue && this._maskValue.getTime()) !== (value && value.getTime())
  466. },
  467. _fireChangeEvent: function() {
  468. this._clearSearchValue();
  469. if (this._isValueDirty()) {
  470. _events_engine2.default.trigger(this._input(), "change")
  471. }
  472. },
  473. _enterHandler: function(e) {
  474. this._fireChangeEvent();
  475. this._selectNextPart(FORWARD);
  476. e.preventDefault()
  477. },
  478. _focusOutHandler: function(e) {
  479. this.callBase(e);
  480. if (this._useMaskBehavior() && !e.isDefaultPrevented()) {
  481. this._fireChangeEvent();
  482. this._selectFirstPart(e)
  483. }
  484. },
  485. _valueChangeEventHandler: function(e) {
  486. if (this._useMaskBehavior()) {
  487. this._saveValueChangeEvent(e);
  488. if (!this.option("text")) {
  489. this._maskValue = null
  490. }
  491. this._saveMaskValue()
  492. } else {
  493. this.callBase(e)
  494. }
  495. },
  496. _optionChanged: function(args) {
  497. switch (args.name) {
  498. case "useMaskBehavior":
  499. this._renderMask();
  500. break;
  501. case "displayFormat":
  502. case "mode":
  503. this.callBase(args);
  504. this._renderMask();
  505. break;
  506. case "value":
  507. this._loadMaskValue();
  508. this.callBase(args);
  509. this._renderDateParts();
  510. break;
  511. case "advanceCaret":
  512. case "emptyDateValue":
  513. break;
  514. default:
  515. this.callBase(args)
  516. }
  517. },
  518. _clearMaskState: function() {
  519. this._clearSearchValue();
  520. delete this._dateParts;
  521. delete this._activePartIndex;
  522. delete this._maskValue
  523. },
  524. reset: function() {
  525. this.callBase();
  526. this._clearMaskState();
  527. this._activePartIndex = 0
  528. },
  529. _clean: function() {
  530. this.callBase();
  531. this._detachMaskEvents();
  532. this._clearMaskState()
  533. }
  534. });
  535. module.exports = DateBoxMask;