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