1/* 2 Masked Input plugin for jQuery 3 Copyright (c) 2007-2013 Josh Bush (digitalbush.com) 4 Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) 5 Version: 1.4.1 6 Source: https://github.com/RubtsovAV/jquery.maskedinput/blob/master/src/jquery.maskedinput.js 7 Updated 26 June 2017 8 - Fixed bug with caret position on Android 9 */ 10(function (factory) { 11 if (typeof define === 'function' && define.amd) { 12 // AMD. Register as an anonymous module. 13 define(['jquery'], factory); 14 } else if (typeof exports === 'object') { 15 // Node/CommonJS 16 factory(require('jquery')); 17 } else { 18 // Browser globals 19 factory(jQuery); 20 } 21}(function ($) { 22 23 var ua = navigator.userAgent, 24 iPhone = /iphone/i.test(ua), 25 chrome = /chrome/i.test(ua), 26 android = /android/i.test(ua), 27 caretTimeoutId; 28 29 $.mask = { 30 //Predefined character definitions 31 definitions: { 32 '9': "[0-9]", 33 'a': "[A-Za-z]", 34 '*': "[A-Za-z0-9]" 35 }, 36 autoclear: true, 37 dataName: "rawMaskFn", 38 placeholder: '_' 39 }; 40 41 $.fn.extend({ 42 //Helper Function for Caret positioning 43 caret: function(begin, end) { 44 var range; 45 46 if (this.length === 0 || this.is(":hidden") || this.get(0) !== document.activeElement) { 47 return; 48 } 49 50 if (typeof begin == 'number') { 51 end = (typeof end === 'number') ? end : begin; 52 return this.each(function() { 53 if (this.setSelectionRange) { 54 this.setSelectionRange(begin, end); 55 } else if (this.createTextRange) { 56 range = this.createTextRange(); 57 range.collapse(true); 58 range.moveEnd('character', end); 59 range.moveStart('character', begin); 60 range.select(); 61 } 62 }); 63 } else { 64 if (this[0].setSelectionRange) { 65 begin = this[0].selectionStart; 66 end = this[0].selectionEnd; 67 } else if (document.selection && document.selection.createRange) { 68 range = document.selection.createRange(); 69 begin = 0 - range.duplicate().moveStart('character', -100000); 70 end = begin + range.text.length; 71 } 72 return { begin: begin, end: end }; 73 } 74 }, 75 unmask: function() { 76 return this.trigger("unmask"); 77 }, 78 mask: function(mask, settings) { 79 var input, 80 defs, 81 tests, 82 partialPosition, 83 firstNonMaskPos, 84 lastRequiredNonMaskPos, 85 len, 86 oldVal; 87 88 if (!mask && this.length > 0) { 89 input = $(this[0]); 90 var fn = input.data($.mask.dataName) 91 return fn?fn():undefined; 92 } 93 94 settings = $.extend({ 95 autoclear: $.mask.autoclear, 96 placeholder: $.mask.placeholder, // Load default placeholder 97 completed: null 98 }, settings); 99 100 101 defs = $.mask.definitions; 102 tests = []; 103 partialPosition = len = mask.length; 104 firstNonMaskPos = null; 105 106 mask = String(mask); 107 108 $.each(mask.split(""), function(i, c) { 109 if (c == '?') { 110 len--; 111 partialPosition = i; 112 } else if (defs[c]) { 113 tests.push(new RegExp(defs[c])); 114 if (firstNonMaskPos === null) { 115 firstNonMaskPos = tests.length - 1; 116 } 117 if(i < partialPosition){ 118 lastRequiredNonMaskPos = tests.length - 1; 119 } 120 } else { 121 tests.push(null); 122 } 123 }); 124 125 return this.trigger("unmask").each(function() { 126 var input = $(this), 127 buffer = $.map( 128 mask.split(""), 129 function(c, i) { 130 if (c != '?') { 131 return defs[c] ? getPlaceholder(i) : c; 132 } 133 }), 134 defaultBuffer = buffer.join(''), 135 focusText = input.val(); 136 137 function tryFireCompleted(){ 138 if (!settings.completed) { 139 return; 140 } 141 142 for (var i = firstNonMaskPos; i <= lastRequiredNonMaskPos; i++) { 143 if (tests[i] && buffer[i] === getPlaceholder(i)) { 144 return; 145 } 146 } 147 settings.completed.call(input); 148 } 149 150 function getPlaceholder(i){ 151 if(i < settings.placeholder.length) 152 return settings.placeholder.charAt(i); 153 return settings.placeholder.charAt(0); 154 } 155 156 function seekNext(pos) { 157 while (++pos < len && !tests[pos]); 158 return pos; 159 } 160 161 function seekPrev(pos) { 162 while (--pos >= 0 && !tests[pos]); 163 return pos; 164 } 165 166 function shiftL(begin,end) { 167 var i, 168 j; 169 170 if (begin<0) { 171 return; 172 } 173 174 for (i = begin, j = seekNext(end); i < len; i++) { 175 if (tests[i]) { 176 if (j < len && tests[i].test(buffer[j])) { 177 buffer[i] = buffer[j]; 178 buffer[j] = getPlaceholder(j); 179 } else { 180 break; 181 } 182 183 j = seekNext(j); 184 } 185 } 186 writeBuffer(); 187 input.caret(Math.max(firstNonMaskPos, begin)); 188 } 189 190 function shiftR(pos) { 191 var i, 192 c, 193 j, 194 t; 195 196 for (i = pos, c = getPlaceholder(pos); i < len; i++) { 197 if (tests[i]) { 198 j = seekNext(i); 199 t = buffer[i]; 200 buffer[i] = c; 201 if (j < len && tests[j].test(t)) { 202 c = t; 203 } else { 204 break; 205 } 206 } 207 } 208 } 209 210 function androidInputEvent(e) { 211 var curVal = input.val(); 212 var pos = input.caret(); 213 214 var proxy = function () { 215 $.proxy($.fn.caret, input, pos.begin, pos.begin)(); 216 }; 217 218 if (oldVal && oldVal.length && oldVal.length > curVal.length ) { 219 // a deletion or backspace happened 220 checkVal(true); 221 while (pos.begin > 0 && !tests[pos.begin-1]) 222 pos.begin--; 223 if (pos.begin === 0) 224 { 225 while (pos.begin < firstNonMaskPos && !tests[pos.begin]) 226 pos.begin++; 227 } 228 setTimeout(proxy, 0); 229 } else { 230 var pos2 = checkVal(true); 231 var lastEnteredValue = curVal.charAt(pos.begin); 232 if (pos.begin < len){ 233 if (!tests[pos.begin]) { 234 pos.begin = pos2; 235 } else { 236 if(tests[pos.begin].test(lastEnteredValue)){ 237 pos.begin++; 238 } 239 } 240 } 241 setTimeout(proxy, 0); 242 }
243 tryFireCompleted(); 244 } 245 246 247 function blurEvent(e) { 248 checkVal(); 249 250 if (input.val() != focusText) 251 input.change(); 252 } 253 254 function keydownEvent(e) { 255 if (input.prop("readonly")){ 256 return; 257 } 258 259 var k = e.which || e.keyCode, 260 pos, 261 begin, 262 end; 263 oldVal = input.val(); 264 //backspace, delete, and escape get special treatment 265 if (k === 8 || k === 46 || (iPhone && k === 127)) { 266 pos = input.caret(); 267 begin = pos.begin; 268 end = pos.end; 269 270 if (end - begin === 0) { 271 begin=k!==46?seekPrev(begin):(end=seekNext(begin-1)); 272 end=k===46?seekNext(end):end; 273 } 274 clearBuffer(begin, end); 275 shiftL(begin, end - 1); 276 277 e.preventDefault(); 278 } else if( k === 13 ) { // enter 279 blurEvent.call(this, e); 280 } else if (k === 27) { // escape 281 input.val(focusText); 282 input.caret(0, checkVal()); 283 e.preventDefault(); 284 } 285 } 286 287 function keypressEvent(e) { 288 if (input.prop("readonly")){ 289 return; 290 } 291 292 var k = e.which || e.keyCode, 293 pos = input.caret(), 294 p, 295 c, 296 next; 297 298 if (e.ctrlKey || e.altKey || e.metaKey || k < 32) {//Ignore 299 return; 300 } else if ( k && k !== 13 ) { 301 if (pos.end - pos.begin !== 0){ 302 clearBuffer(pos.begin, pos.end); 303 shiftL(pos.begin, pos.end-1); 304 } 305 306 p = seekNext(pos.begin - 1); 307 if (p < len) { 308 c = String.fromCharCode(k); 309 if (tests[p].test(c)) { 310 shiftR(p); 311 312 buffer[p] = c; 313 writeBuffer(); 314 next = seekNext(p); 315 316 if(android){ 317 //Path for CSP Violation on FireFox OS 1.1 318 var proxy = function() { 319 $.proxy($.fn.caret,input,next)(); 320 }; 321 322 setTimeout(proxy,0); 323 }else{ 324 input.caret(next); 325 } 326 if(pos.begin <= lastRequiredNonMaskPos){ 327 tryFireCompleted(); 328 } 329 } 330 } 331 e.preventDefault(); 332 } 333 } 334 335 function clearBuffer(start, end) { 336 var i; 337 for (i = start; i < end && i < len; i++) { 338 if (tests[i]) { 339 buffer[i] = getPlaceholder(i); 340 } 341 } 342 } 343 344 function writeBuffer() { input.val(buffer.join('')); } 345 346 function checkVal(allow) { 347 //try to place characters where they belong 348 var test = input.val(), 349 lastMatch = -1, 350 i, 351 c, 352 pos; 353 354 for (i = 0, pos = 0; i < len; i++) { 355 if (tests[i]) { 356 buffer[i] = getPlaceholder(i); 357 while (pos++ < test.length) { 358 c = test.charAt(pos - 1); 359 if (tests[i].test(c)) { 360 buffer[i] = c; 361 lastMatch = i; 362 break; 363 } 364 } 365 if (pos > test.length) { 366 clearBuffer(i + 1, len); 367 break; 368 } 369 } else { 370 if (buffer[i] === test.charAt(pos)) { 371 pos++; 372 } 373 if( i < partialPosition){ 374 lastMatch = i; 375 } 376 } 377 } 378 if (allow) { 379 writeBuffer(); 380 } else if (lastMatch + 1 < partialPosition) { 381 if (settings.autoclear || buffer.join('') === defaultBuffer) { 382 // Invalid value. Remove it and replace it with the 383 // mask, which is the default behavior. 384 if(input.val()) input.val(""); 385 clearBuffer(0, len); 386 } else { 387 // Invalid value, but we opt to show the value to the 388 // user and allow them to correct their mistake. 389 writeBuffer(); 390 } 391 } else { 392 writeBuffer(); 393 input.val(input.val().substring(0, lastMatch + 1)); 394 } 395 return (partialPosition ? i : firstNonMaskPos); 396 } 397 398 input.data($.mask.dataName,function(){ 399 return $.map(buffer, function(c, i) { 400 return tests[i]&&c!=getPlaceholder(i) ? c : null; 401 }).join(''); 402 }); 403 404 405 input 406 .one("unmask", function() { 407 input 408 .off(".mask") 409 .removeData($.mask.dataName); 410 }) 411 .on("focus.mask", function() { 412 if (input.prop("readonly")){ 413 return; 414 } 415 416 clearTimeout(caretTimeoutId); 417 var pos; 418 419 focusText = input.val(); 420 421 pos = checkVal(); 422 423 caretTimeoutId = setTimeout(function(){ 424 if(input.get(0) !== document.activeElement){ 425 return; 426 } 427 writeBuffer(); 428 if (pos == mask.replace("?","").length) { 429 input.caret(0, pos); 430 } else { 431 input.caret(pos); 432 } 433 }, 10); 434 }) 435 .on("blur.mask", blurEvent)
436 .on("keydown.mask", keydownEvent) 437 .on("keypress.mask", keypressEvent) 438 .on("input.mask paste.mask", function() { 439 if (input.prop("readonly")){ 440 return; 441 } 442 443 setTimeout(function() { 444 var pos=checkVal(true); 445 input.caret(pos); 446 tryFireCompleted(); 447 }, 0); 448 }); 449 if (chrome && android) 450 { 451 input 452 .off('input.mask') 453 .on('input.mask', androidInputEvent); 454 } 455 checkVal(); //Perform initial check for existing values 456 }); 457 } 458 }); 459}));
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.