validation.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059
  1. import { EventHandlers } from "./eventhandlers";
  2. import { keyCode, keys } from "./keycode.js";
  3. import {
  4. determineLastRequiredPosition,
  5. determineNewCaretPosition,
  6. getBuffer,
  7. getLastValidPosition,
  8. isMask,
  9. resetMaskSet,
  10. seekNext,
  11. seekPrevious
  12. } from "./positioning";
  13. import {
  14. determineTestTemplate,
  15. getDecisionTaker,
  16. getPlaceholder,
  17. getTest,
  18. getTests,
  19. getTestTemplate
  20. } from "./validation-tests";
  21. export {
  22. alternate,
  23. checkAlternationMatch,
  24. isComplete,
  25. isSelection,
  26. isValid,
  27. refreshFromBuffer,
  28. revalidateMask,
  29. handleRemove
  30. };
  31. // tobe put on prototype?
  32. function alternate(maskPos, c, strict, fromIsValid, rAltPos, selection) {
  33. // pos == true => generalize
  34. const inputmask = this,
  35. $ = this.dependencyLib,
  36. opts = this.opts,
  37. maskset = inputmask.maskset;
  38. if (!inputmask.hasAlternator) return false;
  39. let validPsClone = $.extend(true, [], maskset.validPositions),
  40. tstClone = $.extend(true, {}, maskset.tests),
  41. lastAlt,
  42. alternation,
  43. isValidRslt = false,
  44. returnRslt = false,
  45. altPos,
  46. prevAltPos,
  47. i,
  48. validPos,
  49. decisionPos,
  50. lAltPos =
  51. rAltPos !== undefined ? rAltPos : getLastValidPosition.call(inputmask),
  52. nextPos,
  53. input,
  54. begin,
  55. end;
  56. if (selection) {
  57. begin = selection.begin;
  58. end = selection.end;
  59. if (selection.begin > selection.end) {
  60. begin = selection.end;
  61. end = selection.begin;
  62. }
  63. }
  64. if (lAltPos === -1 && rAltPos === undefined) {
  65. // do not recurse when already paste the beginning
  66. lastAlt = 0;
  67. prevAltPos = getTest.call(inputmask, lastAlt);
  68. alternation = prevAltPos.alternation;
  69. } else {
  70. // find last modified alternation
  71. for (; lAltPos >= 0; lAltPos--) {
  72. altPos = maskset.validPositions[lAltPos];
  73. if (altPos && altPos.alternation !== undefined) {
  74. if (
  75. lAltPos <= (maskPos || 0) &&
  76. prevAltPos &&
  77. prevAltPos.locator[altPos.alternation] !==
  78. altPos.locator[altPos.alternation]
  79. ) {
  80. break;
  81. }
  82. lastAlt = lAltPos;
  83. alternation = maskset.validPositions[lastAlt].alternation;
  84. prevAltPos = altPos;
  85. }
  86. }
  87. }
  88. if (alternation !== undefined) {
  89. decisionPos = parseInt(lastAlt);
  90. maskset.excludes[decisionPos] = maskset.excludes[decisionPos] || [];
  91. if (maskPos !== true) {
  92. // generalize
  93. maskset.excludes[decisionPos].push(
  94. getDecisionTaker(prevAltPos) + ":" + prevAltPos.alternation
  95. );
  96. }
  97. let validInputs = [],
  98. resultPos = -1;
  99. for (
  100. i = decisionPos;
  101. decisionPos < getLastValidPosition.call(inputmask, undefined, true) + 1;
  102. i++
  103. ) {
  104. if (resultPos === -1 && maskPos <= i && c !== undefined) {
  105. validInputs.push(c);
  106. resultPos = validInputs.length - 1;
  107. }
  108. validPos = maskset.validPositions[decisionPos];
  109. if (
  110. validPos &&
  111. validPos.generatedInput !== true &&
  112. (selection === undefined || i < begin || i >= end)
  113. ) {
  114. validInputs.push(validPos.input);
  115. }
  116. // delete maskset.validPositions[i++];
  117. maskset.validPositions.splice(decisionPos, 1);
  118. }
  119. if (resultPos === -1 && c !== undefined) {
  120. validInputs.push(c);
  121. resultPos = validInputs.length - 1;
  122. }
  123. while (
  124. maskset.excludes[decisionPos] !== undefined &&
  125. maskset.excludes[decisionPos].length < 10
  126. ) {
  127. // maskset.tests[decisionPos] = undefined; //clear decisionPos
  128. maskset.tests = {}; // clear all
  129. resetMaskSet.call(inputmask, true); // clear getbuffer
  130. isValidRslt = true;
  131. for (i = 0; i < validInputs.length; i++) {
  132. nextPos =
  133. isValidRslt.caret ||
  134. (opts.insertMode == false && nextPos != undefined)
  135. ? seekNext.call(inputmask, nextPos)
  136. : getLastValidPosition.call(inputmask, undefined, true) + 1;
  137. input = validInputs[i];
  138. // nextPos = translatePosition.call(inputmask, nextPos);
  139. if (
  140. !(isValidRslt = isValid.call(
  141. inputmask,
  142. nextPos,
  143. input,
  144. false,
  145. fromIsValid,
  146. true
  147. ))
  148. ) {
  149. break;
  150. }
  151. if (i === resultPos) {
  152. returnRslt = isValidRslt;
  153. }
  154. if (maskPos == true && isValidRslt) {
  155. // return validposition on generalise
  156. returnRslt = { caretPos: i };
  157. }
  158. }
  159. if (!isValidRslt) {
  160. resetMaskSet.call(inputmask);
  161. prevAltPos = getTest.call(inputmask, decisionPos); // get the current decisionPos to exclude ~ needs to be before restoring the initial validation
  162. // reset & revert
  163. maskset.validPositions = $.extend(true, [], validPsClone);
  164. maskset.tests = $.extend(true, {}, tstClone); // refresh tests after possible alternating
  165. if (maskset.excludes[decisionPos]) {
  166. if (prevAltPos.alternation != undefined) {
  167. const decisionTaker = getDecisionTaker(prevAltPos);
  168. if (
  169. maskset.excludes[decisionPos].indexOf(
  170. decisionTaker + ":" + prevAltPos.alternation
  171. ) !== -1
  172. ) {
  173. returnRslt = alternate.call(
  174. inputmask,
  175. maskPos,
  176. c,
  177. strict,
  178. fromIsValid,
  179. decisionPos - 1,
  180. selection
  181. );
  182. break;
  183. }
  184. maskset.excludes[decisionPos].push(
  185. decisionTaker + ":" + prevAltPos.alternation
  186. );
  187. for (
  188. i = decisionPos;
  189. i < getLastValidPosition.call(inputmask, undefined, true) + 1;
  190. i++
  191. )
  192. maskset.validPositions.splice(decisionPos);
  193. } else delete maskset.excludes[decisionPos];
  194. } else {
  195. // latest alternation
  196. returnRslt = alternate.call(
  197. inputmask,
  198. maskPos,
  199. c,
  200. strict,
  201. fromIsValid,
  202. decisionPos - 1,
  203. selection
  204. );
  205. break;
  206. }
  207. } else {
  208. break;
  209. }
  210. }
  211. }
  212. // reset alternation excludes
  213. if (!returnRslt || opts.keepStatic !== false) {
  214. delete maskset.excludes[decisionPos];
  215. }
  216. return returnRslt;
  217. }
  218. function casing(elem, test, pos) {
  219. const opts = this.opts,
  220. maskset = this.maskset;
  221. switch (opts.casing || test.casing) {
  222. case "upper":
  223. elem = elem.toUpperCase();
  224. break;
  225. case "lower":
  226. elem = elem.toLowerCase();
  227. break;
  228. case "title":
  229. var posBefore = maskset.validPositions[pos - 1];
  230. if (
  231. pos === 0 ||
  232. (posBefore && posBefore.input === String.fromCharCode(keyCode.Space))
  233. ) {
  234. elem = elem.toUpperCase();
  235. } else {
  236. elem = elem.toLowerCase();
  237. }
  238. break;
  239. default:
  240. if (typeof opts.casing === "function") {
  241. const args = Array.prototype.slice.call(arguments);
  242. args.push(maskset.validPositions);
  243. elem = opts.casing.apply(this, args);
  244. }
  245. }
  246. return elem;
  247. }
  248. // tobe put on prototype?
  249. function checkAlternationMatch(altArr1, altArr2, na) {
  250. const opts = this.opts;
  251. let altArrC = opts.greedy ? altArr2 : altArr2.slice(0, 1),
  252. isMatch = false,
  253. naArr = na !== undefined ? na.split(",") : [],
  254. naNdx;
  255. // remove no alternate indexes from alternation array
  256. for (let i = 0; i < naArr.length; i++) {
  257. if ((naNdx = altArr1.indexOf(naArr[i])) !== -1) {
  258. altArr1.splice(naNdx, 1);
  259. }
  260. }
  261. for (let alndx = 0; alndx < altArr1.length; alndx++) {
  262. if (altArrC.includes(altArr1[alndx])) {
  263. isMatch = true;
  264. break;
  265. }
  266. }
  267. return isMatch;
  268. }
  269. // tobe put on prototype?
  270. function handleRemove(input, c, pos, strict, fromIsValid) {
  271. const inputmask = this,
  272. maskset = this.maskset,
  273. opts = this.opts;
  274. if (opts.numericInput || inputmask.isRTL) {
  275. if (c === keys.Backspace) {
  276. c = keys.Delete;
  277. } else if (c === keys.Delete) {
  278. c = keys.Backspace;
  279. }
  280. if (inputmask.isRTL) {
  281. const pend = pos.end;
  282. pos.end = pos.begin;
  283. pos.begin = pend;
  284. }
  285. }
  286. const lvp = getLastValidPosition.call(inputmask, undefined, true);
  287. if (pos.end >= getBuffer.call(inputmask).length && lvp >= pos.end) {
  288. // handle numeric negate symbol offset, due to dynamic jit masking
  289. pos.end = lvp + 1;
  290. }
  291. if (c === keys.Backspace) {
  292. if (pos.end - pos.begin < 1) {
  293. pos.begin = seekPrevious.call(inputmask, pos.begin);
  294. }
  295. } else if (c === keys.Delete) {
  296. if (pos.begin === pos.end) {
  297. pos.end = isMask.call(inputmask, pos.end, true, true)
  298. ? pos.end + 1
  299. : seekNext.call(inputmask, pos.end) + 1;
  300. }
  301. }
  302. let offset;
  303. if ((offset = revalidateMask.call(inputmask, pos)) !== false) {
  304. if (
  305. (strict !== true && opts.keepStatic !== false) ||
  306. (opts.regex !== null &&
  307. getTest.call(inputmask, pos.begin).match.def.indexOf("|") !== -1)
  308. ) {
  309. // TODO NEEDS BETTER CHECK WHEN TO ALTERNATE ~ opts regex isn"t good enough
  310. alternate.call(inputmask, true);
  311. }
  312. if (strict !== true) {
  313. maskset.p = c === keys.Delete ? pos.begin + offset : pos.begin;
  314. maskset.p = determineNewCaretPosition.call(
  315. inputmask,
  316. {
  317. begin: maskset.p,
  318. end: maskset.p
  319. },
  320. false,
  321. opts.insertMode === false && c === keys.Backspace ? "none" : undefined
  322. ).begin;
  323. }
  324. }
  325. }
  326. // tobe put on prototype?
  327. function isComplete(buffer) {
  328. // return true / false / undefined (repeat *)
  329. const inputmask = this,
  330. opts = this.opts,
  331. maskset = this.maskset;
  332. if (typeof opts.isComplete === "function")
  333. return opts.isComplete(buffer, opts);
  334. if (opts.repeat === "*") return undefined;
  335. let complete = false,
  336. lrp = determineLastRequiredPosition.call(inputmask, true),
  337. aml = lrp.l; // seekPrevious.call(inputmask, lrp.l);
  338. if (
  339. lrp.def === undefined ||
  340. lrp.def.newBlockMarker ||
  341. lrp.def.optionality ||
  342. lrp.def.optionalQuantifier
  343. ) {
  344. complete = true;
  345. for (let i = 0; i <= aml; i++) {
  346. const test = getTestTemplate.call(inputmask, i).match;
  347. if (
  348. (test.static !== true &&
  349. maskset.validPositions[i] === undefined &&
  350. (test.optionality === false ||
  351. test.optionality === undefined ||
  352. (test.optionality && test.newBlockMarker == false)) &&
  353. (test.optionalQuantifier === false ||
  354. test.optionalQuantifier === undefined)) ||
  355. (test.static === true &&
  356. test.def != "" &&
  357. buffer[i] !== getPlaceholder.call(inputmask, i, test))
  358. ) {
  359. complete = false;
  360. break;
  361. }
  362. }
  363. }
  364. return complete;
  365. }
  366. function isSelection(posObj) {
  367. const inputmask = this,
  368. opts = this.opts,
  369. insertModeOffset = opts.insertMode ? 0 : 1;
  370. return inputmask.isRTL
  371. ? posObj.begin - posObj.end > insertModeOffset
  372. : posObj.end - posObj.begin > insertModeOffset;
  373. }
  374. // tobe put on prototype?
  375. function isValid(
  376. pos,
  377. c,
  378. strict,
  379. fromIsValid,
  380. fromAlternate,
  381. validateOnly,
  382. fromCheckval
  383. ) {
  384. // strict true ~ no correction or autofill
  385. const inputmask = this,
  386. $ = this.dependencyLib,
  387. opts = this.opts,
  388. maskset = inputmask.maskset;
  389. strict = strict === true; // always set a value to strict to prevent possible strange behavior in the extensions
  390. let maskPos = pos;
  391. if (pos.begin !== undefined) {
  392. // position was a position object - used to handle a delete by typing over a selection
  393. maskPos = inputmask.isRTL ? pos.end : pos.begin;
  394. }
  395. function processCommandObject(commandObj) {
  396. if (commandObj !== undefined) {
  397. if (commandObj.remove !== undefined) {
  398. // remove position(s)
  399. if (!Array.isArray(commandObj.remove))
  400. commandObj.remove = [commandObj.remove];
  401. commandObj.remove
  402. .sort(function (a, b) {
  403. return inputmask.isRTL ? a.pos - b.pos : b.pos - a.pos;
  404. })
  405. .forEach(function (lmnt) {
  406. revalidateMask.call(inputmask, { begin: lmnt, end: lmnt + 1 });
  407. });
  408. commandObj.remove = undefined;
  409. }
  410. if (commandObj.insert !== undefined) {
  411. // insert position(s)
  412. if (!Array.isArray(commandObj.insert))
  413. commandObj.insert = [commandObj.insert];
  414. commandObj.insert
  415. .sort(function (a, b) {
  416. return inputmask.isRTL ? b.pos - a.pos : a.pos - b.pos;
  417. })
  418. .forEach(function (lmnt) {
  419. if (lmnt.c !== "") {
  420. isValid.call(
  421. inputmask,
  422. lmnt.pos,
  423. lmnt.c,
  424. lmnt.strict !== undefined ? lmnt.strict : true,
  425. lmnt.fromIsValid !== undefined ? lmnt.fromIsValid : fromIsValid
  426. );
  427. }
  428. });
  429. commandObj.insert = undefined;
  430. }
  431. if (commandObj.refreshFromBuffer && commandObj.buffer) {
  432. const refresh = commandObj.refreshFromBuffer;
  433. refreshFromBuffer.call(
  434. inputmask,
  435. refresh === true ? refresh : refresh.start,
  436. refresh.end,
  437. commandObj.buffer
  438. );
  439. commandObj.refreshFromBuffer = undefined;
  440. }
  441. if (commandObj.rewritePosition !== undefined) {
  442. maskPos = commandObj.rewritePosition;
  443. // commandObj.rewritePosition = undefined;
  444. commandObj = true; // see prevalidation in isValid
  445. }
  446. }
  447. return commandObj;
  448. }
  449. function _isValid(position, c, strict) {
  450. let rslt = false;
  451. getTests.call(inputmask, position).every(function (tst, ndx) {
  452. const test = tst.match;
  453. // make sure the buffer is set and correct
  454. getBuffer.call(inputmask, true);
  455. if (
  456. test.jit &&
  457. maskset.validPositions[seekPrevious.call(inputmask, position)] ===
  458. undefined
  459. ) {
  460. // ignore if jit is not desirable
  461. rslt = false;
  462. } else {
  463. // return is false or a json object => { pos: ??, c: ??} or true
  464. rslt =
  465. test.fn != null
  466. ? test.fn.test(
  467. c,
  468. maskset,
  469. position,
  470. strict,
  471. opts,
  472. isSelection.call(inputmask, pos)
  473. )
  474. : (c === test.def || c === opts.skipOptionalPartCharacter) &&
  475. test.def !== "" // non mask
  476. ? {
  477. c:
  478. getPlaceholder.call(inputmask, position, test, true) ||
  479. test.def,
  480. pos: position
  481. }
  482. : false;
  483. }
  484. if (rslt !== false) {
  485. let elem = rslt.c !== undefined ? rslt.c : c,
  486. validatedPos = position;
  487. elem =
  488. elem === opts.skipOptionalPartCharacter && test.static === true
  489. ? getPlaceholder.call(inputmask, position, test, true) || test.def
  490. : elem;
  491. rslt = processCommandObject(rslt);
  492. if (rslt !== true && rslt.pos !== undefined && rslt.pos !== position) {
  493. // their is a position offset
  494. validatedPos = rslt.pos;
  495. }
  496. if (rslt !== true && rslt.pos === undefined && rslt.c === undefined) {
  497. return false; // breakout if nothing to insert
  498. }
  499. if (
  500. revalidateMask.call(
  501. inputmask,
  502. pos,
  503. $.extend({}, tst, {
  504. input: casing.call(inputmask, elem, test, validatedPos)
  505. }),
  506. fromIsValid,
  507. validatedPos
  508. ) === false
  509. ) {
  510. rslt = false;
  511. }
  512. return false; // break from loop
  513. }
  514. return true;
  515. });
  516. return rslt;
  517. }
  518. let result = true,
  519. positionsClone = $.extend(true, [], maskset.validPositions); // clone the currentPositions
  520. if (
  521. opts.keepStatic === false &&
  522. maskset.excludes[maskPos] !== undefined &&
  523. fromAlternate !== true &&
  524. fromIsValid !== true
  525. ) {
  526. for (let i = maskPos; i < (inputmask.isRTL ? pos.begin : pos.end); i++) {
  527. if (maskset.excludes[i] !== undefined) {
  528. maskset.excludes[i] = undefined;
  529. delete maskset.tests[i];
  530. }
  531. }
  532. }
  533. if (
  534. typeof opts.preValidation === "function" &&
  535. fromIsValid !== true &&
  536. validateOnly !== true
  537. ) {
  538. result = opts.preValidation.call(
  539. inputmask,
  540. getBuffer.call(inputmask),
  541. maskPos,
  542. c,
  543. isSelection.call(inputmask, pos),
  544. opts,
  545. maskset,
  546. pos,
  547. strict || fromAlternate
  548. );
  549. result = processCommandObject(result);
  550. }
  551. if (result === true) {
  552. // preValidation result
  553. result = _isValid(maskPos, c, strict);
  554. if (
  555. (!strict || fromIsValid === true) &&
  556. result === false &&
  557. validateOnly !== true
  558. ) {
  559. const currentPosValid = maskset.validPositions[maskPos];
  560. if (
  561. currentPosValid &&
  562. currentPosValid.match.static === true &&
  563. (currentPosValid.match.def === c ||
  564. c === opts.skipOptionalPartCharacter)
  565. ) {
  566. result = {
  567. caret: seekNext.call(inputmask, maskPos)
  568. };
  569. } else {
  570. if (
  571. opts.insertMode ||
  572. maskset.validPositions[seekNext.call(inputmask, maskPos)] ===
  573. undefined ||
  574. pos.end > maskPos
  575. ) {
  576. // does the input match on a further position?
  577. let skip = false;
  578. if (
  579. maskset.jitOffset[maskPos] &&
  580. maskset.validPositions[seekNext.call(inputmask, maskPos)] ===
  581. undefined
  582. ) {
  583. result = isValid.call(
  584. inputmask,
  585. maskPos + maskset.jitOffset[maskPos],
  586. c,
  587. true,
  588. true
  589. );
  590. if (result !== false) {
  591. if (fromAlternate !== true) result.caret = maskPos;
  592. skip = true;
  593. }
  594. }
  595. if (pos.end > maskPos) {
  596. maskset.validPositions[maskPos] = undefined;
  597. }
  598. if (
  599. !skip &&
  600. !isMask.call(inputmask, maskPos, opts.keepStatic && maskPos === 0)
  601. ) {
  602. for (
  603. let nPos = maskPos + 1,
  604. snPos = seekNext.call(inputmask, maskPos, false, maskPos !== 0);
  605. nPos <= snPos;
  606. nPos++
  607. ) {
  608. // if (!isMask(nPos, true)) {
  609. // continue;
  610. // }
  611. result = _isValid(nPos, c, strict);
  612. if (result !== false) {
  613. result =
  614. trackbackPositions.call(
  615. inputmask,
  616. maskPos,
  617. result.pos !== undefined ? result.pos : nPos
  618. ) || result;
  619. maskPos = nPos;
  620. break;
  621. }
  622. }
  623. }
  624. }
  625. }
  626. }
  627. if (inputmask.hasAlternator && fromAlternate !== true && !strict) {
  628. fromAlternate = true; // stop possible loop
  629. if (
  630. result === false &&
  631. opts.keepStatic &&
  632. (isComplete.call(inputmask, getBuffer.call(inputmask)) || maskPos === 0)
  633. ) {
  634. // try fuzzy alternator logic
  635. result = alternate.call(
  636. inputmask,
  637. maskPos,
  638. c,
  639. strict,
  640. fromIsValid,
  641. undefined,
  642. pos
  643. );
  644. } else if (
  645. isSelection.call(inputmask, pos) &&
  646. maskset.tests[maskPos] &&
  647. maskset.tests[maskPos].length > 1 &&
  648. opts.keepStatic
  649. ) {
  650. // selection clears an alternated keepstatic mask ~ #2189
  651. result = alternate.call(inputmask, true);
  652. } else if (
  653. result === true &&
  654. opts.numericInput !== true &&
  655. maskset.tests[maskPos] &&
  656. maskset.tests[maskPos].length > 1 &&
  657. getLastValidPosition.call(inputmask, undefined, true) > maskPos
  658. ) {
  659. // console.log("Alternating");
  660. result = alternate.call(inputmask, true);
  661. }
  662. }
  663. if (result === true) {
  664. result = {
  665. pos: maskPos
  666. };
  667. }
  668. if (
  669. typeof opts.postValidation === "function" &&
  670. fromIsValid !== true &&
  671. validateOnly !== true
  672. ) {
  673. const postResult = opts.postValidation.call(
  674. inputmask,
  675. getBuffer.call(inputmask, true),
  676. pos.begin !== undefined ? (inputmask.isRTL ? pos.end : pos.begin) : pos,
  677. c,
  678. result,
  679. opts,
  680. maskset,
  681. strict,
  682. fromCheckval,
  683. fromAlternate
  684. );
  685. if (postResult !== undefined) {
  686. result = postResult === true ? result : postResult;
  687. }
  688. }
  689. }
  690. if (result && result.pos === undefined) {
  691. result.pos = maskPos;
  692. }
  693. if (result === false || validateOnly === true) {
  694. resetMaskSet.call(inputmask, true);
  695. maskset.validPositions = $.extend(true, [], positionsClone); // revert validation changes
  696. } else {
  697. trackbackPositions.call(inputmask, undefined, maskPos, true);
  698. }
  699. let endResult = processCommandObject(result);
  700. // console.log("returned result " + JSON.stringify(endResult));
  701. if (inputmask.maxLength !== undefined) {
  702. const buffer = getBuffer.call(inputmask);
  703. if (buffer.length > inputmask.maxLength && !fromIsValid) {
  704. resetMaskSet.call(inputmask, true);
  705. maskset.validPositions = $.extend(true, [], positionsClone); // revert validation changes
  706. endResult = false;
  707. }
  708. }
  709. return endResult;
  710. }
  711. // tobe put on prototype?
  712. function positionCanMatchDefinition(pos, testDefinition, opts) {
  713. const inputmask = this,
  714. maskset = this.maskset;
  715. let valid = false,
  716. tests = getTests.call(inputmask, pos);
  717. for (let tndx = 0; tndx < tests.length; tndx++) {
  718. if (
  719. tests[tndx].match &&
  720. ((tests[tndx].match.nativeDef ===
  721. testDefinition.match[opts.shiftPositions ? "def" : "nativeDef"] &&
  722. (!opts.shiftPositions || !testDefinition.match.static)) ||
  723. tests[tndx].match.nativeDef === testDefinition.match.nativeDef ||
  724. (opts.regex &&
  725. !tests[tndx].match.static &&
  726. tests[tndx].match.fn.test(
  727. testDefinition.input,
  728. maskset,
  729. pos,
  730. false,
  731. opts
  732. )))
  733. ) {
  734. valid = true;
  735. break;
  736. } else if (
  737. tests[tndx].match &&
  738. tests[tndx].match.def === testDefinition.match.nativeDef
  739. ) {
  740. valid = undefined;
  741. break;
  742. }
  743. }
  744. if (valid === false) {
  745. if (maskset.jitOffset[pos] !== undefined) {
  746. valid = positionCanMatchDefinition.call(
  747. inputmask,
  748. pos + maskset.jitOffset[pos],
  749. testDefinition,
  750. opts
  751. );
  752. }
  753. }
  754. return valid;
  755. }
  756. // tobe put on prototype?
  757. function refreshFromBuffer(start, end, buffer) {
  758. const inputmask = this,
  759. maskset = this.maskset,
  760. opts = this.opts,
  761. $ = this.dependencyLib;
  762. // checkVal.call(inputmask, el, false, true, isRTL ? buffer.reverse() : buffer);
  763. let i,
  764. p,
  765. skipOptionalPartCharacter = opts.skipOptionalPartCharacter,
  766. bffr = inputmask.isRTL ? buffer.slice().reverse() : buffer;
  767. opts.skipOptionalPartCharacter = "";
  768. if (start === true) {
  769. resetMaskSet.call(inputmask, false);
  770. start = 0;
  771. end = buffer.length;
  772. p = determineNewCaretPosition.call(
  773. inputmask,
  774. { begin: 0, end: 0 },
  775. false
  776. ).begin;
  777. } else {
  778. for (i = start; i < end; i++) {
  779. maskset.validPositions.splice(start, 0);
  780. }
  781. p = start;
  782. }
  783. const keypress = new $.Event("keypress");
  784. for (i = start; i < end; i++) {
  785. keypress.key = bffr[i].toString();
  786. inputmask.ignorable = false; // make sure ignorable is ignored ;-)
  787. const valResult = EventHandlers.keypressEvent.call(
  788. inputmask,
  789. keypress,
  790. true,
  791. false,
  792. false,
  793. p
  794. );
  795. if (valResult !== false && valResult !== undefined) {
  796. p = valResult.forwardPosition;
  797. }
  798. }
  799. opts.skipOptionalPartCharacter = skipOptionalPartCharacter;
  800. }
  801. // tobe put on prototype?
  802. // fill in best positions according the current input
  803. function trackbackPositions(originalPos, newPos, fillOnly) {
  804. const inputmask = this,
  805. maskset = this.maskset,
  806. $ = this.dependencyLib;
  807. // console.log("trackbackPositions " + originalPos + " " + newPos);
  808. if (originalPos === undefined) {
  809. // find previous valid
  810. for (originalPos = newPos - 1; originalPos > 0; originalPos--) {
  811. if (maskset.validPositions[originalPos]) break;
  812. }
  813. }
  814. for (let ps = originalPos; ps < newPos; ps++) {
  815. if (
  816. maskset.validPositions[ps] === undefined &&
  817. !isMask.call(inputmask, ps, false)
  818. ) {
  819. const vp =
  820. ps == 0 ? getTest.call(inputmask, ps) : maskset.validPositions[ps - 1];
  821. if (vp) {
  822. const tests = getTests.call(inputmask, ps).slice();
  823. if (tests[tests.length - 1].match.def === "") tests.pop();
  824. var bestMatch = determineTestTemplate.call(inputmask, ps, tests),
  825. np;
  826. if (
  827. bestMatch &&
  828. (bestMatch.match.jit !== true ||
  829. (bestMatch.match.newBlockMarker === "master" &&
  830. (np = maskset.validPositions[ps + 1]) &&
  831. np.match.optionalQuantifier === true))
  832. ) {
  833. bestMatch = $.extend({}, bestMatch, {
  834. input:
  835. getPlaceholder.call(inputmask, ps, bestMatch.match, true) ||
  836. bestMatch.match.def
  837. });
  838. bestMatch.generatedInput = true;
  839. revalidateMask.call(inputmask, ps, bestMatch, true);
  840. if (fillOnly !== true) {
  841. // revalidate the new position to update the locator value
  842. const cvpInput = maskset.validPositions[newPos].input;
  843. maskset.validPositions[newPos] = undefined;
  844. return isValid.call(inputmask, newPos, cvpInput, true, true);
  845. }
  846. }
  847. }
  848. }
  849. }
  850. }
  851. // tobe put on prototype?
  852. function revalidateMask(pos, validTest, fromIsValid, validatedPos) {
  853. // console.log("revalidateMask " + fromIsValid);
  854. const inputmask = this,
  855. maskset = this.maskset,
  856. opts = this.opts,
  857. $ = this.dependencyLib;
  858. function IsEnclosedStatic(pos, valids, selection) {
  859. const posMatch = valids[pos];
  860. if (
  861. posMatch !== undefined &&
  862. posMatch.match.static === true &&
  863. posMatch.match.optionality !== true &&
  864. (valids[0] === undefined || valids[0].alternation === undefined)
  865. ) {
  866. const prevMatch =
  867. selection.begin <= pos - 1
  868. ? valids[pos - 1] &&
  869. valids[pos - 1].match.static === true &&
  870. valids[pos - 1]
  871. : valids[pos - 1],
  872. nextMatch =
  873. selection.end > pos + 1
  874. ? valids[pos + 1] &&
  875. valids[pos + 1].match.static === true &&
  876. valids[pos + 1]
  877. : valids[pos + 1];
  878. return prevMatch && nextMatch;
  879. }
  880. return false;
  881. }
  882. let offset = 0,
  883. begin = pos.begin !== undefined ? pos.begin : pos,
  884. end = pos.end !== undefined ? pos.end : pos,
  885. valid = true;
  886. if (pos.begin > pos.end) {
  887. begin = pos.end;
  888. end = pos.begin;
  889. }
  890. validatedPos = validatedPos !== undefined ? validatedPos : begin;
  891. if (
  892. fromIsValid === undefined &&
  893. (begin !== end ||
  894. (opts.insertMode && maskset.validPositions[validatedPos] !== undefined) ||
  895. validTest === undefined ||
  896. validTest.match.optionalQuantifier ||
  897. validTest.match.optionality)
  898. ) {
  899. // reposition & revalidate others
  900. let positionsClone = $.extend(true, [], maskset.validPositions),
  901. lvp = getLastValidPosition.call(inputmask, undefined, true),
  902. i;
  903. maskset.p = begin; // needed for alternated position after overtype selection
  904. const clearpos = isSelection.call(inputmask, pos) ? begin : validatedPos;
  905. for (i = lvp; i >= clearpos; i--) {
  906. maskset.validPositions.splice(i, 1);
  907. if (validTest === undefined) delete maskset.tests[i + 1];
  908. }
  909. let j = validatedPos,
  910. posMatch = j,
  911. t,
  912. canMatch,
  913. test;
  914. if (validTest) {
  915. maskset.validPositions[validatedPos] = $.extend(true, {}, validTest);
  916. posMatch++;
  917. j++;
  918. }
  919. if (positionsClone[end] == undefined && maskset.jitOffset[end]) {
  920. end += maskset.jitOffset[end] + 1;
  921. }
  922. for (i = validTest ? end : end - 1; i <= lvp; i++) {
  923. if (
  924. (t = positionsClone[i]) !== undefined &&
  925. t.generatedInput !== true &&
  926. (i >= end ||
  927. (i >= begin &&
  928. IsEnclosedStatic(i, positionsClone, {
  929. begin,
  930. end
  931. })))
  932. ) {
  933. while (
  934. ((test = getTest.call(inputmask, posMatch)), test.match.def !== "")
  935. ) {
  936. // loop needed to match further positions
  937. if (
  938. (canMatch = positionCanMatchDefinition.call(
  939. inputmask,
  940. posMatch,
  941. t,
  942. opts
  943. )) !== false ||
  944. t.match.def === "+"
  945. ) {
  946. // validated match //we still need some hackery for the + validator (numeric alias)
  947. if (t.match.def === "+") getBuffer.call(inputmask, true);
  948. const result = isValid.call(
  949. inputmask,
  950. posMatch,
  951. t.input,
  952. t.match.def !== "+",
  953. /* t.match.def !== "+" */ true
  954. );
  955. valid = result !== false;
  956. j = (result.pos || posMatch) + 1;
  957. if (!valid && canMatch) break;
  958. } else {
  959. valid = false;
  960. }
  961. if (valid) {
  962. if (validTest === undefined && t.match.static && i === pos.begin)
  963. offset++;
  964. break;
  965. }
  966. if (
  967. (!valid && getBuffer.call(inputmask), posMatch > maskset.maskLength)
  968. ) {
  969. break;
  970. }
  971. posMatch++;
  972. }
  973. if (getTest.call(inputmask, posMatch).match.def == "") {
  974. valid = false;
  975. }
  976. // restore position
  977. posMatch = j;
  978. }
  979. if (!valid) break;
  980. }
  981. if (!valid) {
  982. maskset.validPositions = $.extend(true, [], positionsClone);
  983. resetMaskSet.call(inputmask, true);
  984. return false;
  985. }
  986. } else if (
  987. validTest &&
  988. getTest.call(inputmask, validatedPos).match.cd === validTest.match.cd
  989. ) {
  990. maskset.validPositions[validatedPos] = $.extend(true, {}, validTest);
  991. }
  992. resetMaskSet.call(inputmask, true);
  993. return offset;
  994. }