1/** 2* @license Input Mask plugin for jquery 3* http://github.com/RobinHerbots/jquery.inputmask 4* Copyright (c) 2010 - 2013 Robin Herbots 5* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php) 6* Version: 0.0.0 7*/ 8 9(function ($) { 10 if ($.fn.inputmask == undefined) { 11 $.inputmask = { 12 //options default 13 defaults: { 14 placeholder: "_", 15 optionalmarker: { 16 start: "[", 17 end: "]" 18 }, 19 escapeChar: "\\", 20 mask: null, 21 oncomplete: $.noop, //executes when the mask is complete 22 onincomplete: $.noop, //executes when the mask is incomplete and focus is lost 23 oncleared: $.noop, //executes when the mask is cleared 24 repeat: 0, //repetitions of the mask 25 greedy: true, //true: allocated buffer for the mask and repetitions - false: allocate only if needed 26 autoUnmask: false, //automatically unmask when retrieving the value with $.fn.val or value if the browser supports __lookupGetter__ or getOwnPropertyDescriptor 27 clearMaskOnLostFocus: true, 28 insertMode: true, //insert the input or overwrite the input 29 clearIncomplete: false, //clear the incomplete input on blur 30 aliases: {}, //aliases definitions => see jquery.inputmask.extensions.js 31 onKeyUp: $.noop, //override to implement autocomplete on certain keys for example 32 onKeyDown: $.noop, //override to implement autocomplete on certain keys for example 33 showMaskOnFocus: true, //show the mask-placeholder when the input has focus 34 showMaskOnHover: true, //show the mask-placeholder when hovering the empty input 35 onKeyValidation: $.noop, //executes on every key-press with the result of isValid 36 skipOptionalPartCharacter: " ", //a character which can be used to skip an optional part of a mask 37 //numeric basic properties 38 numericInput: false, //numericInput input direction style (input shifts to the left while holding the caret position) 39 radixPoint: "", //".", // | "," 40 //numeric basic properties 41 definitions: { 42 '9': { 43 validator: "[0-9]", 44 cardinality: 1 45 }, 46 'a': { 47 validator: "[A-Za-z\u0410-\u044F\u0401\u0451]", 48 cardinality: 1 49 }, 50 '*': { 51 validator: "[A-Za-z\u0410-\u044F\u0401\u04510-9]", 52 cardinality: 1 53 } 54 }, 55 keyCode: { 56 ALT: 18, BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, COMMAND: 91, COMMAND_LEFT: 91, COMMAND_RIGHT: 93, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, MENU: 93, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, 57 NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38, WINDOWS: 91 58 }, 59 //specify keycodes which should not be considered in the keypress event, otherwise the preventDefault will stop their default behavior especially in FF 60 ignorables: [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], 61 getMaskLength: function (buffer, greedy, repeat, currentBuffer, opts) { 62 var calculatedLength = buffer.length; 63 if (!greedy && repeat > 1) { 64 calculatedLength += (buffer.length * (repeat - 1)); 65 } 66 return calculatedLength; 67 } 68 }, 69 val: $.fn.val, //store the original jquery val function 70 escapeRegex: function (str) { 71 var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\']; 72 return str.replace(new RegExp('(\\' + specials.join('|\\') + ')', 'gim'), '\\$1'); 73 } 74 }; 75 76 $.fn.inputmask = function (fn, options) { 77 var opts = $.extend(true, {}, $.inputmask.defaults, options); 78 var pasteEvent = isInputEventSupported('paste') ? 'paste' : 'input'; 79 80 var iphone = navigator.userAgent.match(/iphone/i) != null; 81 var android = navigator.userAgent.match(/android.*safari.*/i) != null, 82 android534; 83 if (android) { 84 var browser = navigator.userAgent.match(/safari.*/i); 85 var version = parseInt(new RegExp(/[0-9]+/).exec(browser)); 86 android = (version <= 533); 87 android534 = (533 < version <= 534); 88 } 89 var caretposCorrection = null; 90 var masksets, 91 activeMasksetIndex = 0; 92 93 if (typeof fn == "string") { 94 switch (fn) { 95 case "mask": 96 //resolve possible aliases given by options 97 resolveAlias(opts.alias, options); 98 masksets = generateMaskSets(); 99 100 return this.each(function () { 101 mask(this); 102 }); 103 break; 104 case "unmaskedvalue": 105 masksets = this.data('inputmask')['masksets']; 106 activeMasksetIndex = this.data('inputmask')['activeMasksetIndex']; 107 opts.definitions = this.data('inputmask')['definitions']; 108 return unmaskedvalue(this); 109 break; 110 case "remove": 111 return this.each(function () { 112 var $input = $(this), input = this; 113 setTimeout(function () { 114 if ($input.data('inputmask')) { 115 masksets = $input.data('inputmask')['masksets']; 116 activeMasksetIndex = $input.data('inputmask')['activeMasksetIndex']; 117 opts.definitions = $input.data('inputmask')['definitions']; 118 //writeout the unmaskedvalue 119 input._valueSet(unmaskedvalue($input, true)); 120 //clear data 121 $input.removeData('inputmask'); 122 //unbind all events 123 $input.unbind(".inputmask"); 124 $input.removeClass('focus.inputmask'); 125 //restore the value property 126 var valueProperty; 127 if (Object.getOwnPropertyDescriptor) 128 valueProperty = Object.getOwnPropertyDescriptor(input, "value"); 129 if (valueProperty && valueProperty.get) { 130 if (input._valueGet) { 131 Object.defineProperty(input, "value", { 132 get: input._valueGet, 133 set: input._valueSet 134 }); 135 } 136 } else if (document.__lookupGetter__ && input.__lookupGetter__("value")) { 137 if (input._valueGet) { 138 input.__defineGetter__("value", input._valueGet); 139 input.__defineSetter__("value", input._valueSet); 140 } 141 } 142 delete input._valueGet; 143 delete input._valueSet; 144 } 145 }, 0); 146 }); 147 break; 148 case "getemptymask": //return the default (empty) mask value, usefull for setting the default value in validation 149 if (this.data('inputmask')) { 150 masksets = this.data('inputmask')['masksets']; 151 activeMasksetIndex = this.data('inputmask')['activeMasksetIndex']; 152 return masksets[activeMasksetIndex]['_buffer'].join(''); 153 } 154 else return ""; 155 case "hasMaskedValue": //check wheter the returned value is masked or not;
155 currently only works reliable when using jquery.val fn to retrieve the value 156 return this.data('inputmask') ? !this.data('inputmask')['autoUnmask'] : false; 157 case "isComplete": 158 masksets = this.data('inputmask')['masksets']; 159 activeMasksetIndex = this.data('inputmask')['activeMasksetIndex']; 160 opts.definitions = this.data('inputmask')['definitions']; 161 return isComplete(this[0].split('')); 162 default: 163 //check if the fn is an alias 164 if (!resolveAlias(fn, options)) { 165 //maybe fn is a mask so we try 166 //set mask 167 opts.mask = fn; 168 } 169 masksets = generateMaskSets(); 170 171 return this.each(function () { 172 mask(this); 173 }); 174 175 break; 176 } 177 } else if (typeof fn == "object") { 178 opts = $.extend(true, {}, $.inputmask.defaults, fn); 179 180 resolveAlias(opts.alias, fn); //resolve aliases 181 masksets = generateMaskSets(); 182 183 return this.each(function () { 184 mask(this); 185 }); 186 } else if (fn == undefined) { 187 //look for data-inputmask atribute - the attribute should only contain optipns 188 return this.each(function () { 189 var attrOptions = $(this).attr("data-inputmask"); 190 if (attrOptions && attrOptions != "") { 191 try { 192 attrOptions = attrOptions.replace(new RegExp("'", "g"), '"'); 193 var options = $.parseJSON("{" + attrOptions + "}"); 194 opts = $.extend(true, {}, $.inputmask.defaults, options); 195 resolveAlias(opts.alias, options); 196 opts.alias = undefined; 197 $(this).inputmask(opts); 198 } catch (ex) { } //need a more relax parseJSON 199 } 200 }); 201 } 202 203 //helper functions 204 function isInputEventSupported(eventName) { 205 var el = document.createElement('input'), 206 eventName = 'on' + eventName, 207 isSupported = (eventName in el); 208 if (!isSupported) { 209 el.setAttribute(eventName, 'return;'); 210 isSupported = typeof el[eventName] == 'function'; 211 } 212 el = null; 213 return isSupported; 214 } 215 216 function resolveAlias(aliasStr, options) { 217 var aliasDefinition = opts.aliases[aliasStr]; 218 if (aliasDefinition) { 219 if (aliasDefinition.alias) resolveAlias(aliasDefinition.alias); //alias is another alias 220 $.extend(true, opts, aliasDefinition); //merge alias definition in the options 221 $.extend(true, opts, options); //reapply extra given options 222 return true; 223 } 224 return false; 225 } 226 227 function getMaskTemplate(mask) { 228 var escaped = false, outCount = 0, greedy = opts.greedy, repeat = opts.repeat; 229 if (mask.length == 1 && greedy == false) { opts.placeholder = ""; } //hide placeholder with single non-greedy mask 230 var singleMask = $.map(mask.split(""), function (element, index) { 231 var outElem = []; 232 if (element == opts.escapeChar) { 233 escaped = true; 234 } 235 else if ((element != opts.optionalmarker.start && element != opts.optionalmarker.end) || escaped) { 236 var maskdef = opts.definitions[element]; 237 if (maskdef && !escaped) { 238 for (var i = 0; i < maskdef.cardinality; i++) { 239 outElem.push(getPlaceHolder(outCount + i)); 240 } 241 } else { 242 outElem.push(element); 243 escaped = false;
244 } 245 outCount += outElem.length; 246 return outElem; 247 } 248 }); 249 250 //allocate repetitions 251 var repeatedMask = singleMask.slice(); 252 for (var i = 1; i < repeat && greedy; i++) { 253 repeatedMask = repeatedMask.concat(singleMask.slice()); 254 } 255 256 return { "mask": repeatedMask, "repeat": repeat, "greedy": greedy }; 257 } 258 259 //test definition => {fn: RegExp/function, cardinality: int, optionality: bool, newBlockMarker: bool, offset: int, casing: null/upper/lower, def: definitionSymbol} 260 function getTestingChain(mask) { 261 var isOptional = false, escaped = false; 262 var newBlockMarker = false; //indicates wheter the begin/ending of a block should be indicated 263 264 return $.map(mask.split(""), function (element, index) { 265 var outElem = []; 266 267 if (element == opts.escapeChar) { 268 escaped = true; 269 } else if (element == opts.optionalmarker.start && !escaped) { 270 isOptional = true; 271 newBlockMarker = true; 272 } 273 else if (element == opts.optionalmarker.end && !escaped) { 274 isOptional = false;
275 newBlockMarker = true; 276 } 277 else { 278 var maskdef = opts.definitions[element]; 279 if (maskdef && !escaped) { 280 var prevalidators = maskdef["prevalidator"], prevalidatorsL = prevalidators ? prevalidators.length : 0; 281 for (var i = 1; i < maskdef.cardinality; i++) { 282 var prevalidator = prevalidatorsL >= i ? prevalidators[i - 1] : [], validator = prevalidator["validator"], cardinality = prevalidator["cardinality"]; 283 outElem.push({ fn: validator ? typeof validator == 'string' ? new RegExp(validator) : new function () { this.test = validator; } : new RegExp("."), cardinality: cardinality ? cardinality : 1, optionality: isOptional, newBlockMarker: isOptional == true ? newBlockMarker : false, offset: 0, casing: maskdef["casing"], def: element }); 284 if (isOptional == true) //reset newBlockMarker 285 newBlockMarker = false;
286 } 287 outElem.push({ fn: maskdef.validator ? typeof maskdef.validator == 'string' ? new RegExp(maskdef.validator) : new function () { this.test = maskdef.validator; } : new RegExp("."), cardinality: maskdef.cardinality, optionality: isOptional, newBlockMarker: newBlockMarker, offset: 0, casing: maskdef["casing"], def: element }); 288 } else { 289 outElem.push({ fn: null, cardinality: 0, optionality: isOptional, newBlockMarker: newBlockMarker, offset: 0, casing: null, def: element }); 290 escaped = false; 291 } 292 //reset newBlockMarker 293 newBlockMarker = false; 294 return outElem; 295 } 296 }); 297 } 298 299 function generateMaskSets() { //TODO improve generate masksets 300 var ms = []; 301 function markOptional(maskPart) { //needed for the clearOptionalTail functionality 302 return opts.optionalmarker.start + maskPart + opts.optionalmarker.end; 303 } 304 function generateMask(maskPrefix, maskPart) { 305 var maskParts = maskPart.split(opts.optionalmarker.end, 2); 306 var newMask, maskTemplate; 307 308 309 var masks = maskParts[0].split(opts.optionalmarker.start); 310 if (masks.length > 1) { 311 newMask = maskPrefix + masks[0] + markOptional(masks[1]) + (maskParts.length > 1 ? maskParts[1] : ""); 312 maskTemplate = getMaskTemplate(newMask); 313 ms.push({ 314 "_buffer": maskTemplate["mask"], 315 "tests": getTestingChain(newMask), 316 "lastValidPosition": 0, 317 "greedy": maskTemplate["greedy"], 318 "repeat": maskTemplate["repeat"] 319 }); 320 newMask = maskPrefix + masks[0] + (maskParts.length > 1 ? maskParts[1] : ""); 321 maskTemplate = getMaskTemplate(newMask); 322 ms.push({ 323 "_buffer": maskTemplate["mask"], 324 "tests": getTestingChain(newMask), 325 "lastValidPosition": 0, 326 "greedy": maskTemplate["greedy"], 327 "repeat": maskTemplate["repeat"] 328 }); 329 if (maskParts.length > 1 && maskParts[1].split(opts.optionalmarker.start).length > 1) { 330 generateMask(maskPrefix + masks[0] + markOptional(masks[1]), maskParts[1]); 331 generateMask(maskPrefix + masks[0], maskParts[1]); 332 } 333 } 334 else { 335 newMask = maskPrefix + maskParts; 336 maskTemplate = getMaskTemplate(newMask); 337 ms.push({ 338 "_buffer": maskTemplate["mask"], 339 "tests": getTestingChain(newMask), 340 "lastValidPosition": 0, 341 "greedy": maskTemplate["greedy"], 342 "repeat": maskTemplate["repeat"] 343 }); 344 } 345 346 } 347 348 generateMask("", opts.mask.toString()); 349 return ms; 350 } 351 352 //maskset helperfunctions 353 function getActiveMaskSet() { 354 return masksets[activeMasksetIndex]; 355 } 356 357 function getActiveTests() { 358 return getActiveMaskSet()['tests']; 359 } 360 361 function getActiveBuffer() { 362 return getActiveMaskSet()['_buffer']; 363 } 364 365 function isValid(pos, c, buffer, strict, isRTL) { //strict true ~ no correction or autofill 366 function _isValid(position, activeMaskset) { 367 var testPos = determineTestPosition(position), loopend = c ? 1 : 0, chrs = ''; 368 for (var i = activeMaskset['tests'][testPos].cardinality; i > loopend; i--) { 369 chrs += getBufferElement(buffer, testPos - (i - 1)); 370 } 371 372 if (c) { 373 chrs += c; 374 } 375 376 //return is false or a json object => { pos: ??, c: ??} or true 377 return activeMaskset['tests'][testPos].fn != null ? activeMaskset['tests'][testPos].fn.test(chrs, buffer, position, strict, opts) : false;
378 } 379 380 if (strict) return _isValid(pos, getActiveMaskSet()); //only check validity in current mask when validating strict 381 382 var results = [], result = false, currentActiveMasksetIndex = activeMasksetIndex; 383 $.each(masksets, function (index, value) { 384 var activeMaskset = this; 385 activeMasksetIndex = index; 386 387 var maskPos = pos; 388 if (currentActiveMasksetIndex != activeMasksetIndex && !isMask(pos)) { 389 if (c == activeMaskset['_buffer'][maskPos] || c == opts.skipOptionalPartCharacter) { //match non-mask item 390 results[index] = { "refresh": true }; //new command hack only rewrite buffer 391 activeMaskset['lastValidPosition'] = maskPos; 392 return false; 393 } 394 395 maskPos = isRTL ? seekPrevious(buffer, pos) : seekNext(buffer, pos); 396 } 397 if ((isRTL || opts.numericInput) ? activeMaskset['lastValidPosition'] <= opts.numericInput ? getMaskLength(buffer) : seekNext(buffer, maskPos) : activeMaskset['lastValidPosition'] >= seekPrevious(buffer, maskPos)) { 398 if (maskPos >= 0 && maskPos < getMaskLength(buffer)) { 399 results[index] = _isValid(maskPos, activeMaskset); 400 if (results[index] !== false) { 401 if (results[index] === true) { 402 results[index] = { "pos": maskPos }; //always take a possible corrected maskposition into account 403 } 404 activeMaskset['lastValidPosition'] = results[index].pos || maskPos; //set new position from isValid 405 } else activeMaskset['lastValidPosition'] = isRTL ? seekNext(buffer, pos) : seekPrevious(buffer, pos); //autocorrect validposition from backspace etc 406 } 407 } 408 }); 409 activeMasksetIndex = currentActiveMasksetIndex; //reset activeMasksetIndex 410 determineActiveMasksetIndex(buffer, pos, currentActiveMasksetIndex, isRTL); 411 result = results[activeMasksetIndex] || result; 412 setTimeout(function () { opts.onKeyValidation.call(this, result, opts); }, 0); //extra stuff to execute on keydown 413 return result; 414 } 415 416 function determineActiveMasksetIndex(buffer, pos, currentActiveMasksetIndex, isRTL) { 417 $.each(masksets, function (index, value) { 418 var activeMaskset = this; 419 if ((isRTL || opts.numericInput) ? activeMaskset['lastValidPosition'] <= pos : activeMaskset['lastValidPosition'] >= pos) { 420 activeMasksetIndex = index; 421 //reset to correct masktemplate 422 if (activeMasksetIndex != currentActiveMasksetIndex) { 423 var abl = getMaskLength(buffer), bufTemplate = getActiveBuffer(); 424 if (isRTL || opts.numericInput) { 425 buffer.reverse(); 426 bufTemplate.reverse(); 427 } 428 buffer.length = pos; //clearout beyond the current 429 for (var i = pos; i < abl; i++) { 430 var testPos = determineTestPosition(i); 431 setBufferElement(buffer, i, getBufferElement(bufTemplate, testPos)); 432 } 433 if (isRTL) { 434 buffer.reverse(); 435 } 436 } 437 return false; //breaks 438 } 439 }); 440 } 441 442 function isMask(pos) { 443 var testPos = determineTestPosition(pos); 444 var test = getActiveTests()[testPos]; 445 446 return test != undefined ? test.fn : false;
447 } 448 449 function determineTestPosition(pos) { 450 return pos % getActiveTests().length; 451 } 452 453 function getPlaceHolder(pos) { 454 return opts.placeholder.charAt(pos % opts.placeholder.length); 455 } 456 457 function getMaskLength(currentBuffer) { 458 return opts.getMaskLength(getActiveBuffer(), getActiveMaskSet()['greedy'], getActiveMaskSet()['repeat'], currentBuffer, opts); 459 } 460 461 //pos: from position 462 function seekNext(buffer, pos) { 463 var maskL = getMaskLength(buffer); 464 if (pos >= maskL) return maskL; 465 var position = pos; 466 while (++position < maskL && !isMask(position)) { }; 467 return position; 468 } 469 //pos: from position 470 function seekPrevious(buffer, pos) { 471 var position = pos; 472 if (position <= 0) return 0; 473 474 while (--position > 0 && !isMask(position)) { }; 475 return position; 476 } 477 478 function setBufferElement(buffer, position, element) { 479 //position = prepareBuffer(buffer, position); 480 481 var test = getActiveTests()[determineTestPosition(position)]; 482 var elem = element; 483 if (elem != undefined) { 484 switch (test.casing) { 485 case "upper": 486 elem = element.toUpperCase(); 487 break; 488 case "lower": 489 elem = element.toLowerCase(); 490 break; 491 } 492 } 493 494 buffer[position] = elem; 495 } 496 function getBufferElement(buffer, position, autoPrepare) { 497 if (autoPrepare) position = prepareBuffer(buffer, position); 498 return buffer[position]; 499 } 500 501 //needed to handle the non-greedy mask repetitions 502 function prepareBuffer(buffer, position, isRTL) { 503 var j; 504 if (isRTL) { 505 while (position < 0 && buffer.length < getMaskLength(buffer)) { 506 j = getActiveBuffer().length - 1; 507 position = getActiveBuffer().length; 508 while (getActiveBuffer()[j] !== undefined) { 509 buffer.unshift(getActiveBuffer()[j--]); 510 } 511 } 512 } else { 513 while (buffer[position] == undefined && buffer.length < getMaskLength(buffer)) { 514 j = 0; 515 while (getActiveBuffer()[j] !== undefined) { //add a new buffer 516 buffer.push(getActiveBuffer()[j++]); 517 } 518 } 519 } 520 521 return position; 522 } 523 524 function writeBuffer(input, buffer, caretPos) { 525 input._valueSet(buffer.join('')); 526 if (caretPos != undefined) { 527 if (android) { 528 setTimeout(function () { 529 caret(input, caretPos); 530 }, 100); 531 } 532 else caret(input, caretPos); 533 } 534 }; 535 function clearBuffer(buffer, start, end) { 536 for (var i = start, maskL = getMaskLength(buffer) ; i < end && i < maskL; i++) { 537 setBufferElement(buffer, i, getBufferElement(getActiveBuffer().slice(), i)); 538 } 539 }; 540 541 function setReTargetPlaceHolder(buffer, pos) { 542 var testPos = determineTestPosition(pos); 543 setBufferElement(buffer, pos, getBufferElement(getActiveBuffer(), testPos)); 544 } 545 546 function checkVal(input, buffer, clearInvalid, skipRadixHandling) { 547 var isRTL = $(input).data('inputmask')['isRTL'], 548 inputValue = truncateInput(input._valueGet(), isRTL).split(''); 549 550 var maskL = getMaskLength(buffer); 551 if (isRTL) { //align inputValue for RTL/numeric input 552 var inputValueRev = inputValue.reverse(); inputValueRev.length = maskL; 553 554 for (var i = 0; i < maskL; i++) { 555 var targetPosition = determineTestPosition(maskL - (i + 1)); 556 if (getActiveTests()[targetPosition].fn == null && inputValueRev[i] != getBufferElement(getActiveBuffer(), targetPosition)) { 557 inputValueRev.splice(i, 0, getBufferElement(getActiveBuffer(), targetPosition)); 558 inputValueRev.length = maskL; 559 } else { 560 inputValueRev[i] = inputValueRev[i] || getBufferElement(getActiveBuffer(), targetPosition); 561 } 562 } 563 inputValue = inputValueRev.reverse(); 564 } 565 clearBuffer(buffer, 0, buffer.length); 566 buffer.length = getActiveBuffer().length; 567 var lastMatch = -1, checkPosition = -1, np, ivl = inputValue.length, rtlMatch = ivl == 0 ? maskL : -1; 568 for (var i = 0; i < ivl; i++) { 569 for (var pos = checkPosition + 1; pos < maskL; pos++) { 570 if (isMask(pos)) { 571 var c = inputValue[i]; 572 if ((np = isValid(pos, c, buffer, !clearInvalid, isRTL)) !== false) { 573 if (np !== true) { 574 pos = np.pos != undefined ? np.pos : pos; //set new position from isValid 575 c = np.c != undefined ? np.c : c; //set new char from isValid 576 } 577 setBufferElement(buffer, pos, c); 578 lastMatch = checkPosition = pos; 579 } else { 580 setReTargetPlaceHolder(buffer, pos); 581 if (c == getPlaceHolder(pos)) { 582 checkPosition = pos; 583 rtlMatch = pos; 584 } 585 } 586 break; 587 } else { //nonmask 588 setReTargetPlaceHolder(buffer, pos); 589 if (lastMatch == checkPosition) //once outsync the nonmask cannot be the lastmatch 590 lastMatch = pos; 591 checkPosition = pos; 592 if (inputValue[i] == getBufferElement(buffer, pos)) 593 break; 594 } 595 } 596 } 597 //Truncate buffer when using non-greedy masks 598 if (getActiveMaskSet()['greedy'] == false) { 599 var newBuffer = truncateInput(buffer.join(''), isRTL).split(''); 600 while (buffer.length != newBuffer.length) { //map changes into the original buffer 601 isRTL ? buffer.shift() : buffer.pop(); 602 } 603 } 604 605 if (clearInvalid) { 606 writeBuffer(input, buffer); 607 } 608 return isRTL ? (opts.numericInput ? (opts.radixPoint != "" && $.inArray(opts.radixPoint, buffer) != -1 && skipRadixHandling !== true ? $.inArray(opts.radixPoint, buffer) : seekNext(buffer, maskL)) : seekNext(buffer, rtlMatch)) : seekNext(buffer, lastMatch); 609 } 610 611 function escapeRegex(str) { 612 return $.inputmask.escapeRegex.call(this, str); 613 } 614 615 function truncateInput(inputValue, rtl) { 616 return rtl ? inputValue.replace(new RegExp("^(" + escapeRegex(getActiveBuffer().join('')) + ")*"), "") : inputValue.replace(new RegExp("(" + escapeRegex(getActiveBuffer().join('')) + ")*$"), ""); 617 } 618 619 function clearOptionalTail(input, buffer) { 620 checkVal(input, buffer, false); 621 var tmpBuffer = buffer.slice(), testPos, pos; 622 if ($(input).data('inputmask')['isRTL']) { 623 for (var pos = 0; pos <= tmpBuffer.length - 1; pos++) { 624 var testPos = determineTestPosition(pos); 625 if (getActiveTests()[testPos].optionality) { 626 if (!isMask(pos) || !isValid(pos, buffer[pos], buffer, true)) 627 tmpBuffer.splice(0, 1); 628 else break; 629 } else break; 630 } 631 } else { 632 for (var pos = tmpBuffer.length - 1; pos >= 0; pos--) { 633 var testPos = determineTestPosition(pos); 634 if (getActiveTests()[testPos].optionality) { 635 if (!isMask(pos) || !isValid(pos, buffer[pos], buffer, true)) 636 tmpBuffer.pop(); 637 else break; 638 } else break; 639 } 640 } 641 writeBuffer(input, tmpBuffer); 642 } 643 644 //functionality fn 645 function unmaskedvalue($input, skipDatepickerCheck) { 646 var input = $input[0]; 647 if (getActiveTests() && (skipDatepickerCheck === true || !$input.hasClass('hasDatepicker'))) { 648 var buffer = getActiveBuffer().slice(); 649 checkVal(input, buffer); 650 return $.map(buffer, function (element, index) { 651 return isMask(index) && isValid(index, element, buffer, true) ? element : null; 652 }).join(''); 653 } 654 else { 655 return input._valueGet(); 656 } 657 } 658 659 function caret(input, begin, end) { 660 var npt = input.jquery && input.length > 0 ? input[0] : input; 661 if (typeof begin == 'number') { 662 if (!$(input).is(':visible')) { 663 return; 664 } 665 end = (typeof end == 'number') ? end : begin; 666 if (opts.insertMode == false && begin == end) end++; //set visualization for insert/overwrite mode 667 if (npt.setSelectionRange) { 668 if (end == begin) { 669 npt.focus(); 670 npt.setSelectionRange(begin, end); 671 } else { 672 npt.select(); 673 npt.selectionStart = begin; 674 npt.selectionEnd = android534 ? begin : end; 675 } 676 } else if (npt.createTextRange) { 677 var range = npt.createTextRange(); 678 range.collapse(true); 679 range.moveEnd('character', end); 680 range.moveStart('character', begin); 681 range.select(); 682 } 683 npt.focus(); 684 if (android && end != npt.selectionEnd) caretposCorrection = { begin: begin, end: end }; 685 } else { 686 if (!$(input).is(':visible')) { 687 return { begin: 0, end: 0 }; 688 } 689 var caretpos = android ? caretposCorrection : null, caretposCorrection = null; 690 if (caretpos == null) { 691 if (npt.setSelectionRange) { 692 begin = npt.selectionStart;
693 end = npt.selectionEnd; 694 } else if (document.selection && document.selection.createRange) { 695 var range = document.selection.createRange(); 696 begin = 0 - range.duplicate().moveStart('character', -100000); 697 end = begin + range.text.length; 698 } 699 caretpos = { begin: begin, end: end }; 700 } 701 return caretpos; 702 } 703 }; 704 705 function isComplete(buffer) { 706 var complete = false; 707 currentActiveMasksetIndex = activeMasksetIndex, highestValidPosition = 0; 708 $.each(masksets, function (ndx, ms) { 709 activeMasksetIndex = ndx; 710 var aml = getMaskLength(buffer); 711 if (ms["lastValidPosition"] >= highestValidPosition && ms["lastValidPosition"] == (aml - 1)) { 712 var msComplete = true; 713 for (var i = 0; i < aml; i++) { 714 var mask = isMask(i); 715 if ((mask && buffer[i] == getPlaceHolder(i)) || (!mask && buffer[i] != getActiveBuffer()[i])) { 716 msComplete = false; 717 break; 718 } 719 } 720 complete = complete || msComplete; 721 if (complete) //break loop 722 return false; 723 } 724 highestValidPosition = ms["lastValidPosition"]; 725 }); 726 activeMasksetIndex = currentActiveMasksetIndex; //reset activeMaskset 727 return complete; 728 } 729 730 function mask(el) { 731 var $input = $(el); 732 if (!$input.is(":input")) return; 733 734 var buffer = getActiveBuffer().slice(); 735 736 //correct greedy setting if needed 737 getActiveMaskSet()['greedy'] = getActiveMaskSet()['greedy'] ? getActiveMaskSet()['greedy'] : getActiveMaskSet()['repeat'] == 0; 738 739 //handle maxlength attribute 740 var maxLength = $input.prop('maxLength'); 741 if (getMaskLength(buffer) > maxLength && maxLength > -1) { //FF sets no defined max length to -1 742 if (maxLength < getActiveBuffer().length) getActiveBuffer().length = maxLength; 743 if (getActiveMaskSet()['greedy'] == false) { 744 getActiveMaskSet()['repeat'] = Math.round(maxLength / getActiveBuffer().length); 745 } 746 $input.prop('maxLength', getMaskLength(buffer) * 2); 747 } 748 749 //store tests & original buffer in the input element - used to get the unmasked value 750 $input.data('inputmask', { 751 'masksets': masksets, 752 'activeMasksetIndex': activeMasksetIndex, 753 'autoUnmask': opts.autoUnmask, 754 'definitions': opts.definitions, 755 'isRTL': false 756 }); 757 758 patchValueProperty(el); 759 760 //init vars 761 var buffer = getActiveBuffer().slice(), 762 undoBuffer = el._valueGet(), 763 764 skipKeyPressEvent = false, //Safari 5.1.x - modal dialog fires keypress twice workaround 765 ignorable = false, 766 lastPosition = -1, 767 firstMaskPos = seekNext(buffer, -1), 768 lastMaskPos = seekPrevious(buffer, getMaskLength(buffer)), 769 isRTL = false; 770 if (el.dir == "rtl" || opts.numericInput) { 771 el.dir = "ltr" 772 $input.css("text-align", "right"); 773 $input.removeAttr("dir"); 774 var inputData = $input.data('inputmask'); 775 inputData['isRTL'] = true; 776 $input.data('inputmask', inputData); 777 isRTL = true; 778 } 779 780 //unbind all events - to make sure that no other mask will interfere when re-masking 781 $input.unbind(".inputmask"); 782 $input.removeClass('focus.inputmask'); 783 //bind events 784 $input.bind("mouseenter.inputmask", function () { 785 var $input = $(this), input = this; 786 if (!$input.hasClass('focus.inputmask') && opts.showMaskOnHover) { 787 var nptL = input._valueGet().length; 788 if (nptL < buffer.length) { 789 if (nptL == 0) 790 buffer = getActiveBuffer().slice(); 791 writeBuffer(input, buffer); 792 } 793 } 794 }).bind("blur.inputmask", function () { 795 var $input = $(this), input = this, nptValue = input._valueGet(); 796 $input.removeClass('focus.inputmask'); 797 if (nptValue != undoBuffer) { 798 $input.change(); 799 } 800 if (opts.clearMaskOnLostFocus && nptValue != '') { 801 if (nptValue == getActiveBuffer().join('')) 802 input._valueSet(''); 803 else { //clearout optional tail of the mask 804 clearOptionalTail(input, buffer); 805 } 806 } 807 if (!isComplete(buffer)) { 808 $input.trigger("incomplete"); 809 if (opts.clearIncomplete) { 810 if (opts.clearMaskOnLostFocus) 811 input._valueSet(''); 812 else { 813 buffer = getActiveBuffer().slice(); 814 writeBuffer(input, buffer); 815 } 816 } 817 } 818 }).bind("focus.inputmask", function () { 819 var $input = $(this), input = this, nptValue = input._valueGet(); 820 if (opts.showMaskOnFocus && !$input.hasClass('focus.inputmask') && (!opts.showMaskOnHover || (opts.showMaskOnHover && nptValue == ''))) { 821 var nptL = nptValue.length; 822 if (nptL < buffer.length) { 823 if (nptL == 0) 824 buffer = getActiveBuffer().slice(); 825 caret(input, checkVal(input, buffer, true)); 826 } 827 } 828 $input.addClass('focus.inputmask'); 829 undoBuffer = input._valueGet(); 830 }).bind("mouseleave.inputmask", function () { 831 var $input = $(this), input = this; 832 if (opts.clearMaskOnLostFocus) { 833 if (!$input.hasClass('focus.inputmask')) { 834 if (input._valueGet() == getActiveBuffer().join('') || input._valueGet() == '') 835 input._valueSet(''); 836 else { //clearout optional tail of the mask 837 clearOptionalTail(input, buffer); 838 } 839 } 840 } 841 }).bind("click.inputmask", function () { 842 var input = this; 843 setTimeout(function () { 844 var selectedCaret = caret(input); 845 if (selectedCaret.begin == selectedCaret.end) { 846 var clickPosition = selectedCaret.begin; 847 lastPosition = checkVal(input, buffer, false); 848 determineInputDirection(input, selectedCaret); 849 if (isRTL) 850 caret(input, clickPosition > lastPosition && (isValid(clickPosition, buffer[clickPosition], buffer, true, isRTL) !== false || !isMask(clickPosition)) ? clickPosition : lastPosition); 851 else 852 caret(input, clickPosition < lastPosition && (isValid(clickPosition, buffer[clickPosition], buffer, true, isRTL) !== false || !isMask(clickPosition)) ? clickPosition : lastPosition); 853 } 854 }, 0); 855 }).bind('dblclick.inputmask', function () { 856 var input = this; 857 setTimeout(function () { 858 caret(input, 0, lastPosition); 859 }, 0); 860 }).bind("keydown.inputmask", keydownEvent 861 ).bind("keypress.inputmask", keypressEvent 862 ).bind("keyup.inputmask", keyupEvent 863 ).bind(pasteEvent + ".inputmask dragdrop.inputmask drop.inputmask", function () { 864 var input = this; 865 setTimeout(function () { 866 caret(input, checkVal(input, buffer, true)); 867 if (isComplete(buffer)) 868 $input.trigger("complete"); 869 }, 0); 870 }).bind('setvalue.inputmask', function () { 871 var input = this; 872 undoBuffer = input._valueGet(); 873 checkVal(input, buffer, true); 874 if (input._valueGet() == getActiveBuffer().join('')) 875 input._valueSet(''); 876 }).bind('complete.inputmask', opts.oncomplete) 877 .bind('incomplete.inputmask', opts.onincomplete) 878 .bind('cleared.inputmask', opts.oncleared); 879 880 //apply mask 881 lastPosition = checkVal(el, buffer, true); 882 883 // Wrap document.activeElement in a try/catch block since IE9 throw "Unspecified error" if document.activeElement is undefined when we are in an IFrame. 884 var activeElement; 885 try { 886 activeElement = document.activeElement; 887 } catch (e) { } 888 if (activeElement === el) { //position the caret when in focus 889 $input.addClass('focus.inputmask'); 890 caret(el, lastPosition); 891 } else if (opts.clearMaskOnLostFocus) { 892 if (el._valueGet() == getActiveBuffer().join('')) { 893 el._valueSet(''); 894 } else { 895 clearOptionalTail(el, buffer); 896 } 897 } 898 899 installEventRuler(el); 900 901 //private functions 902 function installEventRuler(npt) { 903 var events = $._data(npt).events; 904 905 $.each(events, function (eventType, eventHandlers) { 906 $.each(eventHandlers, function (ndx, eventHandler) { 907 if (eventHandler.namespace == "inputmask") { 908 var handler = eventHandler.handler; 909 eventHandler.handler = function () { 910 if (this.readOnly || this.disabled) 911 return false;
912 return handler.apply(this, arguments); 913 }; 914 } 915 }); 916 }); 917 } 918 919 function patchValueProperty(npt) { 920 var valueProperty; 921 if (Object.getOwnPropertyDescriptor) 922 valueProperty = Object.getOwnPropertyDescriptor(npt, "value"); 923 if (valueProperty && valueProperty.get) { 924 if (!npt._valueGet) { 925 926 npt._valueGet = valueProperty.get; 927 npt._valueSet = valueProperty.set; 928 929 Object.defineProperty(npt, "value", { 930 get: function () { 931 var $self = $(this), inputData = $(this).data('inputmask'), masksets = inputData['masksets'], 932 activeMasksetIndex = inputData['activeMasksetIndex']; 933 return inputData && inputData['autoUnmask'] ? $self.inputmask('unmaskedvalue') : this._valueGet() != masksets[activeMasksetIndex]['_buffer'].join('') ? this._valueGet() : ''; 934 }, 935 set: function (value) { 936 this._valueSet(value); $(this).triggerHandler('setvalue.inputmask'); 937 } 938 }); 939 } 940 } else if (document.__lookupGetter__ && npt.__lookupGetter__("value")) { 941 if (!npt._valueGet) { 942 npt._valueGet = npt.__lookupGetter__("value"); 943 npt._valueSet = npt.__lookupSetter__("value"); 944 945 npt.__defineGetter__("value", function () { 946 var $self = $(this), inputData = $(this).data('inputmask'), masksets = inputData['masksets'], 947 activeMasksetIndex = inputData['activeMasksetIndex']; 948 return inputData && inputData['autoUnmask'] ? $self.inputmask('unmaskedvalue') : this._valueGet() != masksets[activeMasksetIndex]['_buffer'].join('') ? this._valueGet() : ''; 949 }); 950 npt.__defineSetter__("value", function (value) { 951 this._valueSet(value); $(this).triggerHandler('setvalue.inputmask'); 952 }); 953 } 954 } else { 955 if (!npt._valueGet) { 956 npt._valueGet = function () { return this.value; } 957 npt._valueSet = function (value) { this.value = value; } 958 } 959 if ($.fn.val.inputmaskpatch != true) { 960 $.fn.val = function () { 961 if (arguments.length == 0) { 962 var $self = $(this); 963 if ($self.data('inputmask')) { 964 if ($self.data('inputmask')['autoUnmask']) 965 return $self.inputmask('unmaskedvalue'); 966 else { 967 var result = $.inputmask.val.apply($self); 968 var inputData = $(this).data('inputmask'), masksets = inputData['masksets'], 969 activeMasksetIndex = inputData['activeMasksetIndex']; 970 return result != masksets[activeMasksetIndex]['_buffer'].join('') ? result : ''; 971 } 972 } else return $.inputmask.val.apply($self); 973 } else { 974 var args = arguments; 975 return this.each(function () { 976 var $self = $(this); 977 var result = $.inputmask.val.apply($self, args); 978 if ($self.data('inputmask')) $self.triggerHandler('setvalue.inputmask'); 979 return result; 980 }); 981 } 982 }; 983 $.extend($.fn.val, { 984 inputmaskpatch: true 985 }); 986 } 987 } 988 } 989 990 function determineInputDirection(input, pos) { 991 //set input direction according the position to the radixPoint 992 if (opts.numericInput && opts.radixPoint != "") { 993 var nptStr = input._valueGet(); 994 var radixPosition = nptStr.indexOf(opts.radixPoint); 995 isRTL = pos.begin <= radixPosition || pos.end <= radixPosition || radixPosition == -1; 996 } 997 } 998 999 //shift chars to left from start to end and put c at end position if defined 1000 function shiftL(start, end, c) { 1001 while (!isMask(start) && start - 1 >= 0) start--; 1002 for (var i = start; i < end && i < getMaskLength(buffer) ; i++) { 1003 if (isMask(i)) { 1004 setReTargetPlaceHolder(buffer, i); 1005 var j = seekNext(buffer, i); 1006 var p = getBufferElement(buffer, j); 1007 if (p != getPlaceHolder(j)) { 1008 if (j < getMaskLength(buffer) && isValid(i, p, buffer, true, isRTL) !== false && getActiveTests()[determineTestPosition(i)].def == getActiveTests()[determineTestPosition(j)].def) { 1009 setBufferElement(buffer, i, getBufferElement(buffer, j)); 1010 setReTargetPlaceHolder(buffer, j); //cleanup next position 1011 } else { 1012 if (isMask(i)) 1013 break; 1014 } 1015 } else if (c == undefined) break; 1016 } else { 1017 setReTargetPlaceHolder(buffer, i); 1018 } 1019 } 1020 if (c != undefined) 1021 setBufferElement(buffer, isRTL ? end : seekPrevious(buffer, end), c); 1022 1023 buffer = truncateInput(buffer.join(''), isRTL).split(''); 1024 if (buffer.length == 0) buffer = getActiveBuffer().slice(); 1025 1026 return start; //return the used start position 1027 } 1028 function shiftR(start, end, c, full) { //full => behave like a push right ~ do not stop on placeholders 1029 for (var i = start; i <= end && i < getMaskLength(buffer) ; i++) { 1030 if (isMask(i)) { 1031 var t = getBufferElement(buffer, i); 1032 setBufferElement(buffer, i, c); 1033 if (t != getPlaceHolder(i)) { 1034 var j = seekNext(buffer, i); 1035 if (j < getMaskLength(buffer)) { 1036 if (isValid(j, t, buffer, true, isRTL) !== false && getActiveTests()[determineTestPosition(i)].def == getActiveTests()[determineTestPosition(j)].def) 1037 c = t; 1038 else { 1039 if (isMask(j)) 1040 break; 1041 else c = t; 1042 } 1043 } else break; 1044 } else if (full !== true) break; 1045 } else 1046 setReTargetPlaceHolder(buffer, i); 1047 } 1048 var lengthBefore = buffer.length; 1049 buffer = truncateInput(buffer.join(''), isRTL).split(''); 1050 if (buffer.length == 0) buffer = getActiveBuffer().slice(); 1051 1052 return end - (lengthBefore - buffer.length); //return new start position 1053 }; 1054 1055 function keydownEvent(e) { 1056 //Safari 5.1.x - modal dialog fires keypress twice workaround 1057 skipKeyPressEvent = false;
1058 1059 var input = this, k = e.keyCode, pos = caret(input); 1060 1061 determineInputDirection(input, pos); 1062 1063 //backspace, delete, and escape get special treatment 1064 if (k == opts.keyCode.BACKSPACE || k == opts.keyCode.DELETE || (iphone && k == 127)) {//backspace/delete 1065 var maskL = getMaskLength(buffer); 1066 if (pos.begin == 0 && pos.end == maskL) { //remove full selection 1067 activeMasksetIndex = 0; //reset activemask 1068 buffer = getActiveBuffer().slice(); 1069 writeBuffer(input, buffer); 1070 caret(input, checkVal(input, buffer, false)); 1071 } else if ((pos.end - pos.begin) > 1 || ((pos.end - pos.begin) == 1 && opts.insertMode)) { //partial selection 1072 clearBuffer(buffer, pos.begin, pos.end); 1073 determineActiveMasksetIndex(buffer, pos.begin, activeMasksetIndex); 1074 writeBuffer(input, buffer, isRTL ? checkVal(input, buffer, false) : pos.begin); 1075 } else { //handle delete 1076 var beginPos = pos.begin; 1077 if (k == opts.keyCode.DELETE) { 1078 if (beginPos < firstMaskPos) 1079 beginPos = firstMaskPos; 1080 if (beginPos < maskL) { 1081 if (opts.numericInput && opts.radixPoint != "" && buffer[beginPos] == opts.radixPoint) { 1082 beginPos = (buffer.length - 1 == beginPos) /* radixPoint is latest? delete it */ ? beginPos : seekNext(buffer, beginPos); 1083 beginPos = shiftL(beginPos, maskL); 1084 } else { 1085 if (isRTL) { 1086 beginPos = shiftR(firstMaskPos, beginPos, getPlaceHolder(beginPos), true); 1087 beginPos = seekNext(buffer, beginPos); 1088 } else { 1089 beginPos = shiftL(beginPos, maskL); 1090 } 1091 } 1092 determineActiveMasksetIndex(buffer, beginPos, activeMasksetIndex); 1093 writeBuffer(input, buffer, beginPos); 1094 } 1095 } else if (k == opts.keyCode.BACKSPACE) { //handle backspace 1096 if (beginPos > firstMaskPos) { 1097 beginPos -= 1; 1098 if (opts.numericInput && opts.radixPoint != "" && buffer[beginPos] == opts.radixPoint) { 1099 beginPos = shiftR(firstMaskPos, (buffer.length - 1 == beginPos) /* radixPoint is latest? delete it */ ? beginPos : beginPos - 1, getPlaceHolder(beginPos), true); 1100 beginPos++; 1101 } else { 1102 if (isRTL) { 1103 beginPos = shiftR(firstMaskPos, beginPos, getPlaceHolder(beginPos), true); 1104 beginPos = buffer[beginPos + 1] == opts.radixPoint ? beginPos + 1 : seekNext(buffer, beginPos); 1105 } else { 1106 beginPos = shiftL(beginPos, maskL); 1107 } 1108 } 1109 determineActiveMasksetIndex(buffer, beginPos, activeMasksetIndex); 1110 writeBuffer(input, buffer, beginPos); 1111 } 1112 } 1113 } 1114 if (input._valueGet() == getActiveBuffer().join('')) 1115 $(input).trigger('cleared'); 1116 1117 e.preventDefault(); //stop default action but allow propagation 1118 } else if (k == opts.keyCode.END || k == opts.keyCode.PAGE_DOWN) { //when END or PAGE_DOWN pressed set position at lastmatch 1119 setTimeout(function () { 1120 var caretPos = checkVal(input, buffer, false, true); 1121 if (!opts.insertMode && caretPos == getMaskLength(buffer) && !e.shiftKey) caretPos--; 1122 caret(input, e.shiftKey ? pos.begin : caretPos, caretPos); 1123 }, 0); 1124 } else if (k == opts.keyCode.HOME || k == opts.keyCode.PAGE_UP) {//Home or page_up 1125 caret(input, 0, e.shiftKey ? pos.begin : 0); 1126 } 1127 else if (k == opts.keyCode.ESCAPE) {//escape 1128 input._valueSet(undoBuffer); 1129 caret(input, 0, checkVal(input, buffer)); 1130 } else if (k == opts.keyCode.INSERT) {//insert 1131 opts.insertMode = !opts.insertMode; 1132 caret(input, !opts.insertMode && pos.begin == getMaskLength(buffer) ? pos.begin - 1 : pos.begin); 1133 } else if (e.ctrlKey && k == 88) { 1134 setTimeout(function () { 1135 caret(input, checkVal(input, buffer, true)); 1136 }, 0); 1137 } else if (!opts.insertMode) { //overwritemode 1138 if (k == opts.keyCode.RIGHT) {//right 1139 var caretPos = pos.begin == pos.end ? pos.end + 1 : pos.end; 1140 caretPos = caretPos < getMaskLength(buffer) ? caretPos : pos.end; 1141 caret(input, e.shiftKey ? pos.begin : caretPos, e.shiftKey ? caretPos + 1 : caretPos); 1142 } else if (k == opts.keyCode.LEFT) {//left 1143 var caretPos = pos.begin - 1; 1144 caretPos = caretPos > 0 ? caretPos : 0; 1145 caret(input, caretPos, e.shiftKey ? pos.end : caretPos); 1146 } 1147 } 1148 1149 opts.onKeyDown.call(this, e, buffer, opts); //extra stuff to execute on keydown 1150 ignorable = $.inArray(k, opts.ignorables) != -1; 1151 } 1152 1153 function keypressEvent(e) { 1154 //Safari 5.1.x - modal dialog fires keypress twice workaround 1155 if (skipKeyPressEvent) return false;
1156 skipKeyPressEvent = true; 1157 1158 var input = this, $input = $(input); 1159 1160 e = e || window.event; 1161 var k = e.which || e.charCode || e.keyCode, 1162 c = String.fromCharCode(k); 1163 1164 if (opts.numericInput && c == opts.radixPoint) { 1165 var nptStr = input._valueGet(); 1166 var radixPosition = nptStr.indexOf(opts.radixPoint); 1167 caret(input, seekNext(buffer, radixPosition != -1 ? radixPosition : getMaskLength(buffer))); 1168 } 1169 1170 if (e.ctrlKey || e.altKey || e.metaKey || ignorable) { 1171 return true; 1172 } else { 1173 if (k) { 1174 $input.trigger('input'); 1175 1176 var pos = caret(input), maskL = getMaskLength(buffer), writeOutBuffer = true; 1177 clearBuffer(buffer, pos.begin, pos.end); 1178 1179 if (isRTL) { 1180 var p = seekPrevious(buffer, pos.end), np; 1181 if ((np = isValid(p == maskL || getBufferElement(buffer, p) == opts.radixPoint ? seekPrevious(buffer, p) : p, c, buffer, false, isRTL)) !== false) { 1182 var refresh = false; 1183 if (np !== true) { 1184 refresh = np["refresh"]; //only rewrite buffer from isValid 1185 p = np.pos != undefined ? np.pos : p; //set new position from isValid 1186 c = np.c != undefined ? np.c : c; //set new char from isValid 1187 } 1188 if (refresh !== true) { 1189 maskL = getMaskLength(buffer); //update masklength to include possible groupSeparator offset 1190 var firstUnmaskedPosition = firstMaskPos; 1191 if (opts.insertMode == true) { 1192 if (getActiveMaskSet()['greedy'] == true) { 1193 var bfrClone = buffer.slice(); 1194 while (getBufferElement(bfrClone, firstUnmaskedPosition, true) != getPlaceHolder(firstUnmaskedPosition) && firstUnmaskedPosition <= p) { 1195 firstUnmaskedPosition = firstUnmaskedPosition == maskL ? (maskL + 1) : seekNext(buffer, firstUnmaskedPosition); 1196 } 1197 } 1198 if (firstUnmaskedPosition <= p && (getActiveMaskSet()['greedy'] || buffer.length < maskL)) { 1199 if (buffer[firstMaskPos] != getPlaceHolder(firstMaskPos) && buffer.length < maskL) { 1200 var offset = prepareBuffer(buffer, -1, isRTL); 1201 if (pos.end != 0) p = p + offset; 1202 maskL = buffer.length; 1203 } 1204 shiftL(firstUnmaskedPosition, p, c); 1205 } else writeOutBuffer = false; 1206 } else setBufferElement(buffer, p, c); 1207 } 1208 1209 if (writeOutBuffer) { 1210 writeBuffer(input, buffer, opts.numericInput ? p + 1 : p); 1211 setTimeout(function () { //timeout needed for IE 1212 if (isComplete(buffer)) 1213 $input.trigger("complete"); 1214 }, 0); 1215 } 1216 } else if (android) writeBuffer(input, buffer, pos.begin); 1217 } 1218 else { 1219 var p = seekNext(buffer, pos.begin - 1), np; 1220 prepareBuffer(buffer, p, isRTL); 1221 if ((np = isValid(p, c, buffer, false, isRTL)) !== false) { 1222 var refresh = false;
1223 if (np !== true) { 1224 refresh = np["refresh"]; //only rewrite buffer from isValid 1225 p = np.pos != undefined ? np.pos : p; //set new position from isValid 1226 c = np.c != undefined ? np.c : c; //set new char from isValid 1227 } 1228 if (refresh !== true) { 1229 if (opts.insertMode == true) { 1230 var lastUnmaskedPosition = getMaskLength(buffer); 1231 var bfrClone = buffer.slice(); 1232 while (getBufferElement(bfrClone, lastUnmaskedPosition, true) != getPlaceHolder(lastUnmaskedPosition) && lastUnmaskedPosition >= p) { 1233 lastUnmaskedPosition = lastUnmaskedPosition == 0 ? -1 : seekPrevious(buffer, lastUnmaskedPosition); 1234 } 1235 if (lastUnmaskedPosition >= p) 1236 shiftR(p, buffer.length, c); 1237 else writeOutBuffer = false; 1238 } else setBufferElement(buffer, p, c); 1239 } 1240 if (writeOutBuffer) { 1241 var next = seekNext(buffer, p); 1242 writeBuffer(input, buffer, next); 1243 1244 setTimeout(function () { //timeout needed for IE 1245 if (isComplete(buffer)) 1246 $input.trigger("complete"); 1247 }, 0); 1248 } 1249 } else if (android) writeBuffer(input, buffer, pos.begin); 1250 } 1251 e.preventDefault(); 1252 } 1253 } 1254 } 1255 1256 function keyupEvent(e) { 1257 var $input = $(this), input = this; 1258 var k = e.keyCode; 1259 opts.onKeyUp.call(this, e, buffer, opts); //extra stuff to execute on keyup 1260 if (k == opts.keyCode.TAB && $input.hasClass('focus.inputmask') && input._valueGet().length == 0 && opts.showMaskOnFocus) { 1261 buffer = getActiveBuffer().slice(); 1262 writeBuffer(input, buffer); 1263 if (!isRTL) caret(input, 0); 1264 undoBuffer = input._valueGet(); 1265 } 1266 } 1267 } 1268 1269 return this; //return this to expose publics 1270 }; 1271 } 1272})(jQuery);
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.