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