inputHandling.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. import { ie } from "./environment";
  2. import { EventHandlers } from "./eventhandlers";
  3. import { keys } from "./keycode.js";
  4. import {
  5. caret,
  6. determineNewCaretPosition,
  7. getBuffer,
  8. getBufferTemplate,
  9. getLastValidPosition,
  10. isMask,
  11. resetMaskSet,
  12. seekNext
  13. } from "./positioning";
  14. import { isComplete, refreshFromBuffer } from "./validation";
  15. import { getMaskTemplate, getPlaceholder, getTest } from "./validation-tests";
  16. export {
  17. applyInputValue,
  18. clearOptionalTail,
  19. checkVal,
  20. HandleNativePlaceholder,
  21. unmaskedvalue,
  22. writeBuffer
  23. };
  24. function applyInputValue(input, value, initialEvent) {
  25. const inputmask = input ? input.inputmask : this,
  26. opts = inputmask.opts;
  27. input.inputmask.refreshValue = false;
  28. if (typeof opts.onBeforeMask === "function")
  29. value = opts.onBeforeMask.call(inputmask, value, opts) || value;
  30. value = (value || "").toString().split("");
  31. checkVal(input, true, false, value, initialEvent);
  32. inputmask.undoValue = inputmask._valueGet(true);
  33. if (
  34. (opts.clearMaskOnLostFocus || opts.clearIncomplete) &&
  35. input.inputmask._valueGet() ===
  36. getBufferTemplate.call(inputmask).join("") &&
  37. getLastValidPosition.call(inputmask) === -1
  38. ) {
  39. input.inputmask._valueSet("");
  40. }
  41. }
  42. // todo put on prototype?
  43. function clearOptionalTail(buffer) {
  44. const inputmask = this;
  45. buffer.length = 0;
  46. let template = getMaskTemplate.call(
  47. inputmask,
  48. true,
  49. 0,
  50. true,
  51. undefined,
  52. true
  53. ),
  54. lmnt;
  55. while ((lmnt = template.shift()) !== undefined) buffer.push(lmnt);
  56. return buffer;
  57. }
  58. function checkVal(input, writeOut, strict, nptvl, initiatingEvent) {
  59. const inputmask = input ? input.inputmask : this,
  60. maskset = inputmask.maskset,
  61. opts = inputmask.opts,
  62. $ = inputmask.dependencyLib;
  63. let inputValue = nptvl.slice(),
  64. charCodes = "",
  65. initialNdx = -1,
  66. result,
  67. skipOptionalPartCharacter = opts.skipOptionalPartCharacter;
  68. opts.skipOptionalPartCharacter = ""; // see issue #2311
  69. function isTemplateMatch(ndx, charCodes) {
  70. let targetTemplate = getMaskTemplate
  71. .call(inputmask, true, 0)
  72. .slice(ndx, seekNext.call(inputmask, ndx, false, false))
  73. .join("")
  74. .replace(/'/g, ""),
  75. charCodeNdx = targetTemplate.indexOf(charCodes);
  76. // strip spaces from targetTemplate
  77. while (charCodeNdx > 0 && targetTemplate[charCodeNdx - 1] === " ")
  78. charCodeNdx--;
  79. const match =
  80. charCodeNdx === 0 &&
  81. !isMask.call(inputmask, ndx) &&
  82. (getTest.call(inputmask, ndx).match.nativeDef === charCodes.charAt(0) ||
  83. (getTest.call(inputmask, ndx).match.static === true &&
  84. getTest.call(inputmask, ndx).match.nativeDef ===
  85. "'" + charCodes.charAt(0)) ||
  86. (getTest.call(inputmask, ndx).match.nativeDef === " " &&
  87. (getTest.call(inputmask, ndx + 1).match.nativeDef ===
  88. charCodes.charAt(0) ||
  89. (getTest.call(inputmask, ndx + 1).match.static === true &&
  90. getTest.call(inputmask, ndx + 1).match.nativeDef ===
  91. "'" + charCodes.charAt(0)))));
  92. if (
  93. !match &&
  94. charCodeNdx > 0 &&
  95. !isMask.call(inputmask, ndx, false, true)
  96. ) {
  97. const nextPos = seekNext.call(inputmask, ndx);
  98. if (inputmask.caretPos.begin < nextPos) {
  99. inputmask.caretPos = { begin: nextPos };
  100. }
  101. }
  102. return match;
  103. }
  104. resetMaskSet.call(inputmask, false);
  105. inputmask.clicked = 0; // reset click counter to correctly determine the caretposition in checkval
  106. initialNdx = opts.radixPoint
  107. ? determineNewCaretPosition.call(
  108. inputmask,
  109. {
  110. begin: 0,
  111. end: 0
  112. },
  113. false,
  114. opts.__financeInput === false ? "radixFocus" : undefined
  115. ).begin
  116. : 0;
  117. maskset.p = initialNdx;
  118. inputmask.caretPos = { begin: initialNdx };
  119. let staticMatches = [],
  120. prevCaretPos = inputmask.caretPos;
  121. inputValue.forEach(function (charCode, ndx) {
  122. if (charCode !== undefined) {
  123. // inputfallback strips some elements out of the inputarray. $.each logically presents them as undefined
  124. /* if (maskset.validPositions[ndx] === undefined && inputValue[ndx] === getPlaceholder.call(inputmask, ndx) && isMask.call(inputmask, ndx, true) &&
  125. isValid.call(inputmask, ndx, inputValue[ndx], true, undefined, true, true) === false) {
  126. inputmask.caretPos.begin++;
  127. } else */
  128. // console.log("caret " + inputmask.caretPos.begin);
  129. const keypress = new $.Event("_checkval");
  130. keypress.key = charCode;
  131. charCodes += charCode;
  132. const lvp = getLastValidPosition.call(inputmask, undefined, true);
  133. if (!isTemplateMatch(initialNdx, charCodes)) {
  134. result = EventHandlers.keypressEvent.call(
  135. inputmask,
  136. keypress,
  137. true,
  138. false,
  139. strict,
  140. inputmask.caretPos.begin
  141. );
  142. if (result) {
  143. initialNdx = inputmask.caretPos.begin + 1;
  144. charCodes = "";
  145. }
  146. } else {
  147. result = EventHandlers.keypressEvent.call(
  148. inputmask,
  149. keypress,
  150. true,
  151. false,
  152. strict,
  153. lvp + 1
  154. );
  155. }
  156. if (result) {
  157. if (
  158. result.pos !== undefined &&
  159. maskset.validPositions[result.pos] &&
  160. maskset.validPositions[result.pos].match.static === true &&
  161. maskset.validPositions[result.pos].alternation === undefined
  162. ) {
  163. staticMatches.push(result.pos);
  164. if (!inputmask.isRTL) {
  165. result.forwardPosition = result.pos + 1;
  166. }
  167. }
  168. writeBuffer.call(
  169. inputmask,
  170. undefined,
  171. getBuffer.call(inputmask),
  172. result.forwardPosition,
  173. keypress,
  174. false
  175. );
  176. inputmask.caretPos = {
  177. begin: result.forwardPosition,
  178. end: result.forwardPosition
  179. };
  180. prevCaretPos = inputmask.caretPos;
  181. } else {
  182. if (
  183. maskset.validPositions[ndx] === undefined &&
  184. inputValue[ndx] === getPlaceholder.call(inputmask, ndx) &&
  185. isMask.call(inputmask, ndx, true)
  186. ) {
  187. inputmask.caretPos.begin++;
  188. } else inputmask.caretPos = prevCaretPos; // restore the caret position from before the failed validation
  189. }
  190. }
  191. });
  192. if (staticMatches.length > 0) {
  193. let sndx,
  194. validPos,
  195. nextValid = seekNext.call(inputmask, -1, undefined, false);
  196. if (
  197. (!isComplete.call(inputmask, getBuffer.call(inputmask)) &&
  198. staticMatches.length <= nextValid) ||
  199. (isComplete.call(inputmask, getBuffer.call(inputmask)) &&
  200. staticMatches.length > 0 &&
  201. staticMatches.length !== nextValid &&
  202. staticMatches[0] === 0)
  203. ) {
  204. // should check if is sequence starting from 0
  205. let nextSndx = nextValid;
  206. while ((sndx = staticMatches.shift()) !== undefined) {
  207. if (sndx < nextSndx) {
  208. const keypress = new $.Event("_checkval");
  209. validPos = maskset.validPositions[sndx];
  210. validPos.generatedInput = true;
  211. keypress.key = validPos.input;
  212. result = EventHandlers.keypressEvent.call(
  213. inputmask,
  214. keypress,
  215. true,
  216. false,
  217. strict,
  218. nextSndx
  219. );
  220. if (
  221. result &&
  222. result.pos !== undefined &&
  223. result.pos !== sndx &&
  224. maskset.validPositions[result.pos] &&
  225. maskset.validPositions[result.pos].match.static === true
  226. ) {
  227. staticMatches.push(result.pos);
  228. } else if (!result) break;
  229. nextSndx++;
  230. }
  231. }
  232. } else {
  233. // mark al statics as generated
  234. // while ((sndx = staticMatches.pop())) {
  235. // validPos = maskset.validPositions[sndx];
  236. // if (validPos) {
  237. // validPos.generatedInput = true;
  238. // }
  239. // }
  240. }
  241. }
  242. if (writeOut) {
  243. writeBuffer.call(
  244. inputmask,
  245. input,
  246. getBuffer.call(inputmask),
  247. result ? result.forwardPosition : inputmask.caretPos.begin,
  248. initiatingEvent || new $.Event("checkval"),
  249. initiatingEvent &&
  250. ((initiatingEvent.type === "input" &&
  251. inputmask.undoValue !== getBuffer.call(inputmask).join("")) ||
  252. initiatingEvent.type === "paste")
  253. );
  254. // for (var vndx in maskset.validPositions) {
  255. // if (maskset.validPositions[vndx].match.generated !== true) { //only remove non forced generated
  256. // delete maskset.validPositions[vndx].generatedInput; //clear generated markings ~ consider initializing with a value as fully typed
  257. // }
  258. // }
  259. }
  260. opts.skipOptionalPartCharacter = skipOptionalPartCharacter;
  261. }
  262. function HandleNativePlaceholder(npt, value) {
  263. const inputmask = npt ? npt.inputmask : this;
  264. if (ie) {
  265. if (
  266. npt.inputmask._valueGet() !== value &&
  267. (npt.placeholder !== value || npt.placeholder === "")
  268. ) {
  269. let buffer = getBuffer.call(inputmask).slice(),
  270. nptValue = npt.inputmask._valueGet();
  271. if (nptValue !== value) {
  272. const lvp = getLastValidPosition.call(inputmask);
  273. if (
  274. lvp === -1 &&
  275. nptValue === getBufferTemplate.call(inputmask).join("")
  276. ) {
  277. buffer = [];
  278. } else if (lvp !== -1) {
  279. // clearout optional tail of the mask
  280. clearOptionalTail.call(inputmask, buffer);
  281. }
  282. writeBuffer(npt, buffer);
  283. }
  284. }
  285. } else if (npt.placeholder !== value) {
  286. npt.placeholder = value;
  287. if (npt.placeholder === "") npt.removeAttribute("placeholder");
  288. }
  289. }
  290. function unmaskedvalue(input) {
  291. const inputmask = input ? input.inputmask : this,
  292. opts = inputmask.opts,
  293. maskset = inputmask.maskset;
  294. if (input) {
  295. if (input.inputmask === undefined) {
  296. return input.value;
  297. }
  298. if (input.inputmask && input.inputmask.refreshValue) {
  299. // forced refresh from the value form.reset
  300. applyInputValue(input, input.inputmask._valueGet(true));
  301. }
  302. }
  303. const umValue = [],
  304. vps = maskset.validPositions;
  305. for (let pndx = 0, vpl = vps.length; pndx < vpl; pndx++) {
  306. if (
  307. vps[pndx] &&
  308. vps[pndx].match &&
  309. (vps[pndx].match.static != true ||
  310. (Array.isArray(maskset.metadata) && vps[pndx].generatedInput !== true))
  311. ) {
  312. // only include generated input with multiple masks (check on metadata)
  313. umValue.push(vps[pndx].input);
  314. }
  315. }
  316. let unmaskedValue =
  317. umValue.length === 0
  318. ? ""
  319. : (inputmask.isRTL ? umValue.reverse() : umValue).join("");
  320. if (typeof opts.onUnMask === "function") {
  321. const bufferValue = (
  322. inputmask.isRTL
  323. ? getBuffer.call(inputmask).slice().reverse()
  324. : getBuffer.call(inputmask)
  325. ).join("");
  326. unmaskedValue = opts.onUnMask.call(
  327. inputmask,
  328. bufferValue,
  329. unmaskedValue,
  330. opts
  331. );
  332. }
  333. return unmaskedValue;
  334. }
  335. function writeBuffer(input, buffer, caretPos, event, triggerEvents) {
  336. const inputmask = input ? input.inputmask : this,
  337. opts = inputmask.opts,
  338. $ = inputmask.dependencyLib;
  339. if (event && typeof opts.onBeforeWrite === "function") {
  340. // buffer = buffer.slice(); //prevent uncontrolled manipulation of the internal buffer
  341. const result = opts.onBeforeWrite.call(
  342. inputmask,
  343. event,
  344. buffer,
  345. caretPos,
  346. opts
  347. );
  348. if (result) {
  349. if (result.refreshFromBuffer) {
  350. const refresh = result.refreshFromBuffer;
  351. refreshFromBuffer.call(
  352. inputmask,
  353. refresh === true ? refresh : refresh.start,
  354. refresh.end,
  355. result.buffer || buffer
  356. );
  357. buffer = getBuffer.call(inputmask, true);
  358. }
  359. if (caretPos !== undefined)
  360. caretPos = result.caret !== undefined ? result.caret : caretPos;
  361. }
  362. }
  363. if (input !== undefined) {
  364. input.inputmask._valueSet(buffer.join(""));
  365. if (
  366. caretPos !== undefined &&
  367. (event === undefined || event.type !== "blur")
  368. ) {
  369. // console.log(caretPos);
  370. caret.call(
  371. inputmask,
  372. input,
  373. caretPos,
  374. undefined,
  375. undefined,
  376. event !== undefined &&
  377. event.type === "keydown" &&
  378. (event.key === keys.Delete || event.key === keys.Backspace)
  379. );
  380. }
  381. input.inputmask.writeBufferHook === undefined ||
  382. input.inputmask.writeBufferHook(caretPos);
  383. if (triggerEvents === true) {
  384. const $input = $(input),
  385. nptVal = input.inputmask._valueGet();
  386. input.inputmask.skipInputEvent = true;
  387. $input.trigger("input");
  388. setTimeout(function () {
  389. // timeout needed for IE
  390. if (nptVal === getBufferTemplate.call(inputmask).join("")) {
  391. $input.trigger("cleared");
  392. } else if (isComplete.call(inputmask, buffer) === true) {
  393. $input.trigger("complete");
  394. }
  395. }, 0);
  396. }
  397. }
  398. }