inputHandling.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import {keys} from "./keycode.js";
  2. import {getMaskTemplate, getPlaceholder, getTest} from "./validation-tests";
  3. import {
  4. caret,
  5. determineNewCaretPosition,
  6. getBuffer, getBufferTemplate,
  7. getLastValidPosition,
  8. isMask,
  9. resetMaskSet,
  10. seekNext
  11. } from "./positioning";
  12. import {isComplete, refreshFromBuffer} from "./validation";
  13. import {ie} from "./environment";
  14. import {EventHandlers} from "./eventhandlers";
  15. export {applyInputValue, clearOptionalTail, checkVal, HandleNativePlaceholder, unmaskedvalue, writeBuffer};
  16. function applyInputValue(input, value) {
  17. const inputmask = input ? input.inputmask : this, opts = inputmask.opts;
  18. input.inputmask.refreshValue = false;
  19. if (typeof opts.onBeforeMask === "function") value = opts.onBeforeMask.call(inputmask, value, opts) || value;
  20. value = value.toString().split("");
  21. checkVal(input, true, false, value);
  22. inputmask.undoValue = inputmask._valueGet(true);
  23. if ((opts.clearMaskOnLostFocus || opts.clearIncomplete) && input.inputmask._valueGet() === getBufferTemplate.call(inputmask).join("") && getLastValidPosition.call(inputmask) === -1) {
  24. input.inputmask._valueSet("");
  25. }
  26. }
  27. //todo put on prototype?
  28. function clearOptionalTail(buffer) {
  29. const inputmask = this;
  30. buffer.length = 0;
  31. var template = getMaskTemplate.call(inputmask, true, 0, true, undefined, true), lmnt;
  32. while ((lmnt = template.shift()) !== undefined) buffer.push(lmnt);
  33. return buffer;
  34. }
  35. function checkVal(input, writeOut, strict, nptvl, initiatingEvent) {
  36. const inputmask = input ? input.inputmask : this,
  37. maskset = inputmask.maskset,
  38. opts = inputmask.opts, $ = inputmask.dependencyLib;
  39. var inputValue = nptvl.slice(),
  40. charCodes = "",
  41. initialNdx = -1,
  42. result = undefined, skipOptionalPartCharacter = opts.skipOptionalPartCharacter;
  43. opts.skipOptionalPartCharacter = ""; //see issue #2311
  44. function isTemplateMatch(ndx, charCodes) {
  45. var targetTemplate = getMaskTemplate.call(inputmask, true, 0).slice(ndx, seekNext.call(inputmask, ndx, false, false)).join("").replace(/'/g, ""),
  46. charCodeNdx = targetTemplate.indexOf(charCodes);
  47. //strip spaces from targetTemplate
  48. while (charCodeNdx > 0 && targetTemplate[charCodeNdx - 1] === " ") charCodeNdx--;
  49. var match = charCodeNdx === 0 && !isMask.call(inputmask, ndx)
  50. && (getTest.call(inputmask, ndx).match.nativeDef === charCodes.charAt(0)
  51. || (getTest.call(inputmask, ndx).match.static === true && getTest.call(inputmask, ndx).match.nativeDef === ("'" + charCodes.charAt(0)))
  52. || (getTest.call(inputmask, ndx).match.nativeDef === " " && (getTest.call(inputmask, ndx + 1).match.nativeDef === charCodes.charAt(0)
  53. || (getTest.call(inputmask, ndx + 1).match.static === true && getTest.call(inputmask, ndx + 1).match.nativeDef === ("'" + charCodes.charAt(0))))));
  54. if (!match && charCodeNdx > 0 && !isMask.call(inputmask, ndx, false, true)) {
  55. var nextPos = seekNext.call(inputmask, ndx);
  56. if (inputmask.caretPos.begin < nextPos) {
  57. inputmask.caretPos = {begin: nextPos};
  58. }
  59. }
  60. return match;
  61. }
  62. resetMaskSet.call(inputmask);
  63. maskset.tests = {}; //reset tests ~ possible after alternating
  64. initialNdx = opts.radixPoint ? determineNewCaretPosition.call(inputmask, {
  65. begin: 0,
  66. end: 0
  67. }, false, opts.__financeInput === false ? "radixFocus" : undefined).begin : 0;
  68. maskset.p = initialNdx;
  69. inputmask.caretPos = {begin: initialNdx};
  70. var staticMatches = [], prevCaretPos = inputmask.caretPos;
  71. inputValue.forEach(function (charCode, ndx) {
  72. if (charCode !== undefined) { //inputfallback strips some elements out of the inputarray. $.each logically presents them as undefined
  73. /*if (maskset.validPositions[ndx] === undefined && inputValue[ndx] === getPlaceholder.call(inputmask, ndx) && isMask.call(inputmask, ndx, true) &&
  74. isValid.call(inputmask, ndx, inputValue[ndx], true, undefined, true, true) === false) {
  75. inputmask.caretPos.begin++;
  76. } else*/
  77. {
  78. var keypress = new $.Event("_checkval");
  79. keypress.key = charCode;
  80. charCodes += charCode;
  81. var lvp = getLastValidPosition.call(inputmask, undefined, true);
  82. if (!isTemplateMatch(initialNdx, charCodes)) {
  83. result = EventHandlers.keypressEvent.call(inputmask, keypress, true, false, strict, inputmask.caretPos.begin);
  84. if (result) {
  85. initialNdx = inputmask.caretPos.begin + 1;
  86. charCodes = "";
  87. }
  88. } else {
  89. result = EventHandlers.keypressEvent.call(inputmask, keypress, true, false, strict, lvp + 1);
  90. }
  91. if (result) {
  92. if (result.pos !== undefined && maskset.validPositions[result.pos] && maskset.validPositions[result.pos].match.static === true && maskset.validPositions[result.pos].alternation === undefined) {
  93. staticMatches.push(result.pos);
  94. if (!inputmask.isRTL) {
  95. result.forwardPosition = result.pos + 1;
  96. }
  97. }
  98. writeBuffer.call(inputmask, undefined, getBuffer.call(inputmask), result.forwardPosition, keypress, false);
  99. inputmask.caretPos = {begin: result.forwardPosition, end: result.forwardPosition};
  100. prevCaretPos = inputmask.caretPos;
  101. } else {
  102. if (maskset.validPositions[ndx] === undefined && inputValue[ndx] === getPlaceholder.call(inputmask, ndx) && isMask.call(inputmask, ndx, true)) {
  103. inputmask.caretPos.begin++;
  104. } else inputmask.caretPos = prevCaretPos; //restore the caret position from before the failed validation
  105. }
  106. }
  107. }
  108. });
  109. if (staticMatches.length > 0) {
  110. var sndx, validPos, nextValid = seekNext.call(inputmask, -1, undefined, false);
  111. if ((!isComplete.call(inputmask, getBuffer.call(inputmask)) && staticMatches.length <= nextValid)
  112. || (isComplete.call(inputmask, getBuffer.call(inputmask)) && staticMatches.length > 0 && (staticMatches.length !== nextValid && staticMatches[0] === 0))) { //should check if is sequence starting from 0
  113. var nextSndx = nextValid;
  114. while ((sndx = staticMatches.shift()) !== undefined) {
  115. var keypress = new $.Event("_checkval");
  116. validPos = maskset.validPositions[sndx];
  117. validPos.generatedInput = true;
  118. keypress.key = validPos.input;
  119. result = EventHandlers.keypressEvent.call(inputmask, keypress, true, false, strict, nextSndx);
  120. if (result && result.pos !== undefined && result.pos !== sndx && maskset.validPositions[result.pos] && maskset.validPositions[result.pos].match.static === true) {
  121. staticMatches.push(result.pos);
  122. } else if (!result) break;
  123. nextSndx++;
  124. }
  125. } else { //mark al statics as generated
  126. // while ((sndx = staticMatches.pop())) {
  127. // validPos = maskset.validPositions[sndx];
  128. // if (validPos) {
  129. // validPos.generatedInput = true;
  130. // }
  131. // }
  132. }
  133. }
  134. if (writeOut) {
  135. writeBuffer.call(
  136. inputmask,
  137. input,
  138. getBuffer.call(inputmask), result ? result.forwardPosition : inputmask.caretPos.begin,
  139. initiatingEvent || new $.Event("checkval"),
  140. initiatingEvent && ((initiatingEvent.type === "input" && inputmask.undoValue !== getBuffer.call(inputmask).join("")) || initiatingEvent.type === "paste"));
  141. // for (var vndx in maskset.validPositions) {
  142. // if (maskset.validPositions[vndx].match.generated !== true) { //only remove non forced generated
  143. // delete maskset.validPositions[vndx].generatedInput; //clear generated markings ~ consider initializing with a value as fully typed
  144. // }
  145. // }
  146. }
  147. opts.skipOptionalPartCharacter = skipOptionalPartCharacter;
  148. }
  149. function HandleNativePlaceholder(npt, value) {
  150. const inputmask = npt ? npt.inputmask : this;
  151. if (ie) {
  152. if (npt.inputmask._valueGet() !== value && (npt.placeholder !== value || npt.placeholder === "")) {
  153. var buffer = getBuffer.call(inputmask).slice(),
  154. nptValue = npt.inputmask._valueGet();
  155. if (nptValue !== value) {
  156. var lvp = getLastValidPosition.call(inputmask);
  157. if (lvp === -1 && nptValue === getBufferTemplate.call(inputmask).join("")) {
  158. buffer = [];
  159. } else if (lvp !== -1) { //clearout optional tail of the mask
  160. clearOptionalTail.call(inputmask, buffer);
  161. }
  162. writeBuffer(npt, buffer);
  163. }
  164. }
  165. } else if (npt.placeholder !== value) {
  166. npt.placeholder = value;
  167. if (npt.placeholder === "") npt.removeAttribute("placeholder");
  168. }
  169. }
  170. function unmaskedvalue(input) {
  171. const inputmask = input ? input.inputmask : this,
  172. opts = inputmask.opts,
  173. maskset = inputmask.maskset;
  174. if (input) {
  175. if (input.inputmask === undefined) {
  176. return input.value;
  177. }
  178. if (input.inputmask && input.inputmask.refreshValue) { //forced refresh from the value form.reset
  179. applyInputValue(input, input.inputmask._valueGet(true));
  180. }
  181. }
  182. var umValue = [],
  183. vps = maskset.validPositions;
  184. for (let pndx = 0, vpl = vps.length; pndx < vpl; pndx++) {
  185. if (vps[pndx] && vps[pndx].match && (vps[pndx].match.static != true || (Array.isArray(maskset.metadata) && vps[pndx].generatedInput !== true))) {
  186. //only include generated input with multiple masks (check on metadata)
  187. umValue.push(vps[pndx].input);
  188. }
  189. }
  190. var unmaskedValue = umValue.length === 0 ? "" : (inputmask.isRTL ? umValue.reverse() : umValue).join("");
  191. if (typeof opts.onUnMask === "function") {
  192. var bufferValue = (inputmask.isRTL ? getBuffer.call(inputmask).slice().reverse() : getBuffer.call(inputmask)).join("");
  193. unmaskedValue = opts.onUnMask.call(inputmask, bufferValue, unmaskedValue, opts);
  194. }
  195. return unmaskedValue;
  196. }
  197. function writeBuffer(input, buffer, caretPos, event, triggerEvents) {
  198. const inputmask = input ? input.inputmask : this,
  199. opts = inputmask.opts,
  200. $ = inputmask.dependencyLib;
  201. if (event && typeof opts.onBeforeWrite === "function") {
  202. // buffer = buffer.slice(); //prevent uncontrolled manipulation of the internal buffer
  203. var result = opts.onBeforeWrite.call(inputmask, event, buffer, caretPos, opts);
  204. if (result) {
  205. if (result.refreshFromBuffer) {
  206. var refresh = result.refreshFromBuffer;
  207. refreshFromBuffer.call(inputmask, refresh === true ? refresh : refresh.start, refresh.end, result.buffer || buffer);
  208. buffer = getBuffer.call(inputmask, true);
  209. }
  210. if (caretPos !== undefined) caretPos = result.caret !== undefined ? result.caret : caretPos;
  211. }
  212. }
  213. if (input !== undefined) {
  214. input.inputmask._valueSet(buffer.join(""));
  215. if (caretPos !== undefined && (event === undefined || event.type !== "blur")) {
  216. // console.log(caretPos);
  217. caret.call(inputmask, input, caretPos, undefined, undefined, (event !== undefined && event.type === "keydown" && (event.key === keys.Delete || event.key === keys.Backspace)));
  218. }
  219. if (triggerEvents === true) {
  220. var $input = $(input), nptVal = input.inputmask._valueGet();
  221. input.inputmask.skipInputEvent = true;
  222. $input.trigger("input");
  223. setTimeout(function () { //timeout needed for IE
  224. if (nptVal === getBufferTemplate.call(inputmask).join("")) {
  225. $input.trigger("cleared");
  226. } else if (isComplete.call(inputmask, buffer) === true) {
  227. $input.trigger("complete");
  228. }
  229. }, 0);
  230. }
  231. }
  232. }