1/* 2 * Input Mask Core 3 * http://github.com/RobinHerbots/jquery.inputmask 4 * Copyright (c) 2010 - Robin Herbots 5 * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) 6 * Version: 0.0.0-dev 7 */ 8(function (factory) { 9 if (typeof define === "function" && define.amd) { 10 define(["./dependencyLibs/inputmask.dependencyLib", "./global/window", "./global/document"], factory); 11 } else if (typeof exports === "object") { 12 module.exports = factory(require("./dependencyLibs/inputmask.dependencyLib"), require("./global/window"), require("./global/document")); 13 } else { 14 window.Inputmask = factory(window.dependencyLib || jQuery, window, document); 15 } 16} 17(function ($, window, document, undefined) { 18 var ua = navigator.userAgent, 19 mobile = isInputEventSupported("touchstart"), //not entirely correct but will currently do 20 iemobile = /iemobile/i.test(ua), 21 iphone = /iphone/i.test(ua) && !iemobile; 22 23 function Inputmask(alias, options, internal) { 24 //allow instanciating without new 25 if (!(this instanceof Inputmask)) { 26 return new Inputmask(alias, options, internal); 27 } 28 29 this.el = undefined; 30 this.events = {}; 31 this.maskset = undefined; 32 this.refreshValue = false; //indicate a refresh from the inputvalue is needed (form.reset) 33 34 if (internal !== true) { 35 //init options 36 if ($.isPlainObject(alias)) { 37 options = alias; 38 } else { 39 options = options || {}; 40 options.alias = alias; 41 } 42 this.opts = $.extend(true, {}, this.defaults, options); 43 this.noMasksCache = options && options.definitions !== undefined; 44 this.userOptions = options || {}; //user passed options 45 this.isRTL = this.opts.numericInput; 46 resolveAlias(this.opts.alias, options, this.opts); 47 } 48 } 49 50 Inputmask.prototype = { 51 dataAttribute: "data-inputmask", //data attribute prefix used for attribute binding 52 //options default 53 defaults: { 54 placeholder: "_", 55 optionalmarker: { 56 start: "[", 57 end: "]" 58 }, 59 quantifiermarker: { 60 start: "{", 61 end: "}" 62 }, 63 groupmarker: { 64 start: "(", 65 end: ")" 66 }, 67 alternatormarker: "|", 68 escapeChar: "\\", 69 mask: null, //needs tobe null instead of undefined as the extend method does not consider props with the undefined value 70 regex: null, //regular expression as a mask 71 oncomplete: $.noop, //executes when the mask is complete 72 onincomplete: $.noop, //executes when the mask is incomplete and focus is lost 73 oncleared: $.noop, //executes when the mask is cleared 74 repeat: 0, //repetitions of the mask: * ~ forever, otherwise specify an integer 75 greedy: true, //true: allocated buffer for the mask and repetitions - false: allocate only if needed 76 autoUnmask: false, //automatically unmask when retrieving the value with $.fn.val or value if the browser supports __lookupGetter__ or getOwnPropertyDescriptor 77 removeMaskOnSubmit: false, //remove the mask before submitting the form. 78 clearMaskOnLostFocus: true, 79 insertMode: true, //insert the input or overwrite the input 80 clearIncomplete: false, //clear the incomplete input on blur 81 alias: null, 82 onKeyDown: $.noop, //callback to implement autocomplete on certain keys for example. args => event, buffer, caretPos, opts 83 onBeforeMask: null, //executes before masking the initial value to allow preprocessing of the initial value. args => initialValue, opts => return processedValue 84 onBeforePaste: function (pastedValue, opts) { 85 return $.isFunction(opts.onBeforeMask) ? opts.onBeforeMask.call(this, pastedValue, opts) : pastedValue; 86 }, //executes before masking the pasted value to allow preprocessing of the pasted value. args => pastedValue, opts => return processedValue 87 onBeforeWrite: null, //executes before writing to the masked element. args => event, opts 88 onUnMask: null, //executes after unmasking to allow postprocessing of the unmaskedvalue. args => maskedValue, unmaskedValue, opts 89 showMaskOnFocus: true, //show the mask-placeholder when the input has focus 90 showMaskOnHover: true, //show the mask-placeholder when hovering the empty input 91 onKeyValidation: $.noop, //executes on every key-press with the result of isValid. Params: key, result, opts 92 skipOptionalPartCharacter: " ", //a character which can be used to skip an optional part of a mask 93 numericInput: false, //numericInput input direction style (input shifts to the left while holding the caret position) 94 rightAlign: false, //align to the right 95 undoOnEscape: true, //pressing escape reverts the value to the value before focus 96 //numeric basic properties 97 radixPoint: "", //".", // | "," 98 radixPointDefinitionSymbol: undefined, //set the radixPoint definitionSymbol ~ used for awareness of the radixpoint 99 groupSeparator: "", //",", // | "." 100 //numeric basic properties 101 keepStatic: null, //try to keep the mask static while typing. Decisions to alter the mask will be posponed if possible - null see auto selection for multi masks 102 positionCaretOnTab: true, //when enabled the caret position is set after the latest valid position on TAB 103 tabThrough: false, //allows for tabbing through the different parts of the masked field 104 supportsInputType: ["text", "tel", "password", "search"], //list with the supported input types 105 //specify keyCodes which should not be considered in the keypress event, otherwise the preventDefault will stop their default behavior especially in FF 106 ignorables: [8, 9, 13, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 93, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 0, 229], 107 isComplete: null, //override for isComplete - args => buffer, opts - return true || false 108 canClearPosition: $.noop, //hook to alter the clear behavior in the stripValidPositions args => maskset, position, lastValidPosition, opts => return true|false/command object 109 preValidation: null, //hook to preValidate the input. Usefull for validating regardless the definition. args => buffer, pos, char, isSelection, opts => return true/false/command object 110 postValidation: null, //hook to postValidate the result from isValid. Usefull for validating the entry as a whole. args => buffer, currentResult, opts => return true/false/json 111 staticDefinitionSymbol: undefined, //specify a definitionSymbol for static content, used to make matches for alternators 112 jitMasking: false, //just in time masking ~ only mask while typing, can n (number), true or false 113 nullable: true, //return nothing instead of the buffertemplate when the user hasn't entered anything. 114 inputEventOnly: false, //dev option - testing inputfallback behavior 115 noValuePatching: false, //disable value property patching 116 positionCaretOnClick: "lvp", //none, lvp (based on the last valid position (default), radixFocus (position caret to radixpoint on initial click) 117 casing: null, //mask-level casing. Options: null, "upper", "lower" or "title" or callback args =>
117 elem, test, pos, validPositions return charValue 118 inputmode: "verbatim", //specify the inputmode - already in place for when browsers will support it 119 colorMask: false, //enable css styleable mask 120 disablePredictiveText: false, //disable Predictive Text on mobile devices 121 importDataAttributes: true //import data-inputmask attributes 122 }, 123 definitions: { 124 "9": { //\uFF11-\uFF19 #1606 125 validator: "[0-9\uFF11-\uFF19]", 126 cardinality: 1, 127 definitionSymbol: "*" 128 }, 129 "a": { //\u0410-\u044F\u0401\u0451\u00C0-\u00FF\u00B5 #76 130 validator: "[A-Za-z\u0410-\u044F\u0401\u0451\u00C0-\u00FF\u00B5]", 131 cardinality: 1, 132 definitionSymbol: "*" 133 }, 134 "*": { 135 validator: "[0-9\uFF11-\uFF19A-Za-z\u0410-\u044F\u0401\u0451\u00C0-\u00FF\u00B5]", 136 cardinality: 1 137 } 138 }, 139 aliases: {}, //aliases definitions => see jquery.inputmask.extensions.js 140 masksCache: {}, 141 mask: function (elems) { 142 var that = this; 143 144 function importAttributeOptions(npt, opts, userOptions, dataAttribute) { 145 if (opts.importDataAttributes === true) { 146 var attrOptions = npt.getAttribute(dataAttribute), 147 option, dataoptions, optionData, p; 148 149 function importOption(option, optionData) { 150 optionData = optionData !== undefined ? optionData : npt.getAttribute(dataAttribute + "-" + option); 151 if (optionData !== null) { 152 if (typeof optionData === "string") { 153 if (option.indexOf("on") === 0) optionData = window[optionData]; //get function definition 154 else if (optionData === "false") optionData = false; 155 else if (optionData === "true") optionData = true; 156 } 157 userOptions[option] = optionData; 158 } 159 } 160 161 if (attrOptions && attrOptions !== "") { 162 attrOptions = attrOptions.replace(new RegExp("'", "g"), '"'); 163 dataoptions = JSON.parse("{" + attrOptions + "}"); 164 } 165 166 //resolve aliases 167 if (dataoptions) { //pickup alias from dataAttribute 168 optionData = undefined; 169 for (p in dataoptions) { 170 if (p.toLowerCase() === "alias") { 171 optionData = dataoptions[p]; 172 break; 173 } 174 } 175 } 176 importOption("alias", optionData); //pickup alias from dataAttribute-alias 177 if (userOptions.alias) { 178 resolveAlias(userOptions.alias, userOptions, opts); 179 } 180 181 for (option in opts) { 182 if (dataoptions) { 183 optionData = undefined; 184 for (p in dataoptions) { 185 if (p.toLowerCase() === option.toLowerCase()) { 186 optionData = dataoptions[p]; 187 break; 188 } 189 } 190 } 191 importOption(option, optionData); 192 } 193 } 194 $.extend(true, opts, userOptions); 195 196 //handle dir=rtl 197 if (npt.dir === "rtl" || opts.rightAlign) { 198 npt.style.textAlign = "right"; 199 } 200 201 if (npt.dir === "rtl" || opts.numericInput) { 202 npt.dir = "ltr"; 203 npt.removeAttribute("dir"); 204 opts.isRTL = true; 205 } 206 207 return opts; 208 } 209 210 if (typeof elems === "string") { 211 elems = document.getElementById(elems) || document.querySelectorAll(elems); 212 } 213 elems = elems.nodeName ? [elems] : elems; 214 $.each(elems, function (ndx, el) { 215 var scopedOpts = $.extend(true, {}, that.opts); 216 importAttributeOptions(el, scopedOpts, $.extend(true, {}, that.userOptions), that.dataAttribute); 217 var maskset = generateMaskSet(scopedOpts, that.noMasksCache); 218 if (maskset !== undefined) { 219 if (el.inputmask !== undefined) { 220 el.inputmask.opts.autoUnmask = true; //force autounmasking when remasking 221 el.inputmask.remove(); 222 } 223 //store inputmask instance on the input with element reference 224 el.inputmask = new Inputmask(undefined, undefined, true); 225 el.inputmask.opts = scopedOpts; 226 el.inputmask.noMasksCache = that.noMasksCache; 227 el.inputmask.userOptions = $.extend(true, {}, that.userOptions); 228 el.inputmask.isRTL = scopedOpts.isRTL || scopedOpts.numericInput; 229 el.inputmask.el = el; 230 el.inputmask.maskset = maskset; 231 232 $.data(el, "_inputmask_opts", scopedOpts); 233 234 maskScope.call(el.inputmask, { 235 "action": "mask" 236 }); 237 } 238 }); 239 return elems && elems[0] ? (elems[0].inputmask || this) : this; 240 }, 241 option: function (options, noremask) { //set extra options || retrieve value of a current option 242 if (typeof options === "string") { 243 return this.opts[options]; 244 } else if (typeof options === "object") { 245 $.extend(this.userOptions, options); //user passed options 246 //remask 247 if (this.el && noremask !== true) { 248 this.mask(this.el); 249 } 250 return this; 251 } 252 }, 253 unmaskedvalue: function (value) { 254 this.maskset = this.maskset || generateMaskSet(this.opts, this.noMasksCache); 255 return maskScope.call(this, { 256 "action": "unmaskedvalue", 257 "value": value 258 }); 259 }, 260 remove: function () { 261 return maskScope.call(this, { 262 "action": "remove" 263 }); 264 }, 265 getemptymask: function () { //return the default (empty) mask value, usefull for setting the default value in validation 266 this.maskset = this.maskset || generateMaskSet(this.opts, this.noMasksCache); 267 return maskScope.call(this, { 268 "action": "getemptymask" 269 }); 270 }, 271 hasMaskedValue: function () { //check wheter the returned value is masked or not;
271 currently only works reliable when using jquery.val fn to retrieve the value 272 return !this.opts.autoUnmask; 273 }, 274 isComplete: function () { 275 this.maskset = this.maskset || generateMaskSet(this.opts, this.noMasksCache); 276 return maskScope.call(this, { 277 "action": "isComplete" 278 }); 279 }, 280 getmetadata: function () { //return mask metadata if exists 281 this.maskset = this.maskset || generateMaskSet(this.opts, this.noMasksCache); 282 return maskScope.call(this, { 283 "action": "getmetadata" 284 }); 285 }, 286 isValid: function (value) { 287 this.maskset = this.maskset || generateMaskSet(this.opts, this.noMasksCache); 288 return maskScope.call(this, { 289 "action": "isValid", 290 "value": value 291 }); 292 }, 293 format: function (value, metadata) { 294 this.maskset = this.maskset || generateMaskSet(this.opts, this.noMasksCache); 295 return maskScope.call(this, { 296 "action": "format", 297 "value": value, 298 "metadata": metadata //true/false getmetadata 299 }); 300 }, 301 analyseMask: function (mask, regexMask, opts) { 302 var tokenizer = /(?:[?*+]|\{[0-9\+\*]+(?:,[0-9\+\*]*)?\})|[^.?*+^${[]()|\\]+|./g, 303 //Thx to https://github.com/slevithan/regex-colorizer for the regexTokenizer regex 304 regexTokenizer = /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g, 305 escaped = false, 306 currentToken = new MaskToken(), 307 match, 308 m, 309 openenings = [], 310 maskTokens = [], 311 openingToken, 312 currentOpeningToken, 313 alternator, 314 lastMatch, 315 groupToken; 316 317 function MaskToken(isGroup, isOptional, isQuantifier, isAlternator) { 318 this.matches = []; 319 this.openGroup = isGroup || false; 320 this.alternatorGroup = false; 321 this.isGroup = isGroup || false; 322 this.isOptional = isOptional || false; 323 this.isQuantifier = isQuantifier || false; 324 this.isAlternator = isAlternator || false; 325 this.quantifier = { 326 min: 1, 327 max: 1 328 }; 329 } 330 331 //test definition => {fn: RegExp/function, cardinality: int, optionality: bool, newBlockMarker: bool, casing: null/upper/lower, def: definitionSymbol, placeholder: placeholder, mask: real maskDefinition} 332 function insertTestDefinition(mtoken, element, position) { 333 position = position !== undefined ? position : mtoken.matches.length; 334 var prevMatch = mtoken.matches[position - 1]; 335 if (regexMask) { 336 if (element.indexOf("[") === 0 || (escaped && /\\d|\\s|\\w]/i.test(element)) || element === ".") { 337 mtoken.matches.splice(position++, 0, { 338 fn: new RegExp(element, opts.casing ? "i" : ""), 339 cardinality: 1, 340 optionality: mtoken.isOptional, 341 newBlockMarker: prevMatch === undefined || prevMatch.def !== element, 342 casing: null, 343 def: element, 344 placeholder: undefined, 345 nativeDef: element 346 }); 347 } else { 348 if (escaped) element = element[element.length - 1]; 349 $.each(element.split(""), function (ndx, lmnt) { 350 prevMatch = mtoken.matches[position - 1]; 351 mtoken.matches.splice(position++, 0, { 352 fn: null, 353 cardinality: 0, 354 optionality: mtoken.isOptional, 355 newBlockMarker: prevMatch === undefined || (prevMatch.def !== lmnt && prevMatch.fn !== null), 356 casing: null, 357 def: opts.staticDefinitionSymbol || lmnt, 358 placeholder: opts.staticDefinitionSymbol !== undefined ? lmnt : undefined, 359 nativeDef: lmnt 360 }); 361 }); 362 } 363 escaped = false;
364 } else { 365 var maskdef = (opts.definitions ? opts.definitions[element] : undefined) || Inputmask.prototype.definitions[element]; 366 if (maskdef && !escaped) { 367 var prevalidators = maskdef.prevalidator, 368 prevalidatorsL = prevalidators ? prevalidators.length : 0; 369 //handle prevalidators 370 for (var i = 1; i < maskdef.cardinality; i++) { 371 var prevalidator = prevalidatorsL >= i ? prevalidators[i - 1] : [], 372 validator = prevalidator.validator, 373 cardinality = prevalidator.cardinality; 374 mtoken.matches.splice(position++, 0, { 375 fn: validator ? typeof validator === "string" ? new RegExp(validator, opts.casing ? "i" : "") : new function () { 376 this.test = validator; 377 } : new RegExp("."), 378 cardinality: cardinality ? cardinality : 1, 379 optionality: mtoken.isOptional, 380 newBlockMarker: prevMatch === undefined || prevMatch.def !== (maskdef.definitionSymbol || element), 381 casing: maskdef.casing, 382 def: maskdef.definitionSymbol || element, 383 placeholder: maskdef.placeholder, 384 nativeDef: element 385 }); 386 prevMatch = mtoken.matches[position - 1]; 387 } 388 mtoken.matches.splice(position++, 0, { 389 fn: maskdef.validator ? typeof maskdef.validator == "string" ? new RegExp(maskdef.validator, opts.casing ? "i" : "") : new function () { 390 this.test = maskdef.validator; 391 } : new RegExp("."), 392 cardinality: maskdef.cardinality, 393 optionality: mtoken.isOptional, 394 newBlockMarker: prevMatch === undefined || prevMatch.def !== (maskdef.definitionSymbol || element), 395 casing: maskdef.casing, 396 def: maskdef.definitionSymbol || element, 397 placeholder: maskdef.placeholder, 398 nativeDef: element 399 }); 400 } else { 401 mtoken.matches.splice(position++, 0, { 402 fn: null, 403 cardinality: 0, 404 optionality: mtoken.isOptional, 405 newBlockMarker: prevMatch === undefined || (prevMatch.def !== element && prevMatch.fn !== null), 406 casing: null, 407 def: opts.staticDefinitionSymbol || element, 408 placeholder: opts.staticDefinitionSymbol !== undefined ? element : undefined, 409 nativeDef: element 410 }); 411 escaped = false; 412 } 413 } 414 } 415 416 function verifyGroupMarker(maskToken) { 417 if (maskToken && maskToken.matches) { 418 $.each(maskToken.matches, function (ndx, token) { 419 var nextToken = maskToken.matches[ndx + 1]; 420 if ((nextToken === undefined || (nextToken.matches === undefined || nextToken.isQuantifier === false)) && token && token.isGroup) { //this is not a group but a normal mask => convert 421 token.isGroup = false; 422 if (!regexMask) { 423 insertTestDefinition(token, opts.groupmarker.start, 0); 424 if (token.openGroup !== true) { 425 insertTestDefinition(token, opts.groupmarker.end); 426 } 427 } 428 } 429 verifyGroupMarker(token); 430 }); 431 } 432 } 433 434 function defaultCase() { 435 if (openenings.length > 0) { 436 currentOpeningToken = openenings[openenings.length - 1]; 437 insertTestDefinition(currentOpeningToken, m); 438 if (currentOpeningToken.isAlternator) { //handle alternator a | b case 439 alternator = openenings.pop(); 440 for (var mndx = 0; mndx < alternator.matches.length; mndx++) { 441 alternator.matches[mndx].isGroup = false; //don't mark alternate groups as group 442 } 443 if (openenings.length > 0) { 444 currentOpeningToken = openenings[openenings.length - 1]; 445 currentOpeningToken.matches.push(alternator); 446 } else { 447 currentToken.matches.push(alternator); 448 } 449 } 450 } else { 451 insertTestDefinition(currentToken, m); 452 } 453 } 454 455 function reverseTokens(maskToken) { 456 function reverseStatic(st) { 457 if (st === opts.optionalmarker.start) st = opts.optionalmarker.end; 458 else if (st === opts.optionalmarker.end) st = opts.optionalmarker.start; 459 else if (st === opts.groupmarker.start) st = opts.groupmarker.end; 460 else if (st === opts.groupmarker.end) st = opts.groupmarker.start; 461 462 return st; 463 } 464 465 maskToken.matches = maskToken.matches.reverse(); 466 for (var match in maskToken.matches) { 467 if (maskToken.matches.hasOwnProperty(match)) { 468 var intMatch = parseInt(match); 469 if (maskToken.matches[match].isQuantifier && maskToken.matches[intMatch + 1] && maskToken.matches[intMatch + 1].isGroup) { //reposition quantifier 470 var qt = maskToken.matches[match]; 471 maskToken.matches.splice(match, 1); 472 maskToken.matches.splice(intMatch + 1, 0, qt); 473 } 474 if (maskToken.matches[match].matches !== undefined) { 475 maskToken.matches[match] = reverseTokens(maskToken.matches[match]); 476 } else { 477 maskToken.matches[match] = reverseStatic(maskToken.matches[match]); 478 } 479 } 480 } 481 482 return maskToken; 483 } 484 485 if (regexMask) { 486 opts.optionalmarker.start = undefined; 487 opts.optionalmarker.end = undefined; 488 } 489 while (match = regexMask ? regexTokenizer.exec(mask) : tokenizer.exec(mask)) { 490 m = match[0]; 491 492 if (regexMask) { 493 switch (m.charAt(0)) { 494 //Quantifier 495 case "?": 496 m = "{0,1}"; 497 break; 498 case "+": 499 case "*": 500 m = "{" + m + "}"; 501 break; 502 } 503 } 504 505 if (escaped) { 506 defaultCase(); 507 continue; 508 } 509 switch (m.charAt(0)) { 510 case opts.escapeChar: 511 escaped = true; 512 if (regexMask) { 513 defaultCase(); 514 } 515 break; 516 case opts.optionalmarker.end: 517 // optional closing 518 case opts.groupmarker.end: 519 // Group closing 520 openingToken = openenings.pop(); 521 openingToken.openGroup = false; //mark group as complete 522 if (openingToken !== undefined) { 523 if (openenings.length > 0) { 524 currentOpeningToken = openenings[openenings.length - 1]; 525 currentOpeningToken.matches.push(openingToken); 526 if (currentOpeningToken.isAlternator) { //handle alternator (a) | (b) case 527 alternator = openenings.pop(); 528 for (var mndx = 0; mndx < alternator.matches.length; mndx++) { 529 alternator.matches[mndx].isGroup = false; //don't mark alternate groups as group 530 alternator.matches[mndx].alternatorGroup = false;
531 } 532 if (openenings.length > 0) { 533 currentOpeningToken = openenings[openenings.length - 1]; 534 currentOpeningToken.matches.push(alternator); 535 } else { 536 currentToken.matches.push(alternator); 537 } 538 } 539 } else { 540 currentToken.matches.push(openingToken); 541 } 542 } else defaultCase(); 543 break; 544 case opts.optionalmarker.start: 545 // optional opening 546 openenings.push(new MaskToken(false, true)); 547 break; 548 case opts.groupmarker.start: 549 // Group opening 550 openenings.push(new MaskToken(true)); 551 break; 552 case opts.quantifiermarker.start: 553 //Quantifier 554 var quantifier = new MaskToken(false, false, true); 555 556 m = m.replace(/[{}]/g, ""); 557 var mq = m.split(","), 558 mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]), 559 mq1 = mq.length === 1 ? mq0 : (isNaN(mq[1]) ? mq[1] : parseInt(mq[1])); 560 if (mq1 === "*" || mq1 === "+") { 561 mq0 = mq1 === "*" ? 0 : 1; 562 } 563 quantifier.quantifier = { 564 min: mq0, 565 max: mq1 566 }; 567 if (openenings.length > 0) { 568 var matches = openenings[openenings.length - 1].matches; 569 match = matches.pop(); 570 if (!match.isGroup) { 571 groupToken = new MaskToken(true); 572 groupToken.matches.push(match); 573 match = groupToken; 574 } 575 matches.push(match); 576 matches.push(quantifier); 577 } else { 578 match = currentToken.matches.pop(); 579 if (!match.isGroup) { 580 if (regexMask && match.fn === null) { 581 if (match.def === ".") match.fn = new RegExp(match.def, opts.casing ? "i" : ""); 582 } 583 584 groupToken = new MaskToken(true); 585 groupToken.matches.push(match); 586 match = groupToken; 587 } 588 currentToken.matches.push(match); 589 currentToken.matches.push(quantifier); 590 } 591 break; 592 case opts.alternatormarker: 593 if (openenings.length > 0) { 594 currentOpeningToken = openenings[openenings.length - 1]; 595 var subToken = currentOpeningToken.matches[currentOpeningToken.matches.length - 1]; 596 if (currentOpeningToken.openGroup && //regexp alt syntax 597 (subToken.matches === undefined || (subToken.isGroup === false && subToken.isAlternator === false))) { //alternations within group 598 lastMatch = openenings.pop(); 599 } else { 600 lastMatch = currentOpeningToken.matches.pop(); 601 } 602 } else { 603 lastMatch = currentToken.matches.pop(); 604 } 605 if (lastMatch.isAlternator) { 606 openenings.push(lastMatch); 607 } else { 608 if (lastMatch.alternatorGroup) { 609 alternator = openenings.pop(); 610 lastMatch.alternatorGroup = false;
611 } else { 612 alternator = new MaskToken(false, false, false, true); 613 } 614 alternator.matches.push(lastMatch); 615 openenings.push(alternator); 616 if (lastMatch.openGroup) { //regexp alt syntax 617 lastMatch.openGroup = false; 618 var alternatorGroup = new MaskToken(true); 619 alternatorGroup.alternatorGroup = true; 620 openenings.push(alternatorGroup); 621 } 622 } 623 break; 624 default: 625 defaultCase(); 626 } 627 } 628 629 while (openenings.length > 0) { 630 openingToken = openenings.pop(); 631 currentToken.matches.push(openingToken); 632 } 633 if (currentToken.matches.length > 0) { 634 verifyGroupMarker(currentToken); 635 maskTokens.push(currentToken); 636 } 637 638 if (opts.numericInput || opts.isRTL) { 639 reverseTokens(maskTokens[0]); 640 } 641 // console.log(JSON.stringify(maskTokens)); 642 return maskTokens; 643 } 644 }; 645 646 //apply defaults, definitions, aliases 647 Inputmask.extendDefaults = function (options) { 648 $.extend(true, Inputmask.prototype.defaults, options); 649 }; 650 Inputmask.extendDefinitions = function (definition) { 651 $.extend(true, Inputmask.prototype.definitions, definition); 652 }; 653 Inputmask.extendAliases = function (alias) { 654 $.extend(true, Inputmask.prototype.aliases, alias); 655 }; 656 //static fn on inputmask 657 Inputmask.format = function (value, options, metadata) { 658 return Inputmask(options).format(value, metadata); 659 }; 660 Inputmask.unmask = function (value, options) { 661 return Inputmask(options).unmaskedvalue(value); 662 }; 663 Inputmask.isValid = function (value, options) { 664 return Inputmask(options).isValid(value); 665 }; 666 Inputmask.remove = function (elems) { 667 $.each(elems, function (ndx, el) { 668 if (el.inputmask) el.inputmask.remove(); 669 }); 670 }; 671 Inputmask.escapeRegex = function (str) { 672 var specials = ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\", "$", "^"]; 673 return str.replace(new RegExp("(\\" + specials.join("|\\") + ")", "gim"), "\\$1"); 674 }; 675 Inputmask.keyCode = { 676 ALT: 18, 677 BACKSPACE: 8, 678 BACKSPACE_SAFARI: 127, 679 CAPS_LOCK: 20, 680 COMMA: 188, 681 COMMAND: 91, 682 COMMAND_LEFT: 91, 683 COMMAND_RIGHT: 93, 684 CONTROL: 17, 685 DELETE: 46, 686 DOWN: 40, 687 END: 35, 688 ENTER: 13, 689 ESCAPE: 27, 690 HOME: 36, 691 INSERT: 45, 692 LEFT: 37, 693 MENU: 93, 694 NUMPAD_ADD: 107, 695 NUMPAD_DECIMAL: 110, 696 NUMPAD_DIVIDE: 111, 697 NUMPAD_ENTER: 108, 698 NUMPAD_MULTIPLY: 106, 699 NUMPAD_SUBTRACT: 109, 700 PAGE_DOWN: 34, 701 PAGE_UP: 33, 702 PERIOD: 190, 703 RIGHT: 39, 704 SHIFT: 16, 705 SPACE: 32, 706 TAB: 9, 707 UP: 38, 708 WINDOWS: 91, 709 X: 88 710 }; 711 712 function resolveAlias(aliasStr, options, opts) { 713 var aliasDefinition = Inputmask.prototype.aliases[aliasStr]; 714 if (aliasDefinition) { 715 if (aliasDefinition.alias) resolveAlias(aliasDefinition.alias, undefined, opts); //alias is another alias 716 $.extend(true, opts, aliasDefinition); //merge alias definition in the options 717 $.extend(true, opts, options); //reapply extra given options 718 return true; 719 } else //alias not found - try as mask 720 if (opts.mask === null) { 721 opts.mask = aliasStr; 722 } 723 724 return false; 725 } 726 727 function generateMaskSet(opts, nocache) { 728 function generateMask(mask, metadata, opts) { 729 var regexMask = false; 730 if (mask === null || mask === "") { 731 regexMask = opts.regex !== null; 732 if (regexMask) { 733 mask = opts.regex; 734 mask = mask.replace(/^(\^)(.*)(\$)$/, "$2"); 735 } else { 736 regexMask = true; 737 mask = ".*"; 738 } 739 } 740 if (mask.length === 1 && opts.greedy === false && opts.repeat !== 0) { 741 opts.placeholder = ""; 742 } //hide placeholder with single non-greedy mask 743 if (opts.repeat > 0 || opts.repeat === "*" || opts.repeat === "+") { 744 var repeatStart = opts.repeat === "*" ? 0 : (opts.repeat === "+" ? 1 : opts.repeat); 745 mask = opts.groupmarker.start + mask + opts.groupmarker.end + opts.quantifiermarker.start + repeatStart + "," + opts.repeat + opts.quantifiermarker.end; 746 } 747 748 // console.log(mask); 749 var masksetDefinition, 750 maskdefKey = regexMask ? "regex_" + opts.regex : (opts.numericInput ? mask.split("").reverse().join("") : mask); 751 if (Inputmask.prototype.masksCache[maskdefKey] === undefined || nocache === true) { 752 masksetDefinition = { 753 "mask": mask,
754 "maskToken": Inputmask.prototype.analyseMask(mask, regexMask, opts), 755 "validPositions": {}, 756 "_buffer": undefined, 757 "buffer": undefined, 758 "tests": {}, 759 "metadata": metadata, 760 maskLength: undefined 761 }; 762 if (nocache !== true) { 763 Inputmask.prototype.masksCache[maskdefKey] = masksetDefinition; 764 masksetDefinition = $.extend(true, {}, Inputmask.prototype.masksCache[maskdefKey]); 765 } 766 } else masksetDefinition = $.extend(true, {}, Inputmask.prototype.masksCache[maskdefKey]); 767 768 return masksetDefinition; 769 } 770 771 var ms; 772 773 if ($.isFunction(opts.mask)) { //allow mask to be a preprocessing fn - should return a valid mask 774 opts.mask = opts.mask(opts); 775 } 776 if ($.isArray(opts.mask)) { 777 if (opts.mask.length > 1) { 778 opts.keepStatic = opts.keepStatic === null ? true : opts.keepStatic; //enable by default when passing multiple masks when the option is not explicitly specified 779 var altMask = opts.groupmarker.start; 780 $.each(opts.numericInput ? opts.mask.reverse() : opts.mask, function (ndx, msk) { 781 if (altMask.length > 1) { 782 altMask += opts.groupmarker.end + opts.alternatormarker + opts.groupmarker.start; 783 } 784 if (msk.mask !== undefined && !$.isFunction(msk.mask)) { 785 altMask += msk.mask; 786 } else { 787 altMask += msk; 788 } 789 }); 790 altMask += opts.groupmarker.end; 791 // console.log(altMask); 792 return generateMask(altMask, opts.mask, opts); 793 } else opts.mask = opts.mask.pop(); 794 } 795 796 if (opts.mask && opts.mask.mask !== undefined && !$.isFunction(opts.mask.mask)) { 797 ms = generateMask(opts.mask.mask, opts.mask, opts); 798 } else { 799 ms = generateMask(opts.mask, opts.mask, opts); 800 } 801 802 return ms; 803 }; 804 805 function isInputEventSupported(eventName) { 806 var el = document.createElement("input"), 807 evName = "on" + eventName, 808 isSupported = (evName in el); 809 if (!isSupported) { 810 el.setAttribute(evName, "return;"); 811 isSupported = typeof el[evName] === "function"; 812 } 813 el = null; 814 return isSupported; 815 } 816 817 //masking scope 818 //actionObj definition see below 819 function maskScope(actionObj, maskset, opts) { 820 maskset = maskset || this.maskset; 821 opts = opts || this.opts; 822 var inputmask = this, 823 el = this.el, 824 isRTL = this.isRTL, 825 undoValue, 826 $el, 827 skipKeyPressEvent = false, //Safari 5.1.x - modal dialog fires keypress twice workaround 828 skipInputEvent = false, //skip when triggered from within inputmask 829 ignorable = false, 830 maxLength, 831 mouseEnter = false, 832 colorMask, 833 trackCaret = false; 834 835 //maskset helperfunctions 836 function getMaskTemplate(baseOnInput, minimalPos, includeMode) { 837 //includeMode true => input, undefined => placeholder, false => mask 838 minimalPos = minimalPos || 0; 839 var maskTemplate = [], 840 ndxIntlzr, pos = 0, 841 test, testPos, lvp = getLastValidPosition(); 842 do { 843 if (baseOnInput === true && getMaskSet().validPositions[pos]) { 844 testPos = getMaskSet().validPositions[pos]; 845 test = testPos.match; 846 ndxIntlzr = testPos.locator.slice(); 847 maskTemplate.push(includeMode === true ? testPos.input : includeMode === false ? test.nativeDef : getPlaceholder(pos, test)); 848 } else { 849 testPos = getTestTemplate(pos, ndxIntlzr, pos - 1); 850 test = testPos.match; 851 ndxIntlzr = testPos.locator.slice(); 852 if (opts.jitMasking === false || pos < lvp || (typeof opts.jitMasking === "number" && isFinite(opts.jitMasking) && opts.jitMasking > pos)) { 853 maskTemplate.push(includeMode === false ? test.nativeDef : getPlaceholder(pos, test)); 854 } 855 } 856 pos++; 857 } while ((maxLength === undefined || pos < maxLength) && (test.fn !== null || test.def !== "") || minimalPos > pos); 858 if (maskTemplate[maskTemplate.length - 1] === "") { 859 maskTemplate.pop(); //drop the last one which is empty 860 } 861 862 getMaskSet().maskLength = pos + 1; 863 return maskTemplate; 864 } 865 866 function getMaskSet() { 867 return maskset; 868 } 869 870 function resetMaskSet(soft) { 871 var maskset = getMaskSet(); 872 maskset.buffer = undefined; 873 if (soft !== true) { 874 // maskset._buffer = undefined; 875 maskset.validPositions = {}; 876 maskset.p = 0; 877 } 878 } 879 880 function getLastValidPosition(closestTo, strict, validPositions) { 881 var before = -1, 882 after = -1, 883 valids = validPositions || getMaskSet().validPositions; //for use in valhook ~ context switch 884 if (closestTo === undefined) closestTo = -1; 885 for (var posNdx in valids) { 886 var psNdx = parseInt(posNdx); 887 if (valids[psNdx] && (strict || valids[psNdx].generatedInput !== true)) { 888 if (psNdx <= closestTo) before = psNdx; 889 if (psNdx >= closestTo) after = psNdx; 890 } 891 } 892 return (before !== -1 && (closestTo - before) > 1) || after < closestTo ? before : after; 893 } 894 895 function stripValidPositions(start, end, nocheck, strict) { 896 function IsEnclosedStatic(pos) { 897 var posMatch = getMaskSet().validPositions[pos]; 898 if (posMatch !== undefined && posMatch.match.fn === null) { 899 var prevMatch = getMaskSet().validPositions[pos - 1], 900 nextMatch = getMaskSet().validPositions[pos + 1]; 901 return prevMatch !== undefined && nextMatch !== undefined; 902 } 903 return false;
904 } 905 906 var i, startPos = start, 907 positionsClone = $.extend(true, {}, getMaskSet().validPositions), 908 needsValidation = false; 909 getMaskSet().p = start; //needed for alternated position after overtype selection 910 911 for (i = end - 1; i >= startPos; i--) { //clear selection 912 if (getMaskSet().validPositions[i] !== undefined) { 913 if (nocheck === true || 914 ((getMaskSet().validPositions[i].match.optionality || !IsEnclosedStatic(i)) && opts.canClearPosition(getMaskSet(), i, getLastValidPosition(undefined, true), strict, opts) !== false)) { 915 delete getMaskSet().validPositions[i]; 916 } 917 } 918 } 919 920 //clear buffer 921 resetMaskSet(true); 922 for (i = startPos + 1; i <= getLastValidPosition();) { 923 while (getMaskSet().validPositions[startPos] !== undefined) startPos++; 924 if (i < startPos) i = startPos + 1; 925 if (getMaskSet().validPositions[i] !== undefined || !isMask(i)) { 926 var t = getTestTemplate(i); 927 if (needsValidation === false && positionsClone[startPos] && positionsClone[startPos].match.def === t.match.def) { //obvious match 928 getMaskSet().validPositions[startPos] = $.extend(true, {}, positionsClone[startPos]); 929 getMaskSet().validPositions[startPos].input = t.input; 930 delete getMaskSet().validPositions[i]; 931 i++; 932 } else if (positionCanMatchDefinition(startPos, t.match.def)) { 933 if (isValid(startPos, t.input || getPlaceholder(i), true) !== false) { 934 delete getMaskSet().validPositions[i]; 935 i++; 936 needsValidation = true; 937 } 938 } else if (!isMask(i)) { 939 i++; 940 startPos--; 941 } 942 startPos++; 943 } else i++; 944 } 945 946 resetMaskSet(true); 947 } 948 949 function determineTestTemplate(pos, tests, guessNextBest) { 950 pos = pos > 0 ? pos - 1 : 0; 951 var testPos, 952 altTest = getTest(pos), 953 altArr = (altTest.alternation !== undefined) ? altTest.locator[altTest.alternation].toString().split(",") : []; 954 for (var ndx = 0; ndx < tests.length; ndx++) { 955 testPos = tests[ndx]; 956 957 if (testPos.match && 958 (((opts.greedy && testPos.match.optionalQuantifier !== true) || (testPos.match.optionality === false || testPos.match.newBlockMarker === false) && testPos.match.optionalQuantifier !== true) && 959 ((altTest.alternation === undefined || altTest.alternation !== testPos.alternation) || 960 (testPos.locator[altTest.alternation] !== undefined && checkAlternationMatch(testPos.locator[altTest.alternation].toString().split(","), altArr))))) { 961 962 if (guessNextBest !== true || (testPos.match.fn === null && !/[0-9a-bA-Z]/.test(testPos.match.def))) { 963 break; 964 } 965 } 966 } 967 968 return testPos; 969 } 970 971 function getTestTemplate(pos, ndxIntlzr, tstPs) { 972 return getMaskSet().validPositions[pos] || determineTestTemplate(pos, getTests(pos, ndxIntlzr ? ndxIntlzr.slice() : ndxIntlzr, tstPs)); 973 } 974 975 function getTest(pos) { 976 if (getMaskSet().validPositions[pos]) { 977 return getMaskSet().validPositions[pos]; 978 } 979 return getTests(pos)[0]; 980 } 981 982 function positionCanMatchDefinition(pos, def) { 983 var valid = false, 984 tests = getTests(pos); 985 for (var tndx = 0; tndx < tests.length; tndx++) { 986 if (tests[tndx].match && tests[tndx].match.def === def) { 987 valid = true; 988 break; 989 } 990 } 991 return valid; 992 } 993 994 995 function getTests(pos, ndxIntlzr, tstPs) { 996 var maskTokens = getMaskSet().maskToken, 997 testPos = ndxIntlzr ? tstPs : 0, 998 ndxInitializer = ndxIntlzr ? ndxIntlzr.slice() : [0], 999 matches = [], 1000 insertStop = false, 1001 latestMatch, 1002 cacheDependency = ndxIntlzr ? ndxIntlzr.join("") : ""; 1003 1004 function resolveTestFromToken(maskToken, ndxInitializer, loopNdx, quantifierRecurse) { //ndxInitializer contains a set of indexes to speedup searches in the mtokens 1005 function handleMatch(match, loopNdx, quantifierRecurse) { 1006 function isFirstMatch(latestMatch, tokenGroup) { 1007 var firstMatch = $.inArray(latestMatch, tokenGroup.matches) === 0; 1008 if (!firstMatch) { 1009 $.each(tokenGroup.matches, function (ndx, match) { 1010 if (match.isQuantifier === true) { 1011 firstMatch = isFirstMatch(latestMatch, tokenGroup.matches[ndx - 1]); 1012 if (firstMatch) return false;
1013 } 1014 }); 1015 } 1016 return firstMatch; 1017 } 1018 1019 function resolveNdxInitializer(pos, alternateNdx, targetAlternation) { 1020 var bestMatch, indexPos; 1021 1022 if (getMaskSet().validPositions[pos - 1] && targetAlternation && getMaskSet().tests[pos]) { //detect altarnation offset 1023 var vpAlternation = getMaskSet().validPositions[pos - 1].locator; 1024 var tpAlternation = getMaskSet().tests[pos][0].locator; 1025 for (var i = 0; i < targetAlternation; i++) { 1026 if (vpAlternation[i] !== tpAlternation[i]) { 1027 return vpAlternation.slice(targetAlternation + 1); 1028 } 1029 } 1030 } 1031 1032 if (getMaskSet().tests[pos] || getMaskSet().validPositions[pos]) { 1033 $.each(getMaskSet().tests[pos] || [getMaskSet().validPositions[pos]], function (ndx, lmnt) { 1034 var alternation = targetAlternation !== undefined ? targetAlternation : lmnt.alternation, 1035 ndxPos = lmnt.locator[alternation] !== undefined ? lmnt.locator[alternation].toString().indexOf(alternateNdx) : -1; 1036 if ((indexPos === undefined || ndxPos < indexPos) && ndxPos !== -1) { 1037 bestMatch = lmnt; 1038 indexPos = ndxPos; 1039 } 1040 }); 1041 } 1042 return bestMatch ? 1043 bestMatch.locator.slice((targetAlternation !== undefined ? targetAlternation : bestMatch.alternation) + 1) : 1044 targetAlternation !== undefined ? resolveNdxInitializer(pos, alternateNdx) : undefined; 1045 } 1046 1047 function definitionCanMatchDefinition(source, target) { 1048 return source.match.nativeDef === target.match.nativeDef || source.match.def === target.match.nativeDef || source.match.nativeDef === target.match.def; 1049 } 1050 1051 function isSubsetOf(source, target) { 1052 if (source.match.fn !== null && target.match.fn !== null) { //is regex a subset 1053 //do we need a dfa for this? 1054 //currently only a simplistic approach 1055 return target.match.fn.test(source.match.def.replace(/[\[\]]/g, ""), getMaskSet(), pos, false, opts, false); 1056 } 1057 return false; 1058 } 1059 1060 function staticCanMatchDefinition(source, target) { 1061 return source.match.fn === null && target.match.fn !== null ? target.match.fn.test(source.match.def, getMaskSet(), pos, false, opts, false) : false; 1062 } 1063 1064 if (testPos > 10000) { 1065 throw "Inputmask: There is probably an error in your mask definition or in the code. Create an issue on github with an example of the mask you are using. " + getMaskSet().mask; 1066 } 1067 if (testPos === pos && match.matches === undefined) { 1068 matches.push({ 1069 "match": match, 1070 "locator": loopNdx.reverse(), 1071 "cd": cacheDependency 1072 }); 1073 return true; 1074 } else if (match.matches !== undefined) { 1075 if (match.isGroup && quantifierRecurse !== match) { //when a group pass along to the quantifier 1076 match = handleMatch(maskToken.matches[$.inArray(match, maskToken.matches) + 1], loopNdx); 1077 if (match) return true; 1078 } else if (match.isOptional) { 1079 var optionalToken = match; 1080 match = resolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse); 1081 if (match) { 1082 latestMatch = matches[matches.length - 1].match; 1083 if (isFirstMatch(latestMatch, optionalToken)) { 1084 insertStop = true; //insert a stop 1085 testPos = pos; //match the position after the group 1086 } else return true; 1087 } 1088 } else if (match.isAlternator) { 1089 var alternateToken = match, 1090 malternateMatches = [], 1091 maltMatches, 1092 currentMatches = matches.slice(), 1093 loopNdxCnt = loopNdx.length; 1094 var altIndex = ndxInitializer.length > 0 ? ndxInitializer.shift() : -1; 1095 if (altIndex === -1 || typeof altIndex === "string") { 1096 var currentPos = testPos, 1097 ndxInitializerClone = ndxInitializer.slice(), 1098 altIndexArr = [], 1099 amndx; 1100 if (typeof altIndex == "string") { 1101 altIndexArr = altIndex.split(","); 1102 } else { 1103 for (amndx = 0;
1103 amndx < alternateToken.matches.length; amndx++) { 1104 altIndexArr.push(amndx); 1105 } 1106 } 1107 1108 for (var ndx = 0; ndx < altIndexArr.length; ndx++) { 1109 amndx = parseInt(altIndexArr[ndx]); 1110 matches = []; 1111 //set the correct ndxInitializer 1112 ndxInitializer = resolveNdxInitializer(testPos, amndx, loopNdxCnt) || ndxInitializerClone.slice(); 1113 match = handleMatch(alternateToken.matches[amndx] || maskToken.matches[amndx], [amndx].concat(loopNdx), quantifierRecurse) || match; 1114 if (match !== true && match !== undefined && (altIndexArr[altIndexArr.length - 1] < alternateToken.matches.length)) { //no match in the alternations (length mismatch) => look further 1115 // ndx = altIndexArr.length; //skip alternation 1116 1117 //TODO CHECK ME IS THIS CORRECT??? 1118 // var ntndx = $.inArray(match, maskToken.matches) + 1; 1119 // if (maskToken.matches.length > ntndx) { 1120 // match = handleMatch(maskToken.matches[ntndx], [ntndx].concat(loopNdx.slice(1, loopNdx.length)), quantifierRecurse); 1121 // if (match) { 1122 // altIndexArr.push(ntndx.toString()); 1123 // $.each(matches, function (ndx, lmnt) { 1124 // lmnt.alternation = loopNdx.length - 1; 1125 // }); 1126 // } 1127 // } 1128 } 1129 maltMatches = matches.slice(); 1130 testPos = currentPos; 1131 matches = []; 1132 1133 //fuzzy merge matches 1134 for (var ndx1 = 0; ndx1 < maltMatches.length; ndx1++) { 1135 var altMatch = maltMatches[ndx1], 1136 dropMatch = false; 1137 altMatch.alternation = altMatch.alternation || loopNdxCnt; 1138 for (var ndx2 = 0; ndx2 < malternateMatches.length; ndx2++) { 1139 var altMatch2 = malternateMatches[ndx2]; 1140 //verify equality 1141 if (typeof altIndex !== "string" || $.inArray(altMatch.locator[altMatch.alternation].toString(), altIndexArr) !== -1) { 1142 if (definitionCanMatchDefinition(altMatch, altMatch2)) { 1143 dropMatch = true; 1144 if (altMatch.alternation === altMatch2.alternation && 1145 altMatch2.locator[altMatch2.alternation].toString().indexOf(altMatch.locator[altMatch.alternation]) === -1) { 1146 altMatch2.locator[altMatch2.alternation] = altMatch2.locator[altMatch2.alternation] + "," + altMatch.locator[altMatch.alternation]; 1147 altMatch2.alternation = altMatch.alternation; //we pass the alternation index => used in determineLastRequiredPosition 1148 } 1149 if (altMatch.match.nativeDef === altMatch2.match.def) { 1150 altMatch.locator[altMatch.alternation] = altMatch2.locator[altMatch2.alternation]; 1151 malternateMatches.splice(malternateMatches.indexOf(altMatch2), 1, altMatch); 1152 } 1153 break; 1154 } else if (altMatch.match.def === altMatch2.match.def) { 1155 dropMatch = false;
1156 break; 1157 } else if (staticCanMatchDefinition(altMatch, altMatch2) || isSubsetOf(altMatch, altMatch2)) { 1158 // console.log("case 5"); 1159 if (altMatch.alternation === altMatch2.alternation && 1160 altMatch.locator[altMatch.alternation].toString().indexOf(altMatch2.locator[altMatch2.alternation].toString().split("")[0]) === -1) { 1161 1162 //no alternation marker 1163 altMatch.na = altMatch.na || altMatch.locator[altMatch.alternation].toString(); 1164 if (altMatch.na.indexOf(altMatch.locator[altMatch.alternation].toString().split("")[0]) === -1) { 1165 altMatch.na = altMatch.na + "," + altMatch.locator[altMatch2.alternation].toString().split("")[0]; 1166 } 1167 //insert match above general match 1168 dropMatch = true; 1169 altMatch.locator[altMatch.alternation] = altMatch2.locator[altMatch2.alternation].toString().split("")[0] + "," + altMatch.locator[altMatch.alternation]; 1170 malternateMatches.splice(malternateMatches.indexOf(altMatch2), 0, altMatch); 1171 } 1172 break; 1173 } 1174 } 1175 } 1176 if (!dropMatch) { 1177 malternateMatches.push(altMatch); 1178 } 1179 } 1180 } 1181 if (typeof altIndex == "string") { //filter matches 1182 malternateMatches = $.map(malternateMatches, function (lmnt, ndx) { 1183 if (isFinite(ndx)) { 1184 var mamatch, 1185 alternation = lmnt.alternation, 1186 altLocArr = lmnt.locator[alternation].toString().split(","); 1187 lmnt.locator[alternation] = undefined; 1188 lmnt.alternation = undefined; 1189 1190 for (var alndx = 0; alndx < altLocArr.length; alndx++) { 1191 mamatch = $.inArray(altLocArr[alndx], altIndexArr) !== -1; 1192 if (mamatch) { //rebuild the locator with valid entries 1193 if (lmnt.locator[alternation] !== undefined) { 1194 lmnt.locator[alternation] += ","; 1195 lmnt.locator[alternation] += altLocArr[alndx]; 1196 } else lmnt.locator[alternation] = parseInt(altLocArr[alndx]); 1197 1198 lmnt.alternation = alternation; 1199 } 1200 } 1201 1202 if (lmnt.locator[alternation] !== undefined) return lmnt; 1203 } 1204 }); 1205 } 1206 1207 matches = currentMatches.concat(malternateMatches); 1208 testPos = pos; 1209 insertStop = matches.length > 0; //insert a stopelemnt when there is an alternate - needed for non-greedy option 1210 match = malternateMatches.length > 0; //set correct match state 1211 1212 //cloneback 1213 ndxInitializer = ndxInitializerClone.slice(); 1214 } else { 1215 // if (alternateToken.matches[altIndex]) { //if not in the initial alternation => look further 1216 match = handleMatch(alternateToken.matches[altIndex] || maskToken.matches[altIndex], [altIndex].concat(loopNdx), quantifierRecurse); 1217 // } else match = false;
1218 } 1219 if (match) return true; 1220 } else if (match.isQuantifier && quantifierRecurse !== maskToken.matches[$.inArray(match, maskToken.matches) - 1]) { 1221 var qt = match; 1222 for (var qndx = (ndxInitializer.length > 0) ? ndxInitializer.shift() : 0; 1223 (qndx < (isNaN(qt.quantifier.max) ? qndx + 1 : qt.quantifier.max)) && testPos <= pos; qndx++) { 1224 var tokenGroup = maskToken.matches[$.inArray(qt, maskToken.matches) - 1]; 1225 match = handleMatch(tokenGroup, [qndx].concat(loopNdx), tokenGroup); //set the tokenGroup as quantifierRecurse marker 1226 if (match) { 1227 //get latest match 1228 latestMatch = matches[matches.length - 1].match; 1229 latestMatch.optionalQuantifier = qndx > (qt.quantifier.min - 1); 1230 if (isFirstMatch(latestMatch, tokenGroup)) { //search for next possible match 1231 if (qndx > (qt.quantifier.min - 1)) { 1232 insertStop = true; 1233 testPos = pos; //match the position after the group 1234 break; //stop quantifierloop 1235 } else return true; 1236 } else { 1237 return true; 1238 } 1239 } 1240 } 1241 } else { 1242 match = resolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse); 1243 if (match) return true; 1244 } 1245 } else { 1246 testPos++; 1247 } 1248 } 1249 1250 for (var tndx = (ndxInitializer.length > 0 ? ndxInitializer.shift() : 0); tndx < maskToken.matches.length; tndx++) { 1251 if (maskToken.matches[tndx].isQuantifier !== true) { 1252 var match = handleMatch(maskToken.matches[tndx], [tndx].concat(loopNdx), quantifierRecurse); 1253 if (match && testPos === pos) { 1254 return match; 1255 } else if (testPos > pos) { 1256 break; 1257 } 1258 } 1259 } 1260 } 1261 1262 function mergeLocators(pos, tests) { 1263 var locator = []; 1264 if (!$.isArray(tests)) tests = [tests]; 1265 if (tests.length > 0) { 1266 if (tests[0].alternation === undefined) { 1267 locator = determineTestTemplate(pos, tests.slice()).locator.slice(); 1268 if (locator.length === 0) locator = tests[0].locator.slice(); 1269 } else { 1270 $.each(tests, function (ndx, tst) { 1271 if (tst.def !== "") { 1272 if (locator.length === 0) locator = tst.locator.slice(); 1273 else { 1274 for (var i = 0; i < locator.length; i++) { 1275 if (tst.locator[i] && locator[i].toString().indexOf(tst.locator[i]) === -1) { 1276 locator[i] += "," + tst.locator[i]; 1277 } 1278 } 1279 } 1280 } 1281 }); 1282 } 1283 } 1284 return locator; 1285 } 1286 1287 function filterTests(tests) { 1288 if (opts.keepStatic && pos > 0) { 1289 if (tests.length > 1 + (tests[tests.length - 1].match.def === "" ? 1 : 0)) { 1290 if (tests[0].match.optionality !== true && 1291 tests[0].match.optionalQuantifier !== true && 1292 tests[0].match.fn === null && !/[0-9a-bA-Z]/.test(tests[0].match.def)) { 1293 if (getMaskSet().validPositions[pos - 1] === undefined) { 1294 return [determineTestTemplate(pos, tests)]; 1295 } else if (getMaskSet().validPositions[pos - 1].alternation === tests[0].alternation) { 1296 return [determineTestTemplate(pos, tests)]; 1297 } else if (getMaskSet().validPositions[pos - 1]) { 1298 return [determineTestTemplate(pos, tests)]; 1299 } 1300 } 1301 } 1302 } 1303 1304 return tests; 1305 } 1306 1307 if (pos > -1) { 1308 if (ndxIntlzr === undefined) { //determine index initializer 1309 var previousPos = pos - 1, 1310 test; 1311 while ((test = getMaskSet().validPositions[previousPos] || getMaskSet().tests[previousPos]) === undefined && previousPos > -1) { 1312 previousPos--; 1313 } 1314 if (test !== undefined && previousPos > -1) { 1315 ndxInitializer = mergeLocators(previousPos, test); 1316 cacheDependency = ndxInitializer.join(""); 1317 testPos = previousPos; 1318 } 1319 } 1320 if (getMaskSet().tests[pos] && getMaskSet().tests[pos][0].cd === cacheDependency) { //cacheDependency is set on all tests, just check on the first 1321 //console.log("cache hit " + pos + " - " + ndxIntlzr); 1322 return filterTests(getMaskSet().tests[pos]); 1323 } 1324 for (var mtndx = ndxInitializer.shift(); mtndx < maskTokens.length; mtndx++) { 1325 var match = resolveTestFromToken(maskTokens[mtndx], ndxInitializer, [mtndx]); 1326 if ((match && testPos === pos) || testPos > pos) { 1327 break; 1328 } 1329 } 1330 } 1331 if (matches.length === 0 || insertStop) { 1332 matches.push({ 1333 match: { 1334 fn: null, 1335 cardinality: 0, 1336 optionality: true, 1337 casing: null, 1338 def: "", 1339 placeholder: "" 1340 }, 1341 locator: [], 1342 cd: cacheDependency 1343 }); 1344 } 1345 1346 if (ndxIntlzr !== undefined && getMaskSet().tests[pos]) { //prioritize full tests for caching 1347 return filterTests($.extend(true, [], matches)); 1348 } 1349 getMaskSet().tests[pos] = $.extend(true, [], matches);
1349 //set a clone to prevent overwriting some props 1350 // console.log(pos + " - " + JSON.stringify(matches)); 1351 return filterTests(getMaskSet().tests[pos]); 1352 } 1353 1354 function getBufferTemplate() { 1355 if (getMaskSet()._buffer === undefined) { 1356 //generate template 1357 getMaskSet()._buffer = getMaskTemplate(false, 1); 1358 if (getMaskSet().buffer === undefined) { 1359 getMaskSet().buffer = getMaskSet()._buffer.slice(); 1360 } 1361 } 1362 return getMaskSet()._buffer; 1363 } 1364 1365 function getBuffer(noCache) { 1366 if (getMaskSet().buffer === undefined || noCache === true) { 1367 getMaskSet().buffer = getMaskTemplate(true, getLastValidPosition(), true); 1368 } 1369 return getMaskSet().buffer; 1370 } 1371 1372 function refreshFromBuffer(start, end, buffer) { 1373 var i, p; 1374 if (start === true) { 1375 resetMaskSet(); 1376 start = 0; 1377 end = buffer.length; 1378 } else { 1379 for (i = start; i < end; i++) { 1380 delete getMaskSet().validPositions[i]; 1381 } 1382 } 1383 p = start; 1384 for (i = start; i < end; i++) { 1385 resetMaskSet(true); //prevents clobber from the buffer 1386 if (buffer[i] !== opts.skipOptionalPartCharacter) { 1387 var valResult = isValid(p, buffer[i], true, true); 1388 if (valResult !== false) { 1389 resetMaskSet(true); 1390 p = valResult.caret !== undefined ? valResult.caret : valResult.pos + 1; 1391 } 1392 } 1393 } 1394 } 1395 1396 function casing(elem, test, pos) { 1397 switch (opts.casing || test.casing) { 1398 case "upper": 1399 elem = elem.toUpperCase(); 1400 break; 1401 case "lower": 1402 elem = elem.toLowerCase(); 1403 break; 1404 case "title": 1405 var posBefore = getMaskSet().validPositions[pos - 1]; 1406 if (pos === 0 || posBefore && posBefore.input === String.fromCharCode(Inputmask.keyCode.SPACE)) { 1407 elem = elem.toUpperCase(); 1408 } else { 1409 elem = elem.toLowerCase(); 1410 } 1411 break; 1412 default: 1413 if ($.isFunction(opts.casing)) { 1414 var args = Array.prototype.slice.call(arguments); 1415 args.push(getMaskSet().validPositions); 1416 elem = opts.casing.apply(this, args); 1417 } 1418 } 1419 1420 return elem; 1421 } 1422 1423 function checkAlternationMatch(altArr1, altArr2, na) { 1424 var altArrC = opts.greedy ? altArr2 : altArr2.slice(0, 1), 1425 isMatch = false, 1426 naArr = na !== undefined ? na.split(",") : [], 1427 naNdx; 1428 1429 //remove no alternate indexes from alternation array 1430 for (var i = 0; i < naArr.length; i++) { 1431 if ((naNdx = altArr1.indexOf(naArr[i])) !== -1) { 1432 altArr1.splice(naNdx, 1); 1433 } 1434 } 1435 1436 for (var alndx = 0; alndx < altArr1.length; alndx++) { 1437 if ($.inArray(altArr1[alndx], altArrC) !== -1) { 1438 isMatch = true; 1439 break; 1440 } 1441 } 1442 return isMatch; 1443 } 1444 1445 function isValid(pos, c, strict, fromSetValid, fromAlternate, validateOnly) { //strict true ~ no correction or autofill 1446 function isSelection(posObj) { 1447 var selection = isRTL ? (posObj.begin - posObj.end) > 1 || ((posObj.begin - posObj.end) === 1) : 1448 (posObj.end - posObj.begin) > 1 || ((posObj.end - posObj.begin) === 1); 1449 1450 return selection && posObj.begin === 0 && posObj.end === getMaskSet().maskLength ? "full" : selection; 1451 } 1452
1453 strict = strict === true; //always set a value to strict to prevent possible strange behavior in the extensions 1454 1455 var maskPos = pos; 1456 if (pos.begin !== undefined) { //position was a position object - used to handle a delete by typing over a selection 1457 maskPos = isRTL && !isSelection(pos) ? pos.end : pos.begin; 1458 } 1459 1460 function _isValid(position, c, strict) { 1461 var rslt = false; 1462 $.each(getTests(position), function (ndx, tst) { 1463 var test = tst.match, 1464 loopend = c ? 1 : 0, 1465 chrs = ""; 1466 for (var i = test.cardinality; i > loopend; i--) { 1467 chrs += getBufferElement(position - (i - 1)); 1468 } 1469 if (c) { 1470 chrs += c; 1471 } 1472 1473 //make sure the buffer is set and correct 1474 getBuffer(true); 1475 //return is false or a json object => { pos: ??, c: ??} or true 1476 rslt = test.fn != null ? 1477 test.fn.test(chrs, getMaskSet(), position, strict, opts, isSelection(pos)) : (c === test.def || c === opts.skipOptionalPartCharacter) && test.def !== "" ? //non mask 1478 { 1479 c: getPlaceholder(position, test, true) || test.def, 1480 pos: position 1481 } : false; 1482 1483 if (rslt !== false) { 1484 var elem = rslt.c !== undefined ? rslt.c : c; 1485 elem = (elem === opts.skipOptionalPartCharacter && test.fn === null) ? 1486 (getPlaceholder(position, test, true) || test.def) : elem; 1487 1488 var validatedPos = position, 1489 possibleModifiedBuffer = getBuffer(); 1490 1491 if (rslt.remove !== undefined) { //remove position(s) 1492 if (!$.isArray(rslt.remove)) rslt.remove = [rslt.remove]; 1493 $.each(rslt.remove.sort(function (a, b) { 1494 return b - a; 1495 }), function (ndx, lmnt) { 1496 stripValidPositions(lmnt, lmnt + 1, true); 1497 }); 1498 } 1499 if (rslt.insert !== undefined) { //insert position(s) 1500 if (!$.isArray(rslt.insert)) rslt.insert = [rslt.insert]; 1501 $.each(rslt.insert.sort(function (a, b) { 1502 return a - b; 1503 }), function (ndx, lmnt) { 1504 isValid(lmnt.pos, lmnt.c, true, fromSetValid); 1505 }); 1506 } 1507 1508 if (rslt.refreshFromBuffer) { 1509 var refresh = rslt.refreshFromBuffer; 1510 // strict = true; 1511 refreshFromBuffer(refresh === true ? refresh : refresh.start, refresh.end, possibleModifiedBuffer); 1512 if (rslt.pos === undefined && rslt.c === undefined) { 1513 rslt.pos = getLastValidPosition(); 1514 return false; //breakout if refreshFromBuffer && nothing to insert 1515 } 1516 validatedPos = rslt.pos !== undefined ? rslt.pos : position; 1517 if (validatedPos !== position) { 1518 rslt = $.extend(rslt, isValid(validatedPos, elem, true, fromSetValid)); //revalidate new position strict 1519 return false; 1520 } 1521 1522 } else if (rslt !== true && rslt.pos !== undefined && rslt.pos !== position) { //their is a position offset 1523 validatedPos = rslt.pos; 1524 refreshFromBuffer(position, validatedPos, getBuffer().slice()); 1525 if (validatedPos !== position) { 1526 rslt = $.extend(rslt, isValid(validatedPos, elem, true)); //revalidate new position strict 1527 return false;
1528 } 1529 } 1530 1531 if (rslt !== true && rslt.pos === undefined && rslt.c === undefined) { 1532 return false; //breakout if nothing to insert 1533 } 1534 1535 if (ndx > 0) { 1536 resetMaskSet(true); 1537 } 1538 1539 if (!setValidPosition(validatedPos, $.extend({}, tst, { 1540 "input": casing(elem, test, validatedPos) 1541 }), fromSetValid, isSelection(pos))) { 1542 rslt = false; 1543 } 1544 return false; //break from $.each 1545 } 1546 }); 1547 return rslt; 1548 } 1549 1550 function alternate(pos, c, strict) { 1551 var validPsClone = $.extend(true, {}, getMaskSet().validPositions), 1552 lastAlt, 1553 alternation, 1554 isValidRslt = false, 1555 altPos, prevAltPos, i, validPos, lAltPos = getLastValidPosition(), 1556 altNdxs, decisionPos; 1557 //find last modified alternation 1558 prevAltPos = getMaskSet().validPositions[lAltPos]; 1559 for (; lAltPos >= 0; lAltPos--) { 1560 altPos = getMaskSet().validPositions[lAltPos]; 1561 if (altPos && altPos.alternation !== undefined) { 1562 lastAlt = lAltPos; 1563 alternation = getMaskSet().validPositions[lastAlt].alternation; 1564 if (prevAltPos.locator[altPos.alternation] !== altPos.locator[altPos.alternation]) { 1565 break; 1566 } 1567 prevAltPos = altPos; 1568 } 1569 } 1570 if (alternation !== undefined) { 1571 decisionPos = parseInt(lastAlt); 1572 var decisionTaker = prevAltPos.locator[prevAltPos.alternation || alternation] !== undefined ? prevAltPos.locator[prevAltPos.alternation || alternation] : altNdxs[0]; //no match in the alternations (length mismatch) 1573 if (decisionTaker.length > 0) { //no decision taken ~ take first one as decider 1574 decisionTaker = decisionTaker.split(",")[0]; 1575 } 1576 var possibilityPos = getMaskSet().validPositions[decisionPos], 1577 prevPos = getMaskSet().validPositions[decisionPos - 1]; 1578 $.each(getTests(decisionPos, prevPos ? prevPos.locator : undefined, decisionPos - 1), function (ndx, test) { 1579 altNdxs = test.locator[alternation] ? test.locator[alternation].toString().split(",") : []; 1580 for (var mndx = 0; mndx < altNdxs.length; mndx++) { 1581 var validInputs = [], 1582 staticInputsBeforePos = 0, 1583 staticInputsBeforePosAlternate = 0, 1584 verifyValidInput = false; 1585 if (decisionTaker < altNdxs[mndx] && (test.na === undefined || ($.inArray(altNdxs[mndx], test.na.split(",")) === -1 || $.inArray(decisionTaker.toString(), altNdxs) === -1))) { 1586 getMaskSet().validPositions[decisionPos] = $.extend(true, {}, test); 1587 var possibilities = getMaskSet().validPositions[decisionPos].locator; 1588 getMaskSet().validPositions[decisionPos].locator[alternation] = parseInt(altNdxs[mndx]); //set forced decision 1589 if (test.match.fn == null) { 1590 if (possibilityPos.input !== test.match.def) { 1591 verifyValidInput = true; //verify that the new definition matches the input 1592 if (possibilityPos.generatedInput !== true) { 1593 validInputs.push(possibilityPos.input); 1594 } 1595 } 1596 staticInputsBeforePosAlternate++; 1597 getMaskSet().validPositions[decisionPos].generatedInput = !/[0-9a-bA-Z]/.test(test.match.def); 1598 getMaskSet().validPositions[decisionPos].input = test.match.def; 1599 } else { 1600 getMaskSet().validPositions[decisionPos].input = possibilityPos.input; 1601 } 1602 for (i = decisionPos + 1; i < getLastValidPosition(undefined, true) + 1; i++) { 1603 validPos = getMaskSet().validPositions[i]; 1604 if (validPos && validPos.generatedInput !== true && /[0-9a-bA-Z]/.test(validPos.input)) { 1605 validInputs.push(validPos.input); 1606 } else if (i < pos) staticInputsBeforePos++; 1607 delete getMaskSet().validPositions[i]; 1608 } 1609 if (verifyValidInput && validInputs[0] === test.match.def) { 1610 validInputs.shift(); 1611 } 1612 resetMaskSet(true); //clear getbuffer 1613 isValidRslt = true; 1614 while (validInputs.length > 0) { 1615 var input = validInputs.shift(); 1616 if (input !== opts.skipOptionalPartCharacter) { 1617 if (!(isValidRslt = isValid(getLastValidPosition(undefined, true) + 1, input, false, fromSetValid, true))) { 1618 break; 1619 } 1620 } 1621 } 1622 1623 if (isValidRslt) { 1624 getMaskSet().validPositions[decisionPos].locator = possibilities; //reset forceddecision ~ needed for proper delete 1625 var targetLvp = getLastValidPosition(pos) + 1; 1626 for (i = decisionPos + 1; i < getLastValidPosition() + 1; i++) { 1627 validPos = getMaskSet().validPositions[i]; 1628 if ((validPos === undefined || validPos.match.fn == null) && i < (pos + (staticInputsBeforePosAlternate - staticInputsBeforePos))) { 1629 staticInputsBeforePosAlternate++; 1630 } 1631 } 1632 pos = pos + (staticInputsBeforePosAlternate - staticInputsBeforePos); 1633 isValidRslt = isValid(pos > targetLvp ? targetLvp : pos, c, strict, fromSetValid, true); 1634 } 1635 if (!isValidRslt) { 1636 resetMaskSet(); 1637 getMaskSet().validPositions = $.extend(true, {}, validPsClone); 1638 } else return false; //exit $.each 1639 } 1640 } 1641 }); 1642 } 1643 1644 return isValidRslt; 1645 } 1646 1647 //set alternator choice on previous skipped placeholder positions 1648 function trackbackAlternations(originalPos, newPos) { 1649 var vp = getMaskSet().validPositions[newPos]; 1650 if (vp) {
1651 var targetLocator = vp.locator, 1652 tll = targetLocator.length; 1653 1654 for (var ps = originalPos; ps < newPos; ps++) { 1655 if (getMaskSet().validPositions[ps] === undefined && !isMask(ps, true)) { 1656 var tests = getTests(ps).slice(), 1657 bestMatch = determineTestTemplate(ps, tests, true), 1658 equality = -1; 1659 if (tests[tests.length - 1].match.def === "") tests.pop(); 1660 $.each(tests, function (ndx, tst) { //find best matching 1661 for (var i = 0; i < tll; i++) { 1662 if (tst.locator[i] !== undefined && checkAlternationMatch(tst.locator[i].toString().split(","), targetLocator[i].toString().split(","), tst.na)) { 1663 if (equality < i) { 1664 equality = i; 1665 bestMatch = tst; 1666 } 1667 } else { 1668 //check if alternationIndex is closer then the current bestmatch 1669 var targetAI = targetLocator[i], 1670 bestMatchAI = bestMatch.locator[i], 1671 tstAI = tst.locator[i]; 1672 if ((targetAI - bestMatchAI) > Math.abs(targetAI - tstAI)) { 1673 bestMatch = tst; 1674 } 1675 break; 1676 } 1677 } 1678 }); 1679 bestMatch = $.extend({}, bestMatch, { 1680 "input": getPlaceholder(ps, bestMatch.match, true) || bestMatch.match.def 1681 }); 1682 bestMatch.generatedInput = true; 1683 setValidPosition(ps, bestMatch, true); 1684 //revalidate the new position to update the locator value 1685 getMaskSet().validPositions[newPos] = undefined; 1686 _isValid(newPos, vp.input, true); 1687 } 1688 } 1689 } 1690 } 1691 1692 function setValidPosition(pos, validTest, fromSetValid, isSelection) { 1693 if (isSelection || (opts.insertMode && getMaskSet().validPositions[pos] !== undefined && fromSetValid === undefined)) { 1694 //reposition & revalidate others 1695 var positionsClone = $.extend(true, {}, getMaskSet().validPositions), 1696 lvp = getLastValidPosition(undefined, true), 1697 i; 1698 for (i = pos; i <= lvp; i++) { //clear selection 1699 delete getMaskSet().validPositions[i]; 1700 } 1701 getMaskSet().validPositions[pos] = $.extend(true, {}, validTest); 1702 var valid = true, 1703 j, vps = getMaskSet().validPositions, 1704 needsValidation = false, 1705 initialLength = getMaskSet().maskLength; 1706 for (i = (j = pos); i <= lvp; i++) { 1707 var t = positionsClone[i]; 1708 if (t !== undefined /*&& (t.generatedInput !== true || t.match.fn === null)*/) { 1709 var posMatch = j; 1710 while (posMatch < getMaskSet().maskLength && ((t.match.fn === null && vps[i] && (vps[i].match.optionalQuantifier === true || vps[i].match.optionality === true)) || t.match.fn != null)) { 1711 posMatch++; 1712 if (needsValidation === false && positionsClone[posMatch] && positionsClone[posMatch].match.def === t.match.def) { //obvious match 1713 getMaskSet().validPositions[posMatch] = $.extend(true, {}, positionsClone[posMatch]); 1714 getMaskSet().validPositions[posMatch].input = t.input; 1715 fillMissingNonMask(posMatch); 1716 j = posMatch; 1717 valid = true; 1718 } else if (positionCanMatchDefinition(posMatch, t.match.def)) { //validated match 1719 var result = isValid(posMatch, t.input, true, true); 1720 valid = result !== false; 1721 j = (result.caret || result.insert) ? getLastValidPosition() : posMatch; 1722 needsValidation = true; 1723 } else { 1724 valid = t.generatedInput === true; 1725 if (!valid && posMatch >= getMaskSet().maskLength - 1) break; 1726 } 1727 if (getMaskSet().maskLength < initialLength) getMaskSet().maskLength = initialLength; //a bit hacky but the masklength is corrected later on 1728 if (valid) break; 1729 } 1730 } 1731 if (!valid) break; 1732 } 1733 1734 if (!valid) { 1735 getMaskSet().validPositions = $.extend(true, {}, positionsClone); 1736 resetMaskSet(true); 1737 return false;
1738 } 1739 } else { 1740 getMaskSet().validPositions[pos] = $.extend(true, {}, validTest); 1741 } 1742 1743 1744 resetMaskSet(true); 1745 return true; 1746 } 1747 1748 var result = true, 1749 positionsClone = $.extend(true, {}, getMaskSet().validPositions); //clone the currentPositions 1750 1751 1752 function fillMissingNonMask(maskPos) { 1753 //Check for a nonmask before the pos 1754 //find previous valid 1755 for (var pndx = maskPos - 1; pndx > -1; pndx--) { 1756 if (getMaskSet().validPositions[pndx]) break; 1757 } 1758 ////fill missing nonmask and valid placeholders 1759 var testTemplate, testsFromPos; 1760 for (pndx++; pndx < maskPos; pndx++) { 1761 if (getMaskSet().validPositions[pndx] === undefined && (opts.jitMasking === false || opts.jitMasking > pndx)) { 1762 testsFromPos = getTests(pndx, getTestTemplate(pndx - 1).locator, pndx - 1).slice(); 1763 if (testsFromPos[testsFromPos.length - 1].match.def === "") testsFromPos.pop(); 1764 testTemplate = determineTestTemplate(pndx, testsFromPos); 1765 if (testTemplate && (testTemplate.match.def === opts.radixPointDefinitionSymbol || !isMask(pndx, true) || 1766 ($.inArray(opts.radixPoint, getBuffer()) < pndx && testTemplate.match.fn && testTemplate.match.fn.test(getPlaceholder(pndx), getMaskSet(), pndx, false, opts)))) { 1767 result = _isValid(pndx, getPlaceholder(pndx, testTemplate.match, true) || (testTemplate.match.fn == null ? testTemplate.match.def : (getPlaceholder(pndx) !== "" ? getPlaceholder(pndx) : getBuffer()[pndx])), true); 1768 if (result !== false) { 1769 getMaskSet().validPositions[result.pos || pndx].generatedInput = true; 1770 } 1771 } 1772 } 1773 } 1774 } 1775 1776 if ($.isFunction(opts.preValidation) && !strict && fromSetValid !== true && validateOnly !== true) { 1777 result = opts.preValidation(getBuffer(), maskPos, c, isSelection(pos), opts); 1778 } 1779 if (result === true) { 1780 fillMissingNonMask(maskPos); 1781 1782 if (isSelection(pos)) { 1783 handleRemove(undefined, Inputmask.keyCode.DELETE, pos, true, true); 1784 maskPos = getMaskSet().p; 1785 } 1786 1787 if (maskPos < getMaskSet().maskLength && (maxLength === undefined || maskPos < maxLength)) { 1788 result = _isValid(maskPos, c, strict); 1789 if ((!strict || fromSetValid === true) && result === false && validateOnly !== true) { 1790 var currentPosValid = getMaskSet().validPositions[maskPos]; 1791 if (currentPosValid && currentPosValid.match.fn === null && (currentPosValid.match.def === c || c === opts.skipOptionalPartCharacter)) { 1792 result = { 1793 "caret": seekNext(maskPos) 1794 }; 1795 } else if ((opts.insertMode || getMaskSet().validPositions[seekNext(maskPos)] === undefined) && !isMask(maskPos, true)) { //does the input match on a further position? 1796 for (var nPos = maskPos + 1, snPos = seekNext(maskPos); nPos <= snPos; nPos++) { 1797 // if (!isMask(nPos, true)) { 1798 // continue; 1799 // } 1800 result = _isValid(nPos, c, strict); 1801 if (result !== false) { 1802 trackbackAlternations(maskPos, result.pos !== undefined ? result.pos : nPos); 1803 maskPos = nPos; 1804 break; 1805 } 1806 } 1807 } 1808 } 1809 } 1810 if (result === false && opts.keepStatic && !strict && fromAlternate !== true) { //try fuzzy alternator logic 1811 result = alternate(maskPos, c, strict); 1812 } 1813 if (result === true) { 1814 result = { 1815 "pos": maskPos 1816 }; 1817 } 1818 } 1819 if ($.isFunction(opts.postValidation) && result !== false && !strict && fromSetValid !== true && validateOnly !== true) { 1820 var postResult = opts.postValidation(getBuffer(true), result, opts); 1821 if (postResult !== undefined) { 1822 if (postResult.refreshFromBuffer && postResult.buffer) { 1823 var refresh = postResult.refreshFromBuffer; 1824 refreshFromBuffer(refresh === true ? refresh : refresh.start, refresh.end, postResult.buffer); 1825 } 1826 result = postResult === true ? result : postResult; 1827 } 1828 } 1829 1830 if (result && result.pos === undefined) { 1831 result.pos = maskPos; 1832 } 1833 1834 if (result === false || validateOnly === true) { 1835 resetMaskSet(true); 1836 getMaskSet().validPositions = $.extend(true, {}, positionsClone); //revert validation changes 1837 } 1838 1839 return result; 1840 } 1841 1842 function isMask(pos, strict) { 1843 var test = getTestTemplate(pos).match; 1844 if (test.def === "") test = getTest(pos).match; 1845 1846 if (test.fn != null) { 1847 return test.fn; 1848 } 1849 if (strict !== true && pos > -1) { 1850 var tests = getTests(pos); 1851 return tests.length > 1 + (tests[tests.length - 1].match.def === "" ? 1 : 0); 1852 } 1853 return false;
1854 } 1855 1856 function seekNext(pos, newBlock) { 1857 var maskL = getMaskSet().maskLength; 1858 if (pos >= maskL) return maskL; 1859 var position = pos; 1860 if (getTests(maskL + 1).length > 1) { 1861 getMaskTemplate(true, maskL + 1, true); 1862 maskL = getMaskSet().maskLength; 1863 } 1864 while (++position < maskL && 1865 ((newBlock === true && (getTest(position).match.newBlockMarker !== true || !isMask(position))) || 1866 (newBlock !== true && !isMask(position)))) { 1867 } 1868 return position; 1869 } 1870 1871 function seekPrevious(pos, newBlock) { 1872 var position = pos, 1873 tests; 1874 if (position <= 0) return 0; 1875 1876 while (--position > 0 && 1877 ((newBlock === true && getTest(position).match.newBlockMarker !== true) || 1878 (newBlock !== true && !isMask(position) && 1879 (tests = getTests(position), tests.length < 2 || (tests.length === 2 && tests[1].match.def === ""))))) { 1880 } 1881 1882 return position; 1883 } 1884 1885 function getBufferElement(position) { 1886 return getMaskSet().validPositions[position] === undefined ? getPlaceholder(position) : getMaskSet().validPositions[position].input; 1887 } 1888 1889 function writeBuffer(input, buffer, caretPos, event, triggerInputEvent) { 1890 if (event && $.isFunction(opts.onBeforeWrite)) { 1891 // buffer = buffer.slice(); //prevent uncontrolled manipulation of the internal buffer 1892 var result = opts.onBeforeWrite.call(inputmask, event, buffer, caretPos, opts); 1893 if (result) { 1894 if (result.refreshFromBuffer) { 1895 var refresh = result.refreshFromBuffer; 1896 refreshFromBuffer(refresh === true ? refresh : refresh.start, refresh.end, result.buffer || buffer); 1897 buffer = getBuffer(true); 1898 } 1899 //only alter when intented !== undefined 1900 if (caretPos !== undefined) caretPos = result.caret !== undefined ? result.caret : caretPos; 1901 } 1902 } 1903 if (input !== undefined) { 1904 input.inputmask._valueSet(buffer.join("")); 1905 if (caretPos !== undefined && (event === undefined || event.type !== "blur")) { 1906 caret(input, caretPos); 1907 } else renderColorMask(input, caretPos, buffer.length === 0); 1908 if (triggerInputEvent === true) { 1909 skipInputEvent = true; 1910 $(input).trigger("input"); 1911 } 1912 } 1913 } 1914 1915 function getPlaceholder(pos, test, returnPL) { 1916 test = test || getTest(pos).match; 1917 if (test.placeholder !== undefined || returnPL === true) { 1918 return $.isFunction(test.placeholder) ? test.placeholder(opts) : test.placeholder; 1919 } else if (test.fn === null) { 1920 if (pos > -1 && getMaskSet().validPositions[pos] === undefined) { 1921 var tests = getTests(pos), 1922 staticAlternations = [], 1923 prevTest; 1924 if (tests.length > 1 + (tests[tests.length - 1].match.def === "" ? 1 : 0)) { 1925 for (var i = 0; i < tests.length; i++) { 1926 if (tests[i].match.optionality !== true && tests[i].match.optionalQuantifier !== true && 1927 (tests[i].match.fn === null || (prevTest === undefined || tests[i].match.fn.test(prevTest.match.def, getMaskSet(), pos, true, opts) !== false))) { 1928 staticAlternations.push(tests[i]); 1929 if (tests[i].match.fn === null) prevTest = tests[i]; 1930 if (staticAlternations.length > 1) { 1931 if (/[0-9a-bA-Z]/.test(staticAlternations[0].match.def)) { 1932 return opts.placeholder.charAt(pos % opts.placeholder.length); 1933 } 1934 } 1935 } 1936 } 1937 } 1938 } 1939 return test.def; 1940 } 1941 1942 return opts.placeholder.charAt(pos % opts.placeholder.length); 1943 } 1944 1945 1946 var EventRuler = { 1947 on: function (input, eventName, eventHandler) { 1948 var ev = function (e) { 1949 // console.log("triggered " + e.type); 1950 var that = this; 1951 if (that.inputmask === undefined && this.nodeName !== "FORM") { //happens when cloning an object with jquery.clone 1952 var imOpts = $.data(that, "_inputmask_opts");
1953 if (imOpts) (new Inputmask(imOpts)).mask(that); 1954 else EventRuler.off(that); 1955 } else if (e.type !== "setvalue" && this.nodeName !== "FORM" && (that.disabled || (that.readOnly && !(e.type === "keydown" && (e.ctrlKey && e.keyCode === 67) || (opts.tabThrough === false && e.keyCode === Inputmask.keyCode.TAB))))) { 1956 e.preventDefault(); 1957 } else { 1958 switch (e.type) { 1959 case "input": 1960 if (skipInputEvent === true) { 1961 skipInputEvent = false; 1962 return e.preventDefault(); 1963 } 1964 if (mobile) { 1965 trackCaret = true; 1966 } 1967 break; 1968 case "keydown": 1969 //Safari 5.1.x - modal dialog fires keypress twice workaround 1970 skipKeyPressEvent = false; 1971 skipInputEvent = false; 1972 break; 1973 case "keypress": 1974 if (skipKeyPressEvent === true) { 1975 return e.preventDefault(); 1976 } 1977 skipKeyPressEvent = true; 1978 break; 1979 case "click": 1980 if (iemobile || iphone) { 1981 var args = arguments; 1982 setTimeout(function () { 1983 eventHandler.apply(that, args); 1984 }, 0); 1985 return false; 1986 } 1987 break; 1988 } 1989 // console.log("executed " + e.type); 1990 var returnVal = eventHandler.apply(that, arguments); 1991 if (trackCaret) { 1992 trackCaret = false; 1993 setTimeout(function () { 1994 caret(that, that.inputmask.caretPos); 1995 // console.log("2 " + JSON.stringify(that.inputmask.caretPos)); 1996 }); 1997 } 1998 if (returnVal === false) { 1999 e.preventDefault(); 2000 e.stopPropagation(); 2001 } 2002 return returnVal; 2003 } 2004 }; 2005 //keep instance of the event 2006 input.inputmask.events[eventName] = input.inputmask.events[eventName] || []; 2007 input.inputmask.events[eventName].push(ev); 2008 2009 if ($.inArray(eventName, ["submit", "reset"]) !== -1) { 2010 if (input.form !== null) $(input.form).on(eventName, ev); 2011 } else { 2012 $(input).on(eventName, ev); 2013 } 2014 }, 2015 off: function (input, event) { 2016 if (input.inputmask && input.inputmask.events) { 2017 var events; 2018 if (event) { 2019 events = []; 2020 events[event] = input.inputmask.events[event]; 2021 } else { 2022 events = input.inputmask.events; 2023 } 2024 $.each(events, function (eventName, evArr) { 2025 while (evArr.length > 0) { 2026 var ev = evArr.pop(); 2027 if ($.inArray(eventName, ["submit", "reset"]) !== -1) { 2028 if (input.form !== null) $(input.form).off(eventName, ev); 2029 } else { 2030 $(input).off(eventName, ev); 2031 } 2032 } 2033 delete input.inputmask.events[eventName]; 2034 }); 2035 } 2036 } 2037 }; 2038 2039 2040 var EventHandlers = { 2041 keydownEvent: function (e) { 2042 var input = this, 2043 $input = $(input), 2044 k = e.keyCode, 2045 pos = caret(input); 2046 2047 //backspace, delete, and escape get special treatment 2048 if (k === Inputmask.keyCode.BACKSPACE || k === Inputmask.keyCode.DELETE || (iphone && k === Inputmask.keyCode.BACKSPACE_SAFARI) || (e.ctrlKey && k === Inputmask.keyCode.X && !isInputEventSupported("cut"))) { //backspace/delete 2049 e.preventDefault(); //stop default action but allow propagation 2050 handleRemove(input, k, pos); 2051 writeBuffer(input, getBuffer(true), getMaskSet().p, e, input.inputmask._valueGet() !== getBuffer().join("")); 2052 if (input.inputmask._valueGet() === getBufferTemplate().join("")) { 2053 $input.trigger("cleared"); 2054 } else if (isComplete(getBuffer()) === true) { 2055 $input.trigger("complete"); 2056 } 2057 } else if (k === Inputmask.keyCode.END || k === Inputmask.keyCode.PAGE_DOWN) { //when END or PAGE_DOWN pressed set position at lastmatch 2058 e.preventDefault(); 2059 var caretPos = seekNext(getLastValidPosition()); 2060 if (!opts.insertMode && caretPos === getMaskSet().maskLength && !e.shiftKey) caretPos--; 2061 caret(input, e.shiftKey ? pos.begin : caretPos, caretPos, true); 2062 } else if ((k === Inputmask.keyCode.HOME && !e.shiftKey) || k === Inputmask.keyCode.PAGE_UP) { //Home or page_up 2063 e.preventDefault(); 2064 caret(input, 0, e.shiftKey ? pos.begin : 0, true); 2065 } else if (((opts.undoOnEscape && k === Inputmask.keyCode.ESCAPE) || (k === 90 && e.ctrlKey)) && e.altKey !== true) { //escape && undo && #762 2066 checkVal(input, true, false, undoValue.split("")); 2067 $input.trigger("click"); 2068 } else if (k === Inputmask.keyCode.INSERT && !(e.shiftKey || e.ctrlKey)) { //insert 2069 opts.insertMode = !opts.insertMode; 2070 caret(input, !opts.insertMode && pos.begin === getMaskSet().maskLength ? pos.begin - 1 : pos.begin); 2071 } else if (opts.tabThrough === true && k === Inputmask.keyCode.TAB) { 2072 if (e.shiftKey === true) { 2073 if (getTest(pos.begin).match.fn === null) { 2074 pos.begin = seekNext(pos.begin); 2075 } 2076 pos.end = seekPrevious(pos.begin, true); 2077 pos.begin = seekPrevious(pos.end, true); 2078 } else { 2079 pos.begin = seekNext(pos.begin, true); 2080 pos.end = seekNext(pos.begin, true); 2081 if (pos.end < getMaskSet().maskLength) pos.end--; 2082 } 2083 if (pos.begin < getMaskSet().maskLength) { 2084 e.preventDefault(); 2085 caret(input, pos.begin, pos.end); 2086 } 2087 } else if (!e.shiftKey) { 2088 if (opts.insertMode === false) { 2089 if (k === Inputmask.keyCode.RIGHT) { 2090 setTimeout(function () { 2091 var caretPos = caret(input); 2092 caret(input, caretPos.begin); 2093 }, 0); 2094 } else if (k === Inputmask.keyCode.LEFT) { 2095 setTimeout(function () { 2096 var caretPos = caret(input); 2097 caret(input, isRTL ? caretPos.begin + 1 : caretPos.begin - 1); 2098 }, 0); 2099 } 2100 } 2101 } 2102 opts.onKeyDown.call(this, e, getBuffer(), caret(input).begin, opts); 2103 ignorable = $.inArray(k, opts.ignorables) !== -1; 2104 }, 2105 keypressEvent: function (e, checkval, writeOut, strict, ndx) { 2106 var input = this, 2107 $input = $(input), 2108 k = e.which || e.charCode || e.keyCode; 2109 2110 if (checkval !== true && (!(e.ctrlKey && e.altKey) && (e.ctrlKey || e.metaKey || ignorable))) { 2111 if (k === Inputmask.keyCode.ENTER && undoValue !== getBuffer().join("")) { 2112 undoValue = getBuffer().join(""); 2113 // e.preventDefault(); 2114 setTimeout(function () { 2115 $input.trigger("change"); 2116 }, 0); 2117 } 2118 return true; 2119 } else { 2120 if (k) { 2121 //special treat the decimal separator 2122 if (k === 46 && e.shiftKey === false && opts.radixPoint !== "") k = opts.radixPoint.charCodeAt(0); 2123 var pos = checkval ? { 2124 begin: ndx, 2125 end: ndx 2126 } : caret(input), 2127 forwardPosition, c = String.fromCharCode(k); 2128 2129 getMaskSet().writeOutBuffer = true; 2130 var valResult = isValid(pos, c, strict); 2131 if (valResult !== false) { 2132 resetMaskSet(true); 2133 forwardPosition = valResult.caret !== undefined ? valResult.caret : seekNext(valResult.pos.begin ? valResult.pos.begin : valResult.pos); 2134 getMaskSet().p = forwardPosition; //needed for checkval 2135 } 2136 2137 2138 forwardPosition = (opts.numericInput && valResult.caret === undefined) ? seekPrevious(forwardPosition) : forwardPosition; 2139 if (writeOut !== false) { 2140 setTimeout(function () { 2141 opts.onKeyValidation.call(input, k, valResult, opts); 2142 }, 0); 2143 if (getMaskSet().writeOutBuffer && valResult !== false) { 2144 var buffer = getBuffer(); 2145 writeBuffer(input, buffer, forwardPosition, e, checkval !== true); 2146 if (checkval !== true) { 2147 setTimeout(function () { //timeout needed for IE 2148 if (isComplete(buffer) === true) $
2148input.trigger("complete"); 2149 }, 0); 2150 } 2151 } 2152 } 2153 2154 e.preventDefault(); 2155 2156 if (checkval) { 2157 if (valResult !== false) valResult.forwardPosition = forwardPosition; 2158 return valResult; 2159 } 2160 } 2161 } 2162 }, 2163 pasteEvent: function (e) { 2164 var input = this, 2165 ev = e.originalEvent || e, 2166 $input = $(input), 2167 inputValue = input.inputmask._valueGet(true), 2168 caretPos = caret(input), 2169 tempValue; 2170 2171 // console.log(inputValue); 2172 2173 if (isRTL) { 2174 tempValue = caretPos.end; 2175 caretPos.end = caretPos.begin; 2176 caretPos.begin = tempValue; 2177 } 2178 2179 var valueBeforeCaret = inputValue.substr(0, caretPos.begin), 2180 valueAfterCaret = inputValue.substr(caretPos.end, inputValue.length); 2181 2182 if (valueBeforeCaret === (isRTL ? getBufferTemplate().reverse() : getBufferTemplate()).slice(0, caretPos.begin).join("")) valueBeforeCaret = ""; 2183 if (valueAfterCaret === (isRTL ? getBufferTemplate().reverse() : getBufferTemplate()).slice(caretPos.end).join("")) valueAfterCaret = ""; 2184 if (isRTL) { 2185 tempValue = valueBeforeCaret; 2186 valueBeforeCaret = valueAfterCaret; 2187 valueAfterCaret = tempValue; 2188 } 2189 2190 if (window.clipboardData && window.clipboardData.getData) { // IE 2191 inputValue = valueBeforeCaret + window.clipboardData.getData("Text") + valueAfterCaret; 2192 } else if (ev.clipboardData && ev.clipboardData.getData) { 2193 inputValue = valueBeforeCaret + ev.clipboardData.getData("text/plain") + valueAfterCaret; 2194 } else return true; //allow native paste event as fallback ~ masking will continue by inputfallback 2195 2196 var pasteValue = inputValue; 2197 // console.log(inputValue); 2198 if ($.isFunction(opts.onBeforePaste)) { 2199 pasteValue = opts.onBeforePaste.call(inputmask, inputValue, opts); 2200 if (pasteValue === false) { 2201 return e.preventDefault(); 2202 } 2203 if (!pasteValue) { 2204 pasteValue = inputValue; 2205 } 2206 } 2207 checkVal(input, false, false, isRTL ? pasteValue.split("").reverse() : pasteValue.toString().split("")); 2208 writeBuffer(input, getBuffer(), seekNext(getLastValidPosition()), e, undoValue !== getBuffer().join("")); 2209 if (isComplete(getBuffer()) === true) { 2210 $input.trigger("complete"); 2211 } 2212 2213 return e.preventDefault(); 2214 }, 2215 inputFallBackEvent: function (e) { //fallback when keypress is not triggered 2216 function radixPointHandler(input, inputValue, caretPos) { 2217 //radixpoint tweak 2218 if (inputValue.charAt(caretPos.begin - 1) === "." && opts.radixPoint !== "") { 2219 inputValue = inputValue.split(""); 2220 inputValue[caretPos.begin - 1] = opts.radixPoint.charAt(0); 2221 inputValue = inputValue.join(""); 2222 } 2223 2224 return inputValue; 2225 } 2226 2227 function ieMobileHandler(input, inputValue, caretPos) { 2228 if (iemobile) { //iemobile just sets the character at the end althought the caret position is correctly set 2229 var inputChar = inputValue.replace(getBuffer().join(""), ""); 2230 if (inputChar.length === 1) { 2231 var iv = inputValue.split(""); 2232 iv.splice(caretPos.begin, 0, inputChar); 2233 inputValue = iv.join(""); 2234 } 2235 } 2236 return inputValue; 2237 } 2238 2239 var input = this, 2240 inputValue = input.inputmask._valueGet(); 2241 2242 if (getBuffer().join("") !== inputValue) { 2243 2244 var caretPos = caret(input); 2245 inputValue = radixPointHandler(input, inputValue, caretPos); 2246 inputValue = ieMobileHandler(input, inputValue, caretPos); 2247 2248 // if (caretPos.begin > inputValue.length) { 2249 // caret(input, inputValue.length); 2250 // caretPos = caret(input); 2251 // } 2252 2253 if (getBuffer().join("") !== inputValue) { 2254 var buffer = getBuffer().join(""), 2255 offset = inputValue.length > buffer.length ? -1 : 0, 2256 frontPart = inputValue.substr(0, caretPos.begin), 2257 backPart = inputValue.substr(caretPos.begin), 2258 frontBufferPart = buffer.substr(0, caretPos.begin + offset), 2259 backBufferPart = buffer.substr(caretPos.begin + offset); 2260 2261 //check if thare was a selection 2262 var selection = caretPos,
2263 entries = "", 2264 isEntry = false; 2265 if (frontPart !== frontBufferPart) { 2266 var fpl = (isEntry = frontPart.length >= frontBufferPart.length) ? frontPart.length : frontBufferPart.length 2267 for (var i = 0; frontPart.charAt(i) === frontBufferPart.charAt(i) && i < fpl; i++) { 2268 } 2269 if (isEntry) { 2270 if (offset === 0) selection.begin = i; 2271 entries += frontPart.slice(i, selection.end); 2272 } 2273 } 2274 if (backPart !== backBufferPart) { 2275 if (backPart.length > backBufferPart.length) { 2276 entries += backPart.slice(0, 1); 2277 } else { 2278 if (backPart.length < backBufferPart.length) { 2279 selection.end += backBufferPart.length - backPart.length; 2280 //hack around numeric alias & radixpoint 2281 if (!isEntry && opts.radixPoint !== "" && backPart === "" && frontPart.charAt(selection.begin + offset - 1) === opts.radixPoint) { 2282 selection.begin--; 2283 entries = opts.radixPoint; 2284 } 2285 2286 2287 } 2288 } 2289 } 2290 2291 2292 writeBuffer(input, getBuffer(), { 2293 "begin": selection.begin + offset, 2294 "end": selection.end + offset 2295 }); 2296 if (entries.length > 0) { 2297 $.each(entries.split(""), function (ndx, entry) { 2298 var keypress = new $.Event("keypress"); 2299 keypress.which = entry.charCodeAt(0); 2300 ignorable = false; //make sure ignorable is ignored ;-) 2301 EventHandlers.keypressEvent.call(input, keypress); 2302 }); 2303 } else { 2304 if (selection.begin === selection.end - 1) { 2305 selection.begin = seekPrevious(selection.begin + 1); 2306 if (selection.begin === selection.end - 1) { 2307 caret(input, selection.begin); 2308 } else { 2309 caret(input, selection.begin, selection.end); 2310 } 2311 } 2312 var keydown = new $.Event("keydown"); 2313 keydown.keyCode = Inputmask.keyCode.DELETE; 2314 EventHandlers.keydownEvent.call(input, keydown); 2315 2316 if (opts.insertMode === false) { 2317 caret(input, caret(input).begin - 1); 2318 } 2319 } 2320 2321 // setTimeout(function(){ 2322 // console.log("2 " + JSON.stringify(caret(input))); 2323 // },0); 2324 2325 e.preventDefault(); 2326 } 2327 } 2328 }, 2329 setValueEvent: function (e) { 2330 this.inputmask.refreshValue = false; 2331 var input = this, 2332 value = input.inputmask._valueGet(true); 2333 2334 if ($.isFunction(opts.onBeforeMask)) value = opts.onBeforeMask.call(inputmask, value, opts) || value; 2335 value = value.split(""); 2336 checkVal(input, true, false, isRTL ? value.reverse() : value); 2337 undoValue = getBuffer().join(""); 2338 if ((opts.clearMaskOnLostFocus || opts.clearIncomplete) && input.inputmask._valueGet() === getBufferTemplate().join("")) { 2339 input.inputmask._valueSet(""); 2340 } 2341 } 2342 2343 , 2344 focusEvent: function (e) { 2345 var input = this, 2346 nptValue = input.inputmask._valueGet(); 2347 if (opts.showMaskOnFocus && (!opts.showMaskOnHover || (opts.showMaskOnHover && nptValue === ""))) { 2348 if (input.inputmask._valueGet() !== getBuffer().join("")) { 2349 writeBuffer(input, getBuffer(), seekNext(getLastValidPosition())); 2350 } else if (mouseEnter === false) { //only executed on focus without mouseenter 2351 caret(input, seekNext(getLastValidPosition())); 2352 } 2353 } 2354 if (opts.positionCaretOnTab === true && mouseEnter === false && nptValue !== "") { 2355 writeBuffer(input, getBuffer(), caret(input)); 2356 EventHandlers.clickEvent.apply(input, [e, true]); 2357 } 2358 undoValue = getBuffer().join(""); 2359 }, 2360 mouseleaveEvent: function (e) { 2361 var input = this; 2362 mouseEnter = false;
2363 if (opts.clearMaskOnLostFocus && document.activeElement !== input) { 2364 var buffer = getBuffer().slice(), 2365 nptValue = input.inputmask._valueGet(); 2366 if (nptValue !== input.getAttribute("placeholder") && nptValue !== "") { 2367 if (getLastValidPosition() === -1 && nptValue === getBufferTemplate().join("")) { 2368 buffer = []; 2369 } else { //clearout optional tail of the mask 2370 clearOptionalTail(buffer); 2371 } 2372 writeBuffer(input, buffer); 2373 } 2374 } 2375 }, 2376 clickEvent: function (e, tabbed) { 2377 function doRadixFocus(clickPos) { 2378 if (opts.radixPoint !== "") { 2379 var vps = getMaskSet().validPositions; 2380 if (vps[clickPos] === undefined || (vps[clickPos].input === getPlaceholder(clickPos))) { 2381 if (clickPos < seekNext(-1)) return true; 2382 var radixPos = $.inArray(opts.radixPoint, getBuffer()); 2383 if (radixPos !== -1) { 2384 for (var vp in vps) { 2385 if (radixPos < vp && vps[vp].input !== getPlaceholder(vp)) { 2386 return false; 2387 } 2388 } 2389 return true; 2390 } 2391 } 2392 } 2393 return false; 2394 } 2395 2396 var input = this; 2397 setTimeout(function () { //needed for Chrome ~ initial selection clears after the clickevent 2398 if (document.activeElement === input) { 2399 var selectedCaret = caret(input); 2400 if (tabbed) { 2401 if (isRTL) { 2402 selectedCaret.end = selectedCaret.begin; 2403 } else { 2404 selectedCaret.begin = selectedCaret.end; 2405 } 2406 } 2407 if (selectedCaret.begin === selectedCaret.end) { 2408 switch (opts.positionCaretOnClick) { 2409 case "none": 2410 break; 2411 case "radixFocus": 2412 if (doRadixFocus(selectedCaret.begin)) { 2413 var radixPos = getBuffer().join("").indexOf(opts.radixPoint); 2414 caret(input, opts.numericInput ? seekNext(radixPos) : radixPos); 2415 break; 2416 } 2417 default: //lvp: 2418 var clickPosition = selectedCaret.begin, 2419 lvclickPosition = getLastValidPosition(clickPosition, true), 2420 lastPosition = seekNext(lvclickPosition); 2421 if (clickPosition < lastPosition) { 2422 caret(input, !isMask(clickPosition, true) && !isMask(clickPosition - 1, true) ? seekNext(clickPosition) : clickPosition); 2423 } else { 2424 var lvp = getMaskSet().validPositions[lvclickPosition], 2425 tt = getTestTemplate(lastPosition, lvp ? lvp.match.locator : undefined, lvp), 2426 placeholder = getPlaceholder(lastPosition, tt.match); 2427 if ((placeholder !== "" && getBuffer()[lastPosition] !== placeholder && tt.match.optionalQuantifier !== true && tt.match.newBlockMarker !== true) || (!isMask(lastPosition, true) && tt.match.def === placeholder)) { 2428 var newPos = seekNext(lastPosition); 2429 if (clickPosition >= newPos || clickPosition === lastPosition) { 2430 lastPosition = newPos; 2431 } 2432 } 2433 caret(input, lastPosition); 2434 } 2435 break; 2436 } 2437 } 2438 } 2439 }, 0); 2440 }, 2441 dblclickEvent: function (e) { 2442 var input = this; 2443 setTimeout(function () { 2444 caret(input, 0, seekNext(getLastValidPosition())); 2445 }, 0); 2446 }, 2447 cutEvent: function (e) { 2448 var input = this, 2449 $input = $(input), 2450 pos = caret(input), 2451 ev = e.originalEvent || e; 2452 2453 //correct clipboardData 2454 var clipboardData = window.clipboardData || ev.clipboardData, 2455 clipData = isRTL ? getBuffer().slice(pos.end, pos.begin) : getBuffer().slice(pos.begin, pos.end); 2456 clipboardData.setData("text", isRTL ? clipData.reverse().join("") : clip
2456Data.join("")); 2457 if (document.execCommand) document.execCommand("copy"); // copy selected content to system clipbaord 2458 2459 handleRemove(input, Inputmask.keyCode.DELETE, pos); 2460 writeBuffer(input, getBuffer(), getMaskSet().p, e, undoValue !== getBuffer().join("")); 2461 2462 if (input.inputmask._valueGet() === getBufferTemplate().join("")) { 2463 $input.trigger("cleared"); 2464 } 2465 }, 2466 blurEvent: function (e) { 2467 var $input = $(this), 2468 input = this; 2469 if (input.inputmask) { 2470 var nptValue = input.inputmask._valueGet(), 2471 buffer = getBuffer().slice(); 2472 2473 if (nptValue !== "" || colorMask !== undefined) { 2474 if (opts.clearMaskOnLostFocus) { 2475 if (getLastValidPosition() === -1 && nptValue === getBufferTemplate().join("")) { 2476 buffer = []; 2477 } else { //clearout optional tail of the mask 2478 clearOptionalTail(buffer); 2479 } 2480 } 2481 if (isComplete(buffer) === false) { 2482 setTimeout(function () { 2483 $input.trigger("incomplete"); 2484 }, 0); 2485 if (opts.clearIncomplete) { 2486 resetMaskSet(); 2487 if (opts.clearMaskOnLostFocus) { 2488 buffer = []; 2489 } else { 2490 buffer = getBufferTemplate().slice(); 2491 } 2492 } 2493 } 2494 2495 writeBuffer(input, buffer, undefined, e); 2496 } 2497 2498 if (undoValue !== getBuffer().join("")) { 2499 undoValue = buffer.join(""); 2500 $input.trigger("change"); 2501 } 2502 } 2503 }, 2504 mouseenterEvent: function (e) { 2505 var input = this; 2506 mouseEnter = true; 2507 if (document.activeElement !== input && opts.showMaskOnHover) { 2508 if (input.inputmask._valueGet() !== getBuffer().join("")) { 2509 writeBuffer(input, getBuffer()); 2510 } 2511 } 2512 }, 2513 submitEvent: function (e) { //trigger change on submit if any 2514 if (undoValue !== getBuffer().join("")) { 2515 $el.trigger("change"); 2516 } 2517 if (opts.clearMaskOnLostFocus && getLastValidPosition() === -1 && el.inputmask._valueGet && el.inputmask._valueGet() === getBufferTemplate().join("")) { 2518 el.inputmask._valueSet(""); //clear masktemplete on submit and still has focus 2519 } 2520 if (opts.removeMaskOnSubmit) { 2521 el.inputmask._valueSet(el.inputmask.unmaskedvalue(), true); 2522 setTimeout(function () { 2523 writeBuffer(el, getBuffer()); 2524 }, 0); 2525 } 2526 }, 2527 resetEvent: function (e) { 2528 el.inputmask.refreshValue = true; //indicate a forced refresh when there is a call to the value before leaving the triggering event fn 2529 setTimeout(function () { 2530 $el.trigger("setvalue"); 2531 }, 0); 2532 } 2533 }; 2534 2535 function checkVal(input, writeOut, strict, nptvl, initiatingEvent) { 2536 var inputValue = nptvl.slice(), 2537 charCodes = "", 2538 initialNdx = -1, 2539 result = undefined; 2540 2541 // console.log(nptvl); 2542 2543 function isTemplateMatch(ndx, charCodes) { 2544 var charCodeNdx = getMaskTemplate(true, 0, false).slice(ndx, seekNext(ndx)).join("").indexOf(charCodes); 2545 return charCodeNdx !== -1 && !isMask(ndx) && 2546 (getTest(ndx).match.nativeDef === charCodes.charAt(0) || 2547 (getTest(ndx).match.nativeDef === " " && getTest(ndx + 1).match.nativeDef === charCodes.charAt(0))); 2548 } 2549 2550 resetMaskSet(); 2551 if (!strict && opts.autoUnmask !== true) { 2552 var staticInput = getBufferTemplate().slice(0, seekNext(-1)).join(""), 2553 matches = inputValue.join("").match(new RegExp("^" + Inputmask.escapeRegex(staticInput), "g")); 2554 if (matches && matches.length > 0) { 2555 inputValue.splice(0, matches.length * staticInput.length); 2556 initialNdx = seekNext(initialNdx); 2557 } 2558 } else { 2559 initialNdx = seekNext(initialNdx); 2560 } 2561 if (initialNdx === -1) { 2562 getMaskSet().p = seekNext(initialNdx); 2563 initialNdx = 0; 2564 } else getMaskSet().p = initialNdx;
2565 $.each(inputValue, function (ndx, charCode) { 2566 // console.log(charCode); 2567 if (charCode !== undefined) { //inputfallback strips some elements out of the inputarray. $.each logically presents them as undefined 2568 if (getMaskSet().validPositions[ndx] === undefined && inputValue[ndx] === getPlaceholder(ndx) && isMask(ndx, true) && 2569 isValid(ndx, inputValue[ndx], true, undefined, undefined, true) === false) { 2570 getMaskSet().p++; 2571 } else { 2572 2573 var keypress = new $.Event("_checkval"); 2574 keypress.which = charCode.charCodeAt(0); 2575 charCodes += charCode; 2576 var lvp = getLastValidPosition(undefined, true), 2577 prevTest = getTest(lvp), 2578 nextTest = getTestTemplate(lvp + 1, prevTest ? prevTest.locator.slice() : undefined, lvp); 2579 if (!isTemplateMatch(initialNdx, charCodes) || strict || opts.autoUnmask) { 2580 var pos = strict ? ndx : (nextTest.match.fn == null && nextTest.match.optionality && (lvp + 1) < getMaskSet().p ? lvp + 1 : getMaskSet().p); 2581 result = EventHandlers.keypressEvent.call(input, keypress, true, false, strict, pos); 2582 2583 if (result) { 2584 initialNdx = pos + 1; 2585 charCodes = ""; 2586 } 2587 } else { 2588 result = EventHandlers.keypressEvent.call(input, keypress, true, false, true, lvp + 1); 2589 } 2590 writeBuffer(undefined, getBuffer(), result.forwardPosition, keypress, false); 2591 } 2592 } 2593 }); 2594 2595 try{ 2596 if (writeOut) 2597 writeBuffer(input, getBuffer(), result.forwardPosition, initiatingEvent || new $.Event("checkval"), initiatingEvent && initiatingEvent.type === "input"); 2598 } catch (e) { 2599 2600 } 2601 2602 } 2603 2604 function unmaskedvalue(input) { 2605 if (input) { 2606 if (input.inputmask === undefined) { 2607 return input.value; 2608 } 2609 if (input.inputmask && input.inputmask.refreshValue) { //forced refresh from the value form.reset 2610 EventHandlers.setValueEvent.call(input); 2611 } 2612 } 2613 var umValue = [], 2614 vps = getMaskSet().validPositions; 2615 for (var pndx in vps) { 2616 if (vps[pndx].match && vps[pndx].match.fn != null) { 2617 umValue.push(vps[pndx].input); 2618 } 2619 } 2620 var unmaskedValue = umValue.length === 0 ? "" : (isRTL ? umValue.reverse() : umValue).join(""); 2621 if ($.isFunction(opts.onUnMask)) { 2622 var bufferValue = (isRTL ? getBuffer().slice().reverse() : getBuffer()).join(""); 2623 unmaskedValue = opts.onUnMask.call(inputmask, bufferValue, unmaskedValue, opts); 2624 } 2625 return unmaskedValue; 2626 } 2627 2628 function caret(input, begin, end, notranslate) { 2629 function translatePosition(pos) { 2630 if (notranslate !== true && isRTL && typeof pos === "number" && (!opts.greedy || opts.placeholder !== "")) { 2631 pos = input.inputmask.__valueGet.call(input).length - pos; 2632 } 2633 return pos; 2634 } 2635 2636 var range; 2637 if (begin !== undefined) { 2638 if (begin.begin !== undefined) { 2639 end = isRTL ? begin.begin : begin.end; 2640 begin = isRTL ? begin.end : begin.begin; 2641 } 2642 if (typeof begin === "number") { 2643 begin = translatePosition(begin); 2644 end = translatePosition(end); 2645 end = (typeof end == "number") ? end : begin; 2646 // if (!$(input).is(":visible")) { 2647 // return; 2648 // } 2649 2650 var scrollCalc = parseInt(((input.ownerDocument.defaultView || window).getComputedStyle ? (input.ownerDocument.defaultView || window).getComputedStyle(input, null) : input.currentStyle).fontSize) * end; 2651 input.scrollLeft = scrollCalc > input.scrollWidth ? scrollCalc : 0; 2652 2653 if (opts.insertMode === false && begin === end) end++; //set visualization for insert/overwrite mode 2654 2655 input.inputmask.caretPos = {begin: begin, end: end}; //track caret internally 2656 if (input.setSelectionRange) { 2657 input.selectionStart = begin; 2658 input.selectionEnd = end; 2659 } else if (window.getSelection) { 2660 range = document.createRange(); 2661 if (input.firstChild === undefined || input.firstChild === null) { 2662 var textNode = document.createTextNode(""); 2663 input.appendChild(textNode); 2664 } 2665 range.setStart(input.firstChild, begin < input.inputmask._valueGet().length ? begin : input.inputmask._valueGet().length); 2666 range.setEnd(input.firstChild, end < input.inputmask._valueGet().length ? end : input.inputmask._valueGet().length); 2667 range.collapse(true); 2668 var sel = window.getSelection(); 2669 sel.removeAllRanges(); 2670 sel.addRange(range); 2671 //input.focus(); 2672 } else if (input.createTextRange) { 2673 range = input.createTextRange(); 2674 range.collapse(true); 2675 range.moveEnd("character", end); 2676 range.moveStart("character", begin); 2677 range.select(); 2678 2679 } 2680 renderColorMask(input, { 2681 begin: begin, 2682 end: end 2683 }); 2684 } 2685 } else { 2686 if (input.setSelectionRange) { 2687 begin = input.selectionStart; 2688 end = input.selectionEnd; 2689 } else if (window.getSelection) { 2690 range = window.getSelection().getRangeAt(0); 2691 if (range.commonAncestorContainer.parentNode === input || range.commonAncestorContainer === input) { 2692 begin = range.startOffset; 2693 end = range.endOffset; 2694 } 2695 } else if (document.selection && document.selection.createRange) { 2696 range = document.selection.createRange(); 2697 begin = 0 - range.duplicate().moveStart("character", -input.inputmask._valueGet().length); 2698 end = begin + range.text.length; 2699 } 2700 2701 /*eslint-disable consistent-return */ 2702 return { 2703 "begin": translatePosition(begin),
2704 "end": translatePosition(end) 2705 }; 2706 /*eslint-enable consistent-return */ 2707 } 2708 } 2709 2710 function determineLastRequiredPosition(returnDefinition) { 2711 var buffer = getBuffer(), 2712 bl = buffer.length, 2713 pos, lvp = getLastValidPosition(), 2714 positions = {}, 2715 lvTest = getMaskSet().validPositions[lvp], 2716 ndxIntlzr = lvTest !== undefined ? lvTest.locator.slice() : undefined, 2717 testPos; 2718 for (pos = lvp + 1; pos < buffer.length; pos++) { 2719 testPos = getTestTemplate(pos, ndxIntlzr, pos - 1); 2720 ndxIntlzr = testPos.locator.slice(); 2721 positions[pos] = $.extend(true, {}, testPos); 2722 } 2723 2724 var lvTestAlt = lvTest && lvTest.alternation !== undefined ? lvTest.locator[lvTest.alternation] : undefined; 2725 for (pos = bl - 1; pos > lvp; pos--) { 2726 testPos = positions[pos]; 2727 if ((testPos.match.optionality || 2728 (testPos.match.optionalQuantifier && testPos.match.newBlockMarker) || 2729 (lvTestAlt && 2730 ((lvTestAlt !== positions[pos].locator[lvTest.alternation] && testPos.match.fn != null) || 2731 (testPos.match.fn === null && testPos.locator[lvTest.alternation] && checkAlternationMatch(testPos.locator[lvTest.alternation].toString().split(","), lvTestAlt.toString().split(",")) && getTests(pos)[0].def !== "")))) && 2732 buffer[pos] === getPlaceholder(pos, testPos.match)) { 2733 bl--; 2734 } else break; 2735 } 2736 return returnDefinition ? { 2737 "l": bl, 2738 "def": positions[bl] ? positions[bl].match : undefined 2739 } : bl; 2740 } 2741 2742 function clearOptionalTail(buffer) { 2743 var rl = determineLastRequiredPosition(), 2744 validPos, bl = buffer.length; 2745 2746 var lv = getMaskSet().validPositions[getLastValidPosition()]; 2747 while (rl < bl && 2748 !isMask(rl, true) && 2749 (validPos = (lv !== undefined ? getTestTemplate(rl, lv.locator.slice(""), lv) : getTest(rl))) && 2750 validPos.match.optionality !== true && 2751 ((validPos.match.optionalQuantifier !== true && validPos.match.newBlockMarker !== true) || (rl + 1 === bl && 2752 (lv !== undefined ? getTestTemplate(rl + 1, lv.locator.slice(""), lv) : getTest(rl + 1)).match.def === ""))) { 2753 rl++; 2754 } 2755 2756 //exceptionally strip from the validatedPositions 2757 while ((validPos = getMaskSet().validPositions[rl - 1]) && validPos && validPos.match.optionality && validPos.input === opts.skipOptionalPartCharacter) { 2758 rl--; 2759 } 2760 buffer.splice(rl); 2761 return buffer; 2762 } 2763 2764 function isComplete(buffer) { //return true / false / undefined (repeat *) 2765 if ($.isFunction(opts.isComplete)) return opts.isComplete(buffer, opts); 2766 if (opts.repeat === "*") return undefined; 2767 var complete = false, 2768 lrp = determineLastRequiredPosition(true), 2769 aml = seekPrevious(lrp.l); 2770 2771 if (lrp.def === undefined || lrp.def.newBlockMarker || lrp.def.optionality || lrp.def.optionalQuantifier) { 2772 complete = true; 2773 for (var i = 0; i <= aml; i++) { 2774 var test = getTestTemplate(i).match; 2775 if ((test.fn !== null && getMaskSet().validPositions[i] === undefined && test.optionality !== true && test.optionalQuantifier !== true) || (test.fn === null && buffer[i] !== getPlaceholder(i, test))) { 2776 complete = false; 2777 break; 2778 } 2779 } 2780 } 2781 return complete; 2782 } 2783 2784 2785 function handleRemove(input, k, pos, strict, fromIsValid) { 2786 function generalize() { 2787 if (opts.keepStatic) { 2788 var validInputs = [], 2789 lastAlt = getLastValidPosition(-1, true), 2790 positionsClone = $.extend(true, {}, getMaskSet().validPositions), 2791 prevAltPos = getMaskSet().validPositions[lastAlt]; 2792 //find last alternation 2793 for (; lastAlt >= 0; lastAlt--) { 2794 var altPos = getMaskSet().validPositions[lastAlt]; 2795 if (altPos) { 2796 if (altPos.generatedInput !== true && /[0-9a-bA-Z]/.test(altPos.input)) { 2797 validInputs.push(altPos.input); 2798 } 2799 delete getMaskSet().validPositions[lastAlt]; 2800 if (altPos.alternation !== undefined && altPos.locator[altPos.alternation] !== prevAltPos.locator[altPos.alternation]) { 2801 break; 2802 } 2803 prevAltPos = altPos; 2804 } 2805 } 2806 2807 if (lastAlt > -1) { 2808 getMaskSet().p = seekNext(getLastValidPosition(-1, true)); 2809 while (validInputs.length > 0) { 2810 var keypress = new $.Event("keypress"); 2811 keypress.which = validInputs.pop().charCo
2811deAt(0); 2812 // eslint-disable-next-line no-use-before-define 2813 EventHandlers.keypressEvent.call(input, keypress, true, false, false, getMaskSet().p); 2814 2815 } 2816 } else getMaskSet().validPositions = $.extend(true, {}, positionsClone); //restore original positions 2817 } 2818 } 2819 2820 if (opts.numericInput || isRTL) { 2821 if (k === Inputmask.keyCode.BACKSPACE) { 2822 k = Inputmask.keyCode.DELETE; 2823 } else if (k === Inputmask.keyCode.DELETE) { 2824 k = Inputmask.keyCode.BACKSPACE; 2825 } 2826 2827 if (isRTL) { 2828 var pend = pos.end; 2829 pos.end = pos.begin; 2830 pos.begin = pend; 2831 } 2832 } 2833 2834 if (k === Inputmask.keyCode.BACKSPACE && (pos.end - pos.begin < 1 || opts.insertMode === false)) { 2835 pos.begin = seekPrevious(pos.begin); 2836 if (getMaskSet().validPositions[pos.begin] !== undefined && getMaskSet().validPositions[pos.begin].input === opts.groupSeparator) { 2837 pos.begin--; 2838 } 2839 } else if (k === Inputmask.keyCode.DELETE && pos.begin === pos.end) { 2840 pos.end = isMask(pos.end, true) && (getMaskSet().validPositions[pos.end] && getMaskSet().validPositions[pos.end].input !== opts.radixPoint) ? 2841 pos.end + 1 : 2842 seekNext(pos.end) + 1; 2843 if (getMaskSet().validPositions[pos.begin] !== undefined && getMaskSet().validPositions[pos.begin].input === opts.groupSeparator) { 2844 pos.end++; 2845 } 2846 } 2847 2848 stripValidPositions(pos.begin, pos.end, false, strict); 2849 if (strict !== true) { 2850 generalize(); //revert the alternation 2851 } 2852 var lvp = getLastValidPosition(pos.begin, true); 2853 if (lvp < pos.begin) { 2854 //if (lvp === -1) resetMaskSet(); 2855 getMaskSet().p = seekNext(lvp); 2856 } else if (strict !== true) { 2857 getMaskSet().p = pos.begin; 2858 if (fromIsValid !== true) { 2859 //put position on first valid from pos.begin ~ #1351 2860 while (getMaskSet().p < lvp && getMaskSet().validPositions[getMaskSet().p] === undefined) { 2861 getMaskSet().p++; 2862 } 2863 } 2864 } 2865 } 2866 2867 function initializeColorMask(input) { 2868 var computedStyle = (input.ownerDocument.defaultView || window).getComputedStyle(input, null); 2869 2870 function findCaretPos(clientx) { 2871 //calculate text width 2872 var e = document.createElement("span"), 2873 caretPos; 2874 for (var style in computedStyle) { //clone styles 2875 if (isNaN(style) && style.indexOf("font") !== -1) { 2876 e.style[style] = computedStyle[style]; 2877 } 2878 } 2879 e.style.textTransform = computedStyle.textTransform; 2880 e.style.letterSpacing = computedStyle.letterSpacing; 2881 e.style.position = "absolute"; 2882 e.style.height = "auto"; 2883 e.style.width = "auto"; 2884 e.style.visibility = "hidden"; 2885 e.style.whiteSpace = "nowrap"; 2886 2887 document.body.appendChild(e); 2888 var inputText = input.inputmask._valueGet(), 2889 previousWidth = 0, 2890 itl; 2891 for (caretPos = 0, itl = inputText.length; caretPos <= itl; caretPos++) { 2892 e.innerHTML += inputText.charAt(caretPos) || "_"; 2893 if (e.offsetWidth >= clientx) { 2894 var offset1 = (clientx - previousWidth); 2895 var offset2 = e.offsetWidth - clientx; 2896 e.innerHTML = inputText.charAt(caretPos); 2897 offset1 -= (e.offsetWidth / 3); 2898 caretPos = offset1 < offset2 ? caretPos - 1 : caretPos; 2899 break; 2900 } 2901 previousWidth = e.offsetWidth; 2902 } 2903 document.body.removeChild(e); 2904 return caretPos; 2905 } 2906 2907 var template = document.createElement("div"); 2908 template.style.width = computedStyle.width; 2909 template.style.textAlign = computedStyle.textAlign; 2910 colorMask = document.createElement("div"); 2911 input.inputmask.colorMask = colorMask; 2912 colorMask.className = "im-colormask"; 2913 input.parentNode.insertBefore(colorMask, input); 2914 input.parentNode.removeChild(input); 2915 colorMask.appendChild(template); 2916 colorMask.appendChild(input); 2917 input.style.left = template.offsetLeft + "px"; 2918 2919 $(input).on("click", function (e) { 2920 caret(input, findCaretPos(e.clientX)); 2921 return EventHandlers.clickEvent.call(input, [e]); 2922 }); 2923 $(input).on("keydown", function (e) { 2924 if (!e.shiftKey && opts.insertMode !== false) { 2925 setTimeout(function () { 2926 renderColorMask(input); 2927 }, 0); 2928 } 2929 }); 2930 } 2931 2932 Inputmask.prototype.positionColorMask = function (input, template) { 2933 input.style.left = template.offsetLeft + "px"; 2934 } 2935 2936 function renderColorMask(input, caretPos, clear) { 2937 var maskTemplate = "", 2938 isStatic = false, 2939 test, testPos, ndxIntlzr, pos = 0; 2940 2941 function handleStatic() { 2942 if (!isStatic && (test.fn === null || testPos.input === undefined)) { 2943 isStatic = true; 2944 maskTemplate += "<span class='im-static'>" 2945 } else if (isStatic && ((test.fn !== null && testPos.input !== undefined) || test.def === "")) { 2946 isStatic = false;
2947 maskTemplate += "</span>" 2948 } 2949 } 2950 2951 function handleCaret(force) { 2952 if ((force === true || pos === caretPos.begin) && document.activeElement === input) { 2953 maskTemplate += "<span class='im-caret' style='border-right-width: 1px;border-right-style: solid;'></span>"; 2954 } 2955 } 2956 2957 if (colorMask !== undefined) { 2958 var buffer = getBuffer(); 2959 if (caretPos === undefined) { 2960 caretPos = caret(input); 2961 } else if (caretPos.begin === undefined) { 2962 caretPos = { 2963 begin: caretPos, 2964 end: caretPos 2965 }; 2966 } 2967 2968 if (clear !== true) { 2969 var lvp = getLastValidPosition(); 2970 do { 2971 handleCaret(); 2972 if (getMaskSet().validPositions[pos]) { 2973 testPos = getMaskSet().validPositions[pos]; 2974 test = testPos.match; 2975 ndxIntlzr = testPos.locator.slice(); 2976 handleStatic(); 2977 maskTemplate += buffer[pos]; 2978 } else { 2979 testPos = getTestTemplate(pos, ndxIntlzr, pos - 1); 2980 test = testPos.match; 2981 ndxIntlzr = testPos.locator.slice(); 2982 if (opts.jitMasking === false || pos < lvp || (typeof opts.jitMasking === "number" && isFinite(opts.jitMasking) && opts.jitMasking > pos)) { 2983 handleStatic(); 2984 maskTemplate += getPlaceholder(pos, test); 2985 } 2986 } 2987 pos++; 2988 } while ((maxLength === undefined || pos < maxLength) && (test.fn !== null || test.def !== "") || lvp > pos || isStatic); 2989 if (maskTemplate.indexOf("im-caret") === -1) handleCaret(true); 2990 if (isStatic) handleStatic(); 2991 } 2992 2993 var template = colorMask.getElementsByTagName("div")[0]; 2994 template.innerHTML = maskTemplate; 2995 input.inputmask.positionColorMask(input, template); 2996 } 2997 } 2998 2999 function mask(elem) { 3000 function isElementTypeSupported(input, opts) { 3001 function patchValueProperty(npt) { 3002 var valueGet; 3003 var valueSet; 3004 3005 function patchValhook(type) { 3006 if ($.valHooks && ($.valHooks[type] === undefined || $.valHooks[type].inputmaskpatch !== true)) { 3007 var valhookGet = $.valHooks[type] && $.valHooks[type].get ? $.valHooks[type].get : function (elem) { 3008 return elem.value; 3009 }; 3010 var valhookSet = $.valHooks[type] && $.valHooks[type].set ? $.valHooks[type].set : function (elem, value) { 3011 elem.value = value; 3012 return elem; 3013 }; 3014 3015 $.valHooks[type] = { 3016 get: function (elem) { 3017 if (elem.inputmask) { 3018 if (elem.inputmask.opts.autoUnmask) { 3019 return elem.inputmask.unmaskedvalue(); 3020 } else { 3021 var result = valhookGet(elem); 3022 return getLastValidPosition(undefined, undefined, elem.inputmask.maskset.validPositions) !== -1 || opts.nullable !== true ? result : ""; 3023 } 3024 } else return valhookGet(elem); 3025 }, 3026 set: function (elem, value) { 3027 var $elem = $(elem), 3028 result; 3029 result = valhookSet(elem, value); 3030 if (elem.inputmask) { 3031 $elem.trigger("setvalue"); 3032 } 3033 return result; 3034 }, 3035 inputmaskpatch: true 3036 }; 3037 } 3038 } 3039 3040 function getter() { 3041 if (this.inputmask) { 3042 return this.inputmask.opts.autoUnmask ? 3043 this.inputmask.unmaskedvalue() : 3044 (getLastValidPosition() !== -1 || opts.nullable !== true ? 3045 (document.activeElement === this && opts.clearMaskOnLostFocus ? 3046 (isRTL ? clearOptionalTail(getBuffer().slice()).reverse() : clearOptionalTail(getBuffer().slice())).join("") : 3047 valueGet.call(this)) : 3048 ""); 3049 } else return valueGet.call(this); 3050 } 3051 3052 function setter(value) { 3053 valueSet.call(this, value); 3054 if (this.inputmask) { 3055 $(this).trigger("setvalue"); 3056 } 3057 } 3058 3059 function installNativeValueSetFallback(npt) { 3060 EventRuler.on(npt, "mouseenter", function (event) { 3061 var $input = $(this), 3062 input = this, 3063 value = input.inputmask._valueGet(); 3064 if (value !== getBuffer().join("") /*&& getLastValidPosition() > 0*/) { 3065 $input.trigger("setvalue"); 3066 } 3067 }); 3068 } 3069 3070 if (!npt.inputmask.__valueGet) { 3071 if (opts.noValuePatching !== true) { 3072 if (Object.getOwnPropertyDescriptor) { 3073 if (typeof Object.getPrototypeOf
3073!== "function") { 3074 Object.getPrototypeOf = typeof "test".__proto__ === "object" ? function (object) { 3075 return object.__proto__; 3076 } : function (object) { 3077 return object.constructor.prototype; 3078 }; 3079 } 3080 3081 var valueProperty = Object.getPrototypeOf ? Object.getOwnPropertyDescriptor(Object.getPrototypeOf(npt), "value") : undefined; 3082 if (valueProperty && valueProperty.get && valueProperty.set) { 3083 valueGet = valueProperty.get; 3084 valueSet = valueProperty.set; 3085 Object.defineProperty(npt, "value", { 3086 get: getter, 3087 set: setter, 3088 configurable: true 3089 }); 3090 } else if (npt.tagName !== "INPUT") { 3091 valueGet = function () { 3092 return this.textContent; 3093 }; 3094 valueSet = function (value) { 3095 this.textContent = value; 3096 }; 3097 Object.defineProperty(npt, "value", { 3098 get: getter, 3099 set: setter, 3100 configurable: true 3101 }); 3102 } 3103 } else if (document.__lookupGetter__ && npt.__lookupGetter__("value")) { 3104 valueGet = npt.__lookupGetter__("value"); 3105 valueSet = npt.__lookupSetter__("value"); 3106 3107 npt.__defineGetter__("value", getter); 3108 npt.__defineSetter__("value", setter); 3109 } 3110 npt.inputmask.__valueGet = valueGet; //store native property getter 3111 npt.inputmask.__valueSet = valueSet; //store native property setter 3112 } 3113 npt.inputmask._valueGet = function (overruleRTL) { 3114 return isRTL && overruleRTL !== true ? valueGet.call(this.el).split("").reverse().join("") : valueGet.call(this.el); 3115 }; 3116 npt.inputmask._valueSet = function (value, overruleRTL) { //null check is needed for IE8 => otherwise converts to "null" 3117 valueSet.call(this.el, (value === null || value === undefined) ? "" : ((overruleRTL !== true && isRTL) ? value.split("").reverse().join("") : value)); 3118 }; 3119 3120 if (valueGet === undefined) { //jquery.val fallback 3121 valueGet = function () { 3122 return this.value; 3123 }; 3124 valueSet = function (value) { 3125 this.value = value; 3126 }; 3127 patchValhook(npt.type); 3128 installNativeValueSetFallback(npt); 3129 } 3130 } 3131 } 3132 3133 var elementType = input.getAttribute("type"); 3134 var isSupported = (input.tagName === "INPUT" && $.inArray(elementType, opts.supportsInputType) !== -1) || input.isContentEditable || input.tagName === "TEXTAREA"; 3135 if (!isSupported) { 3136 if (input.tagName === "INPUT") { 3137 var el = document.createElement("input"); 3138 el.setAttribute("type", elementType); 3139 isSupported = el.type === "text"; //apply mask only if the type is not natively supported 3140 el = null; 3141 } else isSupported = "partial"; 3142 } 3143 if (isSupported !== false) { 3144 patchValueProperty(input); 3145 } else input.inputmask = undefined; 3146 return isSupported; 3147 } 3148 3149 //unbind all events - to make sure that no other mask will interfere when re-masking 3150 EventRuler.off(elem); 3151 var isSupported = isElementTypeSupported(elem, opts); 3152 if (isSupported !== false) { 3153 el = elem; 3154 $el = $(el); 3155 3156 //read maxlength prop from el 3157 maxLength = el !== undefined ? el.maxLength : undefined; 3158 if (maxLength === -1) maxLength = undefined; 3159 3160 if (opts.colorMask === true) { 3161 initializeColorMask(el); 3162 } 3163 if (mobile) { 3164 if ("inputmode" in el) { 3165 el.inputmode = opts.inputmode; 3166 el.setAttribute("inputmode", opts.inputmode); 3167 } 3168 if (opts.disablePredictiveText === true) { 3169 if ("autocorrect" in el) { //safari 3170 el.autocorrect = false;
3171 } else { 3172 if (opts.colorMask !== true) { 3173 initializeColorMask(el); 3174 } 3175 el.type = "password"; 3176 } 3177 } 3178 } 3179 3180 if (isSupported === true) { 3181 //bind events 3182 EventRuler.on(el, "submit", EventHandlers.submitEvent); 3183 EventRuler.on(el, "reset", EventHandlers.resetEvent); 3184 3185 EventRuler.on(el, "mouseenter", EventHandlers.mouseenterEvent); 3186 EventRuler.on(el, "blur", EventHandlers.blurEvent); 3187 EventRuler.on(el, "focus", EventHandlers.focusEvent); 3188 EventRuler.on(el, "mouseleave", EventHandlers.mouseleaveEvent); 3189 if (opts.colorMask !== true) { 3190 EventRuler.on(el, "click", EventHandlers.clickEvent); 3191 } 3192 EventRuler.on(el, "dblclick", EventHandlers.dblclickEvent); 3193 EventRuler.on(el, "paste", EventHandlers.pasteEvent); 3194 EventRuler.on(el, "dragdrop", EventHandlers.pasteEvent); 3195 EventRuler.on(el, "drop", EventHandlers.pasteEvent); 3196 EventRuler.on(el, "cut", EventHandlers.cutEvent); 3197 EventRuler.on(el, "complete", opts.oncomplete); 3198 EventRuler.on(el, "incomplete", opts.onincomplete); 3199 EventRuler.on(el, "cleared", opts.oncleared); 3200 if (!mobile && opts.inputEventOnly !== true) { 3201 EventRuler.on(el, "keydown", EventHandlers.keydownEvent); 3202 EventRuler.on(el, "keypress", EventHandlers.keypressEvent); 3203 } else { 3204 el.removeAttribute("maxLength"); 3205 } 3206 EventRuler.on(el, "compositionstart", $.noop); 3207 EventRuler.on(el, "compositionupdate", $.noop); 3208 EventRuler.on(el, "compositionend", $.noop); 3209 EventRuler.on(el, "keyup", $.noop); 3210 EventRuler.on(el, "input", EventHandlers.inputFallBackEvent); 3211 EventRuler.on(el, "beforeinput", $.noop); //https://github.com/w3c/input-events - to implement 3212 } 3213 EventRuler.on(el, "setvalue", EventHandlers.setValueEvent); 3214 3215 //apply mask 3216 undoValue = getBufferTemplate().join(""); //initialize the buffer and getmasklength 3217 if (el.inputmask._valueGet(true) !== "" || opts.clearMaskOnLostFocus === false || document.activeElement === el) { 3218 var initialValue = $.isFunction(opts.onBeforeMask) ? (opts.onBeforeMask.call(inputmask, el.inputmask._valueGet(true), opts) || el.inputmask._valueGet(true)) : el.inputmask._valueGet(true); 3219 if (initialValue !== "") checkVal(el, true, false, isRTL ? initialValue.split("").reverse() : initialValue.split("")); 3220 var buffer = getBuffer().slice(); 3221 undoValue = buffer.join(""); 3222 // Wrap document.activeElement in a try/catch block since IE9 throw "Unspecified error" if document.activeElement is undefined when we are in an IFrame. 3223 if (isComplete(buffer) === false) { 3224 if (opts.clearIncomplete) { 3225 resetMaskSet(); 3226 } 3227 } 3228 if (opts.clearMaskOnLostFocus && document.activeElement !== el) { 3229 if (getLastValidPosition() === -1) { 3230 buffer = []; 3231 } else { 3232 clearOptionalTail(buffer); 3233 } 3234 } 3235 writeBuffer(el, buffer); 3236 if (document.activeElement === el) { //position the caret when in focus 3237 caret(el, seekNext(getLastValidPosition())); 3238 } 3239 } 3240 } 3241 } 3242 3243 //action object 3244 var valueBuffer; 3245 if (actionObj !== undefined) { 3246 switch (actionObj.action) { 3247 case "isComplete": 3248 el = actionObj.el; 3249 return isComplete(getBuffer()); 3250 case "unmaskedvalue": 3251 if (el === undefined || actionObj.value !== undefined) { 3252 valueBuffer = actionObj.value; 3253 valueBuffer = ($.isFunction(opts.onBeforeMask) ? (opts.onBeforeMask.call(inputmask, valueBuffer, opts) || valueBuffer) : valueBuffer).split(""); 3254 checkVal(undefined, false, false, isRTL ? valueBuffer.reverse() : valueBuffer); 3255 if ($.isFunction(opts.onBeforeWrite)) opts.onBeforeWrite.call(inputmask, undefined, getBuffer(), 0, opts); 3256 } 3257 return unmaskedvalue(el); 3258 case "mask": 3259 mask(el); 3260 break; 3261 case "format": 3262 valueBuffer = ($.isFunction(opts.onBeforeMask) ? (opts.onBeforeMask.call(inputmask, actionObj.value, opts) || actionObj.value) : actionObj.value).split(""); 3263 checkVal(undefined, true, false, isRTL ? valueBuffer.reverse() : valueBuffer); 3264 if (actionObj.metadata) { 3265 return { 3266 value: isRTL ? getBuffer().slice().reverse().join("") : getBuffer().join(""), 3267 metadata: maskScope.call(this, { 3268 "action": "getmetadata" 3269 }, maskset, opts) 3270 }; 3271 } 3272 3273 return isRTL ? getBuffer().slice().reverse().join("") : getBuffer().join(""); 3274 case "isValid": 3275 if (actionObj.value) { 3276 valueBuffer = actionObj.value.split(""); 3277 checkVal(undefined, true, true, isRTL ? valueBuffer.reverse() : valueBuffer); 3278 } else { 3279 actionObj.value = getBuffer().join(""); 3280 } 3281 var buffer = getBuffer(); 3282 var rl = determineLastRequiredPosition(), 3283 lmib = buffer.length - 1; 3284 for (; lmib > rl; lmib--) { 3285 if (isMask(lmib)) break; 3286 } 3287 buffer.splice(rl, lmib + 1 - rl); 3288 3289 return isComplete(buffer) && actionObj.value === getBuffer().join(""); 3290 case "getemptymask": 3291 return getBufferTemplate().join(""); 3292 case "remove": 3293 if (el && el.inputmask) { 3294 $el = $(el); 3295 //writeout the value 3296 el.inputmask._valueSet(opts.autoUnmask ? unmaskedvalue(el) : el.inputmask._valueGet(true)); 3297 //unbind all events 3298 EventRuler.off(el); 3299 //remove colormask if used 3300 if (el.inputmask.colorMask) { 3301 colorMask = el.inputmask.colorMask; 3302 colorMask.removeChild(el); 3303 colorMask.parentNode.insertBefore(el, colorMask); 3304 colorMask.parentNode.removeChild(colorMask); 3305 } 3306 //restore the value property 3307 var valueProperty; 3308 if (Object.getOwnPropertyDescriptor && Ob
3308ject.getPrototypeOf) { 3309 valueProperty = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el), "value"); 3310 if (valueProperty) { 3311 if (el.inputmask.__valueGet) { 3312 Object.defineProperty(el, "value", { 3313 get: el.inputmask.__valueGet, 3314 set: el.inputmask.__valueSet, 3315 configurable: true 3316 }); 3317 } 3318 } 3319 } else if (document.__lookupGetter__ && el.__lookupGetter__("value")) { 3320 if (el.inputmask.__valueGet) { 3321 el.__defineGetter__("value", el.inputmask.__valueGet); 3322 el.__defineSetter__("value", el.inputmask.__valueSet); 3323 } 3324 } 3325 //clear data 3326 el.inputmask = undefined; 3327 } 3328 return el; 3329 break; 3330 case "getmetadata": 3331 if ($.isArray(maskset.metadata)) { 3332 var maskTarget = getMaskTemplate(true, 0, false).join(""); 3333 $.each(maskset.metadata, function (ndx, mtdt) { 3334 if (mtdt.mask === maskTarget) { 3335 maskTarget = mtdt; 3336 return false; 3337 } 3338 }); 3339 return maskTarget; 3340 } 3341 3342 return maskset.metadata; 3343 } 3344 } 3345 } 3346 3347 //make inputmask available 3348 return Inputmask; 3349}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.