number_box.mask.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. /**
  2. * DevExtreme (ui/number_box/number_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 eventsEngine = require("../../events/core/events_engine");
  11. var extend = require("../../core/utils/extend").extend;
  12. var isNumeric = require("../../core/utils/type").isNumeric;
  13. var browser = require("../../core/utils/browser");
  14. var devices = require("../../core/devices");
  15. var fitIntoRange = require("../../core/utils/math").fitIntoRange;
  16. var inRange = require("../../core/utils/math").inRange;
  17. var escapeRegExp = require("../../core/utils/common").escapeRegExp;
  18. var number = require("../../localization/number");
  19. var maskCaret = require("./number_box.caret");
  20. var getLDMLFormat = require("../../localization/ldml/number").getFormat;
  21. var NumberBoxBase = require("./number_box.base");
  22. var eventUtils = require("../../events/utils");
  23. var typeUtils = require("../../core/utils/type");
  24. var NUMBER_FORMATTER_NAMESPACE = "dxNumberFormatter";
  25. var MOVE_FORWARD = 1;
  26. var MOVE_BACKWARD = -1;
  27. var MINUS = "-";
  28. var MINUS_KEY = "minus";
  29. var NUMPUD_MINUS_KEY_IE = "Subtract";
  30. var INPUT_EVENT = "input";
  31. var CARET_TIMEOUT_DURATION = browser.msie ? 300 : 0;
  32. var ensureDefined = function(value, defaultValue) {
  33. return void 0 === value ? defaultValue : value
  34. };
  35. var NumberBoxMask = NumberBoxBase.inherit({
  36. _getDefaultOptions: function() {
  37. return extend(this.callBase(), {
  38. useMaskBehavior: true,
  39. format: null
  40. })
  41. },
  42. _isDeleteKey: function(key) {
  43. return "del" === key
  44. },
  45. _supportedKeys: function() {
  46. if (!this._useMaskBehavior()) {
  47. return this.callBase()
  48. }
  49. var that = this;
  50. return extend(this.callBase(), {
  51. minus: that._revertSign.bind(that),
  52. del: that._removeHandler.bind(that),
  53. backspace: that._removeHandler.bind(that),
  54. leftArrow: that._arrowHandler.bind(that, MOVE_BACKWARD),
  55. rightArrow: that._arrowHandler.bind(that, MOVE_FORWARD),
  56. home: that._moveCaretToBoundaryEventHandler.bind(that, MOVE_FORWARD),
  57. enter: that._updateFormattedValue.bind(that),
  58. end: that._moveCaretToBoundaryEventHandler.bind(that, MOVE_BACKWARD)
  59. })
  60. },
  61. _focusInHandler: function(e) {
  62. if (!this._preventNestedFocusEvent(e)) {
  63. this.clearCaretTimeout();
  64. this._caretTimeout = setTimeout(function() {
  65. this._caretTimeout = null;
  66. var caret = this._caret();
  67. if (caret.start === caret.end && this._useMaskBehavior()) {
  68. var text = this._getInputVal();
  69. var decimalSeparator = number.getDecimalSeparator();
  70. var decimalSeparatorIndex = text.indexOf(decimalSeparator);
  71. if (decimalSeparatorIndex >= 0) {
  72. this._caret({
  73. start: decimalSeparatorIndex,
  74. end: decimalSeparatorIndex
  75. })
  76. } else {
  77. this._moveCaretToBoundaryEventHandler(MOVE_BACKWARD, e)
  78. }
  79. }
  80. }.bind(this), CARET_TIMEOUT_DURATION)
  81. }
  82. this.callBase(e)
  83. },
  84. _focusOutHandler: function(e) {
  85. var shouldHandleEvent = !this._preventNestedFocusEvent(e);
  86. if (shouldHandleEvent) {
  87. this._focusOutOccurs = true;
  88. if (this._useMaskBehavior()) {
  89. this._updateFormattedValue()
  90. }
  91. }
  92. this.callBase(e);
  93. if (shouldHandleEvent) {
  94. this._focusOutOccurs = false
  95. }
  96. },
  97. _hasValueBeenChanged: function(inputValue) {
  98. var format = this._getFormatPattern();
  99. var value = this.option("value");
  100. var formatted = this._format(value, format) || "";
  101. return formatted !== inputValue
  102. },
  103. _updateFormattedValue: function() {
  104. var inputValue = this._getInputVal();
  105. if (this._hasValueBeenChanged(inputValue)) {
  106. this._parsedValue = this._tryParse(inputValue, this._caret());
  107. this._adjustParsedValue();
  108. this._setTextByParsedValue();
  109. if (this._parsedValue !== this.option("value")) {
  110. eventsEngine.trigger(this._input(), "change")
  111. }
  112. }
  113. },
  114. _arrowHandler: function(step, e) {
  115. if (!this._useMaskBehavior()) {
  116. return
  117. }
  118. var text = this._getInputVal();
  119. var format = this._getFormatPattern();
  120. var nextCaret = maskCaret.getCaretWithOffset(this._caret(), step);
  121. if (!maskCaret.isCaretInBoundaries(nextCaret, text, format)) {
  122. nextCaret = step === MOVE_FORWARD ? nextCaret.end : nextCaret.start;
  123. e.preventDefault();
  124. this._caret(maskCaret.getCaretInBoundaries(nextCaret, text, format))
  125. }
  126. },
  127. _moveCaretToBoundary: function(direction) {
  128. var boundaries = maskCaret.getCaretBoundaries(this._getInputVal(), this._getFormatPattern());
  129. var newCaret = maskCaret.getCaretWithOffset(direction === MOVE_FORWARD ? boundaries.start : boundaries.end, 0);
  130. this._caret(newCaret)
  131. },
  132. _moveCaretToBoundaryEventHandler: function(direction, e) {
  133. if (!this._useMaskBehavior() || e && e.shiftKey) {
  134. return
  135. }
  136. this._moveCaretToBoundary(direction);
  137. e && e.preventDefault()
  138. },
  139. _shouldMoveCaret: function(text, caret) {
  140. var decimalSeparator = number.getDecimalSeparator();
  141. var isDecimalSeparatorNext = text.charAt(caret.end) === decimalSeparator;
  142. var isZeroNext = "0" === text.charAt(caret.end);
  143. var moveToFloat = (this._lastKey === decimalSeparator || "." === this._lastKey) && isDecimalSeparatorNext;
  144. var zeroToZeroReplace = "0" === this._lastKey && isZeroNext;
  145. return moveToFloat || zeroToZeroReplace
  146. },
  147. _getInputVal: function() {
  148. return number.convertDigits(this._input().val(), true)
  149. },
  150. _keyboardHandler: function(e) {
  151. this.clearCaretTimeout();
  152. this._lastKey = number.convertDigits(eventUtils.getChar(e), true);
  153. this._lastKeyName = eventUtils.normalizeKeyName(e);
  154. if (!this._shouldHandleKey(e.originalEvent)) {
  155. return this.callBase(e)
  156. }
  157. var normalizedText = this._getInputVal();
  158. var caret = this._caret();
  159. var enteredChar = this._lastKeyName === MINUS_KEY ? "" : this._lastKey;
  160. var newValue = this._tryParse(normalizedText, caret, enteredChar);
  161. if (this._shouldMoveCaret(normalizedText, caret)) {
  162. this._moveCaret(1);
  163. e.originalEvent.preventDefault()
  164. }
  165. if (void 0 === newValue) {
  166. if (this._lastKeyName !== MINUS_KEY) {
  167. e.originalEvent.preventDefault()
  168. }
  169. } else {
  170. this._parsedValue = newValue
  171. }
  172. return this.callBase(e)
  173. },
  174. _keyPressHandler: function(e) {
  175. if (!this._useMaskBehavior()) {
  176. this.callBase(e)
  177. }
  178. },
  179. _removeHandler: function(e) {
  180. var caret = this._caret();
  181. var text = this._getInputVal();
  182. var start = caret.start;
  183. var end = caret.end;
  184. this._lastKey = eventUtils.getChar(e);
  185. this._lastKeyName = eventUtils.normalizeKeyName(e);
  186. var isDeleteKey = this._isDeleteKey(this._lastKeyName);
  187. var isBackspaceKey = !isDeleteKey;
  188. if (start === end) {
  189. var caretPosition = start;
  190. var canDelete = isBackspaceKey && caretPosition > 0 || isDeleteKey && caretPosition < text.length;
  191. if (canDelete) {
  192. isDeleteKey && end++;
  193. isBackspaceKey && start--
  194. } else {
  195. e.preventDefault();
  196. return
  197. }
  198. }
  199. var char = text.slice(start, end);
  200. if (this._isStub(char)) {
  201. this._moveCaret(isDeleteKey ? 1 : -1);
  202. if (this._parsedValue < 0 || 1 / this._parsedValue === -(1 / 0)) {
  203. this._revertSign(e);
  204. this._setTextByParsedValue()
  205. }
  206. e.preventDefault();
  207. return
  208. }
  209. var decimalSeparator = number.getDecimalSeparator();
  210. if (char === decimalSeparator) {
  211. var decimalSeparatorIndex = text.indexOf(decimalSeparator);
  212. if (this._isNonStubAfter(decimalSeparatorIndex + 1)) {
  213. this._moveCaret(isDeleteKey ? 1 : -1);
  214. e.preventDefault()
  215. }
  216. return
  217. }
  218. if (end - start < text.length) {
  219. var editedText = this._replaceSelectedText(text, {
  220. start: start,
  221. end: end
  222. }, "");
  223. var noDigits = editedText.search(/[0-9]/) < 0;
  224. if (noDigits && this._isValueInRange(0)) {
  225. this._parsedValue = this._parsedValue < 0 || 1 / this._parsedValue === -(1 / 0) ? -0 : 0;
  226. return
  227. }
  228. }
  229. var valueAfterRemoving = this._tryParse(text, {
  230. start: start,
  231. end: end
  232. }, "");
  233. if (void 0 === valueAfterRemoving) {
  234. e.preventDefault()
  235. } else {
  236. this._parsedValue = valueAfterRemoving
  237. }
  238. },
  239. _isPercentFormat: function() {
  240. var format = this._getFormatPattern();
  241. var noEscapedFormat = format.replace(/'[^']+'/g, "");
  242. return noEscapedFormat.indexOf("%") !== -1
  243. },
  244. _parse: function(text, format) {
  245. var formatOption = this.option("format");
  246. var isCustomParser = typeUtils.isFunction(formatOption.parser);
  247. var parser = isCustomParser ? formatOption.parser : number.parse;
  248. var formatPointIndex = format.indexOf(".");
  249. var textPointIndex = text.indexOf(number.getDecimalSeparator());
  250. var formatIntegerPartLength = formatPointIndex !== -1 ? formatPointIndex : format.length;
  251. var textIntegerPartLength = textPointIndex !== -1 ? textPointIndex : text.length;
  252. if (textIntegerPartLength > formatIntegerPartLength && format.indexOf("#") === -1) {
  253. text = text.substr(textIntegerPartLength - formatIntegerPartLength)
  254. }
  255. return parser(text, format)
  256. },
  257. _format: function(value, format) {
  258. var formatOption = this.option("format");
  259. var isCustomFormatter = typeUtils.isFunction(formatOption.formatter);
  260. var formatter = isCustomFormatter ? formatOption.formatter : number.format;
  261. return formatter(value, format)
  262. },
  263. _getFormatPattern: function() {
  264. var format = this.option("format");
  265. var isLDMLPattern = "string" === typeof format && (format.indexOf("0") >= 0 || format.indexOf("#") >= 0);
  266. if (isLDMLPattern) {
  267. return format
  268. } else {
  269. return getLDMLFormat(function(value) {
  270. var text = this._format(value, format);
  271. return number.convertDigits(text, true)
  272. }.bind(this))
  273. }
  274. },
  275. _getFormatForSign: function(text) {
  276. var format = this._getFormatPattern();
  277. var signParts = format.split(";");
  278. var sign = number.getSign(text, format);
  279. signParts[1] = signParts[1] || "-" + signParts[0];
  280. return sign < 0 ? signParts[1] : signParts[0]
  281. },
  282. _removeStubs: function(text, excludeComma) {
  283. var format = this._getFormatForSign(text);
  284. var thousandsSeparator = number.getThousandsSeparator();
  285. var stubs = format.replace(/[#0.,]/g, "");
  286. var regExp = new RegExp("[-" + escapeRegExp((excludeComma ? "" : thousandsSeparator) + stubs) + "]", "g");
  287. return text.replace(regExp, "")
  288. },
  289. _truncateToPrecision: function(value, maxPrecision) {
  290. if (typeUtils.isDefined(value)) {
  291. var strValue = value.toString();
  292. var decimalSeparatorIndex = strValue.indexOf(".");
  293. if (strValue && decimalSeparatorIndex > -1) {
  294. var parsedValue = parseFloat(strValue.substr(0, decimalSeparatorIndex + maxPrecision + 1));
  295. return isNaN(parsedValue) ? value : parsedValue
  296. }
  297. }
  298. return value
  299. },
  300. _tryParse: function(text, selection, char) {
  301. var editedText = this._replaceSelectedText(text, selection, char);
  302. var format = this._getFormatPattern();
  303. var isTextSelected = selection.start !== selection.end;
  304. var parsed = this._parse(editedText, format);
  305. var maxPrecision = this._getPrecisionLimits(format, editedText).max;
  306. var isValueChanged = parsed !== this._parsedValue;
  307. var decimalSeparator = number.getDecimalSeparator();
  308. var isDecimalPointRestricted = char === decimalSeparator && 0 === maxPrecision;
  309. var isUselessCharRestricted = !isTextSelected && !isValueChanged && char !== MINUS && !this._isValueIncomplete(editedText) && this._isStub(char);
  310. if (isDecimalPointRestricted || isUselessCharRestricted) {
  311. return
  312. }
  313. if ("" === this._removeStubs(editedText)) {
  314. parsed = 0 * this._parsedValue
  315. }
  316. if (isNaN(parsed)) {
  317. return
  318. }
  319. var value = null === parsed ? this._parsedValue : parsed;
  320. parsed = this._truncateToPrecision(value, maxPrecision);
  321. return this._isPercentFormat() ? parsed && parsed / 100 : parsed
  322. },
  323. _isValueIncomplete: function(text) {
  324. if (!this._useMaskBehavior()) {
  325. return this.callBase(text)
  326. }
  327. var caret = this._caret();
  328. var point = number.getDecimalSeparator();
  329. var pointIndex = text.indexOf(point);
  330. var isCaretOnFloat = pointIndex >= 0 && pointIndex < caret.start;
  331. var textParts = this._removeStubs(text, true).split(point);
  332. if (!isCaretOnFloat || 2 !== textParts.length) {
  333. return false
  334. }
  335. var floatLength = textParts[1].length;
  336. var precision = this._getPrecisionLimits(this._getFormatPattern(), text);
  337. var isPrecisionInRange = inRange(floatLength, precision.min, precision.max);
  338. var endsWithZero = "0" === textParts[1].charAt(floatLength - 1);
  339. return isPrecisionInRange && (endsWithZero || !floatLength)
  340. },
  341. _isValueInRange: function(value) {
  342. var min = ensureDefined(this.option("min"), -(1 / 0));
  343. var max = ensureDefined(this.option("max"), 1 / 0);
  344. return inRange(value, min, max)
  345. },
  346. _setInputText: function(text) {
  347. var normalizedText = number.convertDigits(text, true);
  348. var newCaret = maskCaret.getCaretAfterFormat(this._getInputVal(), normalizedText, this._caret(), this._getFormatPattern());
  349. this._input().val(text);
  350. this._toggleEmptinessEventHandler();
  351. this._formattedValue = text;
  352. if (!this._focusOutOccurs) {
  353. this._caret(newCaret)
  354. }
  355. },
  356. _useMaskBehavior: function() {
  357. return !!this.option("format") && this.option("useMaskBehavior")
  358. },
  359. _renderInputType: function() {
  360. var isNumberType = "number" === this.option("mode");
  361. var isDesktop = "desktop" === devices.real().deviceType;
  362. if (this._useMaskBehavior() && isNumberType) {
  363. this._setInputType(isDesktop || this._isSupportInputMode() ? "text" : "tel")
  364. } else {
  365. this.callBase()
  366. }
  367. },
  368. _isChar: function(str) {
  369. return "string" === typeof str && 1 === str.length
  370. },
  371. _moveCaret: function(offset) {
  372. if (!offset) {
  373. return
  374. }
  375. var newCaret = maskCaret.getCaretWithOffset(this._caret(), offset);
  376. var adjustedCaret = maskCaret.getCaretInBoundaries(newCaret, this._getInputVal(), this._getFormatPattern());
  377. this._caret(adjustedCaret)
  378. },
  379. _shouldHandleKey: function(e) {
  380. var keyName = eventUtils.normalizeKeyName(e);
  381. var isSpecialChar = e.ctrlKey || e.shiftKey || e.altKey || !this._isChar(keyName);
  382. var isMinusKey = keyName === MINUS_KEY;
  383. var useMaskBehavior = this._useMaskBehavior();
  384. return useMaskBehavior && !isSpecialChar && !isMinusKey
  385. },
  386. _renderInput: function() {
  387. this.callBase();
  388. this._renderFormatter()
  389. },
  390. _renderFormatter: function() {
  391. this._clearCache();
  392. this._detachFormatterEvents();
  393. if (this._useMaskBehavior()) {
  394. this._attachFormatterEvents()
  395. }
  396. },
  397. _detachFormatterEvents: function() {
  398. eventsEngine.off(this._input(), "." + NUMBER_FORMATTER_NAMESPACE)
  399. },
  400. _isInputFromPaste: function(e) {
  401. var inputType = e.originalEvent && e.originalEvent.inputType;
  402. if (typeUtils.isDefined(inputType)) {
  403. return "insertFromPaste" === inputType
  404. } else {
  405. return this._isValuePasted
  406. }
  407. },
  408. _attachFormatterEvents: function() {
  409. var $input = this._input();
  410. eventsEngine.on($input, eventUtils.addNamespace(INPUT_EVENT, NUMBER_FORMATTER_NAMESPACE), function(e) {
  411. this._formatValue(e);
  412. this._isValuePasted = false
  413. }.bind(this));
  414. if (browser.msie && browser.version < 12) {
  415. eventsEngine.on($input, eventUtils.addNamespace("paste", NUMBER_FORMATTER_NAMESPACE), function() {
  416. this._isValuePasted = true
  417. }.bind(this))
  418. }
  419. eventsEngine.on($input, eventUtils.addNamespace("dxclick", NUMBER_FORMATTER_NAMESPACE), function() {
  420. if (!this._caretTimeout) {
  421. this._caretTimeout = setTimeout(function() {
  422. this._caret(maskCaret.getCaretInBoundaries(this._caret(), this._getInputVal(), this._getFormatPattern()))
  423. }.bind(this), CARET_TIMEOUT_DURATION)
  424. }
  425. }.bind(this));
  426. eventsEngine.on($input, "dxdblclick", function() {
  427. this.clearCaretTimeout()
  428. }.bind(this))
  429. },
  430. clearCaretTimeout: function() {
  431. clearTimeout(this._caretTimeout);
  432. this._caretTimeout = null
  433. },
  434. _forceRefreshInputValue: function() {
  435. if (!this._useMaskBehavior()) {
  436. return this.callBase()
  437. }
  438. },
  439. _isNonStubAfter: function(index, text) {
  440. text = (text || this._getInputVal()).slice(index);
  441. return text && !this._isStub(text, true)
  442. },
  443. _isStub: function(str, isString) {
  444. var escapedDecimalSeparator = escapeRegExp(number.getDecimalSeparator());
  445. var regExpString = "^[^0-9" + escapedDecimalSeparator + "]+$";
  446. var stubRegExp = new RegExp(regExpString, "g");
  447. return stubRegExp.test(str) && (isString || this._isChar(str))
  448. },
  449. _parseValue: function(text) {
  450. if (!this._useMaskBehavior()) {
  451. return this.callBase(text)
  452. }
  453. return this._parsedValue
  454. },
  455. _getPrecisionLimits: function(text) {
  456. var currentFormat = this._getFormatForSign(text);
  457. var floatPart = (currentFormat.split(".")[1] || "").replace(/[^#0]/g, "");
  458. var minPrecision = floatPart.replace(/^(0*)#*/, "$1").length;
  459. var maxPrecision = floatPart.length;
  460. return {
  461. min: minPrecision,
  462. max: maxPrecision
  463. }
  464. },
  465. _revertSign: function(e) {
  466. if (!this._useMaskBehavior()) {
  467. return
  468. }
  469. var caret = this._caret();
  470. if (caret.start !== caret.end) {
  471. if (eventUtils.normalizeKeyName(e) === MINUS_KEY) {
  472. this._applyRevertedSign(e, caret, true);
  473. return
  474. } else {
  475. this._caret(maskCaret.getCaretInBoundaries(0, this._getInputVal(), this._getFormatPattern()))
  476. }
  477. }
  478. this._applyRevertedSign(e, caret)
  479. },
  480. _applyRevertedSign: function(e, caret, preserveSelectedText) {
  481. var newValue = -1 * ensureDefined(this._parsedValue, null);
  482. if (this._isValueInRange(newValue)) {
  483. this._parsedValue = newValue;
  484. if (preserveSelectedText) {
  485. var format = this._getFormatPattern();
  486. var previousText = this._getInputVal();
  487. this._setTextByParsedValue();
  488. e.preventDefault();
  489. var currentText = this._getInputVal();
  490. var offset = maskCaret.getCaretOffset(previousText, currentText, format);
  491. caret = maskCaret.getCaretWithOffset(caret, offset);
  492. var caretInBoundaries = maskCaret.getCaretInBoundaries(caret, currentText, format);
  493. if (browser.msie) {
  494. clearTimeout(this._caretTimeout);
  495. this._caretTimeout = setTimeout(this._caret.bind(this, caretInBoundaries))
  496. } else {
  497. this._caret(caretInBoundaries)
  498. }
  499. }
  500. if (e.key === NUMPUD_MINUS_KEY_IE) {
  501. eventsEngine.trigger(this._input(), INPUT_EVENT)
  502. }
  503. }
  504. },
  505. _removeMinusFromText: function(text, caret) {
  506. var isMinusPressed = this._lastKeyName === MINUS_KEY && text.charAt(caret.start - 1) === MINUS;
  507. return isMinusPressed ? this._replaceSelectedText(text, {
  508. start: caret.start - 1,
  509. end: caret.start
  510. }, "") : text
  511. },
  512. _setTextByParsedValue: function() {
  513. var format = this._getFormatPattern();
  514. var parsed = this._parseValue();
  515. var formatted = this._format(parsed, format) || "";
  516. this._setInputText(formatted)
  517. },
  518. _formatValue: function(e) {
  519. var normalizedText = this._getInputVal();
  520. var caret = this._caret();
  521. var textWithoutMinus = this._removeMinusFromText(normalizedText, caret);
  522. var wasMinusRemoved = textWithoutMinus !== normalizedText;
  523. normalizedText = textWithoutMinus;
  524. if (!this._isInputFromPaste(e) && this._isValueIncomplete(textWithoutMinus)) {
  525. this._formattedValue = normalizedText;
  526. if (wasMinusRemoved) {
  527. this._setTextByParsedValue()
  528. }
  529. return
  530. }
  531. var textWasChanged = number.convertDigits(this._formattedValue, true) !== normalizedText;
  532. if (textWasChanged) {
  533. var value = this._tryParse(normalizedText, caret, "");
  534. if (typeUtils.isDefined(value)) {
  535. this._parsedValue = value
  536. }
  537. }
  538. this._setTextByParsedValue()
  539. },
  540. _renderDisplayText: function() {
  541. if (this._useMaskBehavior()) {
  542. this._toggleEmptinessEventHandler()
  543. } else {
  544. this.callBase.apply(this, arguments)
  545. }
  546. },
  547. _renderValue: function() {
  548. if (this._useMaskBehavior()) {
  549. this._parsedValue = this.option("value");
  550. this._setTextByParsedValue()
  551. }
  552. return this.callBase()
  553. },
  554. _adjustParsedValue: function() {
  555. if (!this._useMaskBehavior()) {
  556. return
  557. }
  558. var clearedText = this._removeStubs(this._getInputVal());
  559. var parsedValue = clearedText ? this._parseValue() : null;
  560. if (!isNumeric(parsedValue)) {
  561. this._parsedValue = parsedValue;
  562. return
  563. }
  564. this._parsedValue = fitIntoRange(parsedValue, this.option("min"), this.option("max"))
  565. },
  566. _valueChangeEventHandler: function(e) {
  567. if (!this._useMaskBehavior()) {
  568. return this.callBase(e)
  569. }
  570. var caret = this._caret();
  571. this._saveValueChangeEvent(e);
  572. this._lastKey = null;
  573. this._lastKeyName = null;
  574. this._adjustParsedValue();
  575. this.option("value", this._parsedValue);
  576. if (caret) {
  577. this._caret(caret)
  578. }
  579. },
  580. _optionChanged: function(args) {
  581. switch (args.name) {
  582. case "format":
  583. case "useMaskBehavior":
  584. this._renderFormatter();
  585. this._renderValue();
  586. break;
  587. case "min":
  588. case "max":
  589. this._adjustParsedValue();
  590. this.callBase(args);
  591. break;
  592. default:
  593. this.callBase(args)
  594. }
  595. },
  596. _optionValuesEqual: function(name, oldValue, newValue) {
  597. if ("value" === name && 0 === oldValue && 0 === newValue) {
  598. return 1 / oldValue === 1 / newValue
  599. }
  600. return this.callBase.apply(this, arguments)
  601. },
  602. _clearCache: function() {
  603. delete this._formattedValue;
  604. delete this._lastKey;
  605. delete this._lastKeyName;
  606. delete this._parsedValue;
  607. delete this._focusOutOccurs;
  608. clearTimeout(this._caretTimeout);
  609. delete this._caretTimeout
  610. },
  611. _clean: function() {
  612. this._clearCache();
  613. this.callBase()
  614. }
  615. });
  616. module.exports = NumberBoxMask;