1/** 2 * jquery.mask.js 3 * 4 * @version: v1.14.16 5 * @author: Igor Escobar 6 * 7 * Created by Igor Escobar on 2012-03-10. Please report any bug at github.com/igorescobar/jQuery-Mask-Plugin 8 * 9 * Copyright (c) 2012 Igor Escobar http://igorescobar.com 10 * 11 * The MIT License (http://www.opensource.org/licenses/mit-license.php) 12 * 13 * Permission is hereby granted, free of charge, to any person 14 * obtaining a copy of this software and associated documentation 15 * files (the "Software"), to deal in the Software without 16 * restriction, including without limitation the rights to use, 17 * copy, modify, merge, publish, distribute, sublicense, and/or sell 18 * copies of the Software, and to permit persons to whom the 19 * Software is furnished to do so, subject to the following 20 * conditions: 21 * 22 * The above copyright notice and this permission notice shall be 23 * included in all copies or substantial portions of the Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 27 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 29 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 30 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 32 * OTHER DEALINGS IN THE SOFTWARE. 33 */ 34 35/* jshint laxbreak: true */ 36/* jshint maxcomplexity:17 */ 37/* global define */ 38 39// UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere. 40// https://github.com/umdjs/umd/blob/master/templates/jqueryPlugin.js 41// reformatted code by ThemeComplete 42( function( factory, jQuery, Zepto ) { 43 'use strict'; 44 45 if ( typeof define === 'function' && define.amd ) { 46 define( [ 'jquery' ], factory ); 47 } else if ( typeof exports === 'object' && typeof Meteor === 'undefined' ) { 48 window.module.exports = factory( window.require( 'jquery' ) ); 49 } else { 50 factory( jQuery || Zepto ); 51 } 52}( 53 function( $ ) { 54 'use strict'; 55 56 var JSON = window.JSON; 57 var globals; 58 var Mask = function( el, mask, options ) { 59 var jMask = this; 60 var regexMask; 61 var oldValue; 62 63 var p = { 64 invalid: [], 65 getCaret: function() { 66 var sel, 67 pos = 0, 68 ctrl, 69 dSel, 70 cSelStart; 71 try { 72 ctrl = el.get( 0 ); 73 dSel = document.selection; 74 cSelStart = ctrl.selectionStart; 75 76 // IE Support 77 if ( dSel && navigator.appVersion.indexOf( 'MSIE 10' ) === -1 ) { 78 sel = dSel.createRange(); 79 sel.moveStart( 'character', -p.val().length ); 80 pos = sel.text.length; 81 } else if ( cSelStart || cSelStart === '0' ) { // Firefox support 82 pos = cSelStart; 83 } 84 85 return pos; 86 } catch ( err ) { 87 window.console.log( err ); 88 } 89 }, 90 setCaret: function( pos ) { 91 var range; 92 var ctrl; 93 try { 94 if ( el.is( ':focus' ) ) { 95 ctrl = el.get( 0 ); 96 97 // Firefox, WebKit, etc.. 98 if ( ctrl.setSelectionRange ) { 99 ctrl.setSelectionRange( pos, pos ); 100 } else { 101 // IE 102 range = ctrl.createTextRange(); 103 range.collapse( true ); 104 range.moveEnd( 'character', pos ); 105 range.moveStart( 'character', pos ); 106 range.select(); 107 } 108 } 109 } catch ( err ) { 110 window.console.log( err ); 111 } 112 }, 113 events: function() { 114 el.on( 'keydown.mask', function( e ) { 115 el.data( 'mask-keycode', e.keyCode || e.which ); 116 el.data( 'mask-previus-value', el.val() ); 117 el.data( 'mask-previus-caret-pos', p.getCaret() ); 118 p.maskDigitPosMapOld = p.maskDigitPosMap; 119 } ) 120 .on( $.jMaskGlobals.useInput ? 'input.mask' : 'keyup.mask', p.behaviour ) 121 .on( 'paste.mask drop.mask', function() { 122 setTimeout( function() { 123 el.keydown().keyup(); 124 }, 100 ); 125 } ) 126 .on( 'change.mask', function() { 127 el.data( 'changed', true ); 128 } ) 129 .on( 'blur.mask', function() { 130 if ( oldValue !== p.val() && ! el.data( 'changed' ) ) { 131 el.trigger( 'change' ); 132 } 133 el.data( 'changed', false ); 134 } ) 135 // it's very important that this callback remains in this position 136 // otherwhise oldValue it's going to work buggy 137 .on( 'blur.mask', function() { 138 oldValue = p.val(); 139 } ) 140 // select all text on focus 141 .on( 'focus.mask', function( e ) { 142 if ( options.selectOnFocus === true ) { 143 $( e.target ).select(); 144 } 145 } ) 146 // clear the value if it not complete the mask 147 .on( 'focusout.mask', function() { 148 if ( options.clearIfNotMatch && ! regexMask.test( p.val() ) ) { 149 p.val( '' ); 150 } 151 } ); 152 }, 153 getRegexMask: function() { 154 var maskChunks = [], 155 translation, 156 pattern, 157 optional, 158 recursive, 159 oRecursive, 160 r; 161 var i; 162 163 for ( i = 0; i < mask.length; i += 1 ) { 164 translation = jMask.translation[ mask.charAt( i ) ]; 165 166 if ( translation ) { 167 pattern = translation.pattern.toString().replace( /.{1}$|^.{1}/g, '' ); 168 optional = translation.optional; 169 recursive = translation.recursive; 170 171 if ( recursive ) { 172 maskChunks.push( mask.charAt( i ) ); 173 oRecursive = { 174 digit: mask.charAt( i ), 175 pattern: pattern 176 }; 177 } else { 178 maskChunks.push( ! optional && ! recursive ? pattern : pattern + '?' ); 179 } 180 } else { 181 // eslint-disable-next-line no-useless-escape 182 maskChunks.push( mask.charAt( i ).replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' ) ); 183 } 184 } 185 186 r = maskChunks.join( '' ); 187 188 if ( oRecursive ) { 189 r = r.replace( new RegExp( '(' + oRecursive.digit + '(.*' + oRecursive.digit + ')?)' ), '($1)?' ).replace( new RegExp( oRecursive.digit, 'g' ), oRecursive.pattern ); 190 } 191 192 return new RegExp( r ); 193 }, 194 destroyEvents: function() {
195 el.off( [ 'input', 'keydown', 'keyup', 'paste', 'drop', 'blur', 'focusout', '' ].join( '.mask ' ) ); 196 }, 197 val: function( v ) { 198 var isInput = el.is( 'input' ), 199 method = isInput ? 'val' : 'text', 200 r; 201 202 if ( arguments.length > 0 ) { 203 if ( el[ method ]() !== v ) { 204 el[ method ]( v ); 205 } 206 r = el; 207 } else { 208 r = el[ method ](); 209 } 210 211 return r; 212 }, 213 calculateCaretPosition: function( oldVal ) { 214 var newVal = p.getMasked(), 215 caretPosNew = p.getCaret(); 216 var caretPosOld, 217 newValL, 218 oldValL, 219 maskDigitsBeforeCaret = 0, 220 maskDigitsAfterCaret = 0, 221 maskDigitsBeforeCaretAll = 0, 222 maskDigitsBeforeCaretAllOld = 0, 223 i = 0; 224 var caretPos; 225 if ( oldVal !== newVal ) { 226 caretPosOld = el.data( 'mask-previus-caret-pos' ) || 0; 227 newValL = newVal.length; 228 oldValL = oldVal.length; 229 230 for ( i = caretPosNew; i < newValL; i += 1 ) { 231 if ( ! p.maskDigitPosMap[ i ] ) { 232 break; 233 } 234 maskDigitsAfterCaret = maskDigitsAfterCaret + 1; 235 } 236 237 for ( i = caretPosNew - 1; i >= 0; i -= 1 ) { 238 if ( ! p.maskDigitPosMap[ i ] ) { 239 break; 240 } 241 maskDigitsBeforeCaret = maskDigitsBeforeCaret + 1; 242 } 243 244 for ( i = caretPosNew - 1; i >= 0; i -= 1 ) { 245 if ( p.maskDigitPosMap[ i ] ) { 246 maskDigitsBeforeCaretAll = maskDigitsBeforeCaretAll + 1; 247 } 248 } 249 250 for ( i = caretPosOld - 1; i >= 0; i -= 1 ) { 251 if ( p.maskDigitPosMapOld[ i ] ) { 252 maskDigitsBeforeCaretAllOld = maskDigitsBeforeCaretAllOld + 1; 253 } 254 } 255 256 // if the cursor is at the end keep it there 257 if ( caretPosNew > oldValL ) { 258 caretPosNew = newValL * 10; 259 } else if ( caretPosOld >= caretPosNew && caretPosOld !== oldValL ) { 260 if ( ! p.maskDigitPosMapOld[ caretPosNew ] ) { 261 caretPos = caretPosNew; 262 caretPosNew -= maskDigitsBeforeCaretAllOld - maskDigitsBeforeCaretAll; 263 caretPosNew -= maskDigitsBeforeCaret; 264 if ( p.maskDigitPosMap[ caretPosNew ] ) { 265 caretPosNew = caretPos; 266 } 267 } 268 } else if ( caretPosNew > caretPosOld ) { 269 caretPosNew += maskDigitsBeforeCaretAll - maskDigitsBeforeCaretAllOld; 270 caretPosNew += maskDigitsAfterCaret; 271 } 272 } 273 return caretPosNew; 274 }, 275 behaviour: function( e ) { 276 var keyCode = el.data( 'mask-keycode' ); 277 var newVal; 278 var oldVal; 279 var caretPos; 280 e = e || window.event; 281 p.invalid = []; 282 283 if ( $.inArray( keyCode, jMask.byPassKeys ) === -1 ) { 284 newVal = p.getMasked(); 285 caretPos = p.getCaret(); 286 oldVal = el.data( 'mask-previus-value' ) || ''; 287 288 // this is a compensation to devices/browsers that don't compensate 289 // caret positioning the right way 290 setTimeout( function() { 291 p.setCaret( p.calculateCaretPosition( oldVal ) ); 292 }, $.jMaskGlobals.keyStrokeCompensation ); 293 294 p.val( newVal ); 295 p.setCaret( caretPos ); 296 return p.callbacks( e ); 297 } 298 }, 299 getMasked: function( skipMaskChars, val ) { 300 var buf = [], 301 value = val === undefined ? p.val() : val + '', 302 m = 0, 303 maskLen = mask.length, 304 v = 0, 305 valLen = value.length, 306 offset = 1, 307 addMethod = 'push', 308 resetPos = -1, 309 maskDigitCount = 0, 310 maskDigitPosArr = [], 311 lastMaskChar, 312 check; 313 var lastUntranslatedMaskChar; 314 var maskDigit; 315 var valDigit; 316 var translation; 317 var lastMaskCharDigit; 318 var newVal; 319 if ( options.reverse ) { 320 addMethod = 'unshift'; 321 offset = -1; 322 lastMaskChar = 0; 323 m = maskLen - 1; 324 v = valLen - 1; 325 check = function() { 326 return m > -1 && v > -1; 327 }; 328 } else { 329 lastMaskChar = maskLen - 1; 330 check = function() { 331 return m < maskLen && v < valLen; 332 }; 333 } 334 335 while ( check() ) { 336 maskDigit = mask.charAt( m ); 337 valDigit = value.charAt( v ); 338 translation = jMask.translation[ maskDigit ]; 339 340 if ( translation ) { 341 if ( valDigit.match( translation.pattern ) ) { 342 buf[ addMethod ]( valDigit ); 343 if ( translation.recursive ) { 344 if ( resetPos === -1 ) { 345 resetPos = m; 346 } else if ( m === lastMaskChar && m !== resetPos ) { 347 m = resetPos - offset; 348 } 349 350 if ( lastMaskChar === resetPos ) { 351 m -= offset; 352 } 353 } 354 m += offset; 355 } else if ( valDigit === lastUntranslatedMaskChar ) { 356 // matched the last untranslated (raw) mask character that we encountered 357 // likely an insert offset the mask character from the last entry; fall 358 // through and only increment v 359 maskDigitCount = maskDigitCount - 1; 360 lastUntranslatedMaskChar = undefined; 361 } else if ( translation.optional ) { 362 m += offset; 363 v -= offset; 364 } else if ( translation.fallback ) { 365 buf[ addMethod ]( translation.fallback ); 366 m += offset; 367 v -= offset; 368 } else { 369 p.invalid.push( { 370 p: v, 371 v: valDigit, 372 e: translation.pattern 373 } ); 374 } 375 v += offset; 376 } else {
377 if ( ! skipMaskChars ) { 378 buf[ addMethod ]( maskDigit ); 379 } 380 381 if ( valDigit === maskDigit ) { 382 maskDigitPosArr.push( v ); 383 v += offset; 384 } else { 385 lastUntranslatedMaskChar = maskDigit; 386 maskDigitPosArr.push( v + maskDigitCount ); 387 maskDigitCount = maskDigitCount + 1; 388 } 389 390 m += offset; 391 } 392 } 393 394 lastMaskCharDigit = mask.charAt( lastMaskChar ); 395 if ( maskLen === valLen + 1 && ! jMask.translation[ lastMaskCharDigit ] ) { 396 buf.push( lastMaskCharDigit ); 397 } 398 399 newVal = buf.join( '' ); 400 p.mapMaskdigitPositions( newVal, maskDigitPosArr, valLen ); 401 return newVal; 402 }, 403 mapMaskdigitPositions: function( newVal, maskDigitPosArr, valLen ) { 404 var maskDiff = options.reverse ? newVal.length - valLen : 0; 405 var i; 406 p.maskDigitPosMap = {}; 407 for ( i = 0; i < maskDigitPosArr.length; i += 1 ) { 408 p.maskDigitPosMap[ maskDigitPosArr[ i ] + maskDiff ] = 1; 409 } 410 }, 411 callbacks: function( e ) { 412 var val = p.val(), 413 changed = val !== oldValue, 414 defaultArgs = [ val, e, el, options ], 415 callback = function( name, criteria, args ) { 416 if ( typeof options[ name ] === 'function' && criteria ) { 417 options[ name ].apply( this, args ); 418 } 419 }; 420 421 callback( 'onChange', changed === true, defaultArgs ); 422 callback( 'onKeyPress', changed === true, defaultArgs ); 423 callback( 'onComplete', val.length === mask.length, defaultArgs ); 424 callback( 'onInvalid', p.invalid.length > 0, [ val, e, el, p.invalid, options ] ); 425 } 426 }; 427 428 el = $( el ); 429 430 oldValue = p.val(); 431 432 mask = typeof mask === 'function' ? mask( p.val(), undefined, el, options ) : mask; 433 434 // public methods 435 jMask.mask = mask; 436 jMask.options = options; 437 jMask.remove = function() { 438 var caret = p.getCaret(); 439 if ( jMask.options.placeholder ) { 440 el.removeAttr( 'placeholder' ); 441 } 442 if ( el.data( 'mask-maxlength' ) ) { 443 el.removeAttr( 'maxlength' ); 444 } 445 p.destroyEvents(); 446 p.val( jMask.getCleanVal() ); 447 p.setCaret( caret ); 448 return el; 449 }; 450 451 // get value without mask 452 jMask.getCleanVal = function() { 453 return p.getMasked( true ); 454 }; 455 456 // get masked value without the value being in the input or element 457 jMask.getMaskedVal = function( val ) { 458 return p.getMasked( false, val ); 459 }; 460 461 jMask.init = function( onlyMask ) { 462 var i; 463 var translation; 464 var caret; 465 var maxlength; 466 467 onlyMask = onlyMask || false; 468 options = options || {}; 469 470 jMask.clearIfNotMatch = $.jMaskGlobals.clearIfNotMatch; 471 jMask.byPassKeys = $.jMaskGlobals.byPassKeys; 472 jMask.translation = $.extend( {}, $.jMaskGlobals.translation, options.translation ); 473 474 jMask = $.extend( true, {}, jMask, options ); 475 476 regexMask = p.getRegexMask(); 477 478 if ( onlyMask ) { 479 p.events(); 480 p.val( p.getMasked() ); 481 } else { 482 if ( options.placeholder ) { 483 el.attr( 'placeholder', options.placeholder ); 484 } 485 486 // this is necessary, otherwise if the user submit the form 487 // and then press the "back" button, the autocomplete will erase 488 // the data. Works fine on IE9+, FF, Opera, Safari. 489 if ( el.data( 'mask' ) ) { 490 el.attr( 'autocomplete', 'off' ); 491 } 492 493 // detect if is necessary let the user type freely. 494 // for is a lot faster than forEach. 495 for ( i = 0, maxlength = true; i < mask.length; i += 1 ) { 496 translation = jMask.translation[ mask.charAt( i ) ]; 497 if ( translation && translation.recursive ) { 498 maxlength = false; 499 break; 500 } 501 } 502 503 if ( maxlength ) { 504 el.attr( 'maxlength', mask.length ).data( 'mask-maxlength', true ); 505 } 506 507 p.destroyEvents(); 508 p.events(); 509 510 caret = p.getCaret(); 511 p.val( p.getMasked() ); 512 p.setCaret( caret ); 513 } 514 }; 515 516 jMask.init( ! el.is( 'input' ) ); 517 }; 518 519 var notSameMaskObject = function( field, mask, options ) { 520 var maskObject = $( field ).data( 'mask' ), 521 stringify = JSON.stringify, 522 value = $( field ).val() || $( field ).text(); 523 options = options || {};
524 try { 525 if ( typeof mask === 'function' ) { 526 mask = mask( value ); 527 } 528 return typeof maskObject !== 'object' || stringify( maskObject.options ) !== stringify( options ) || maskObject.mask !== mask; 529 } catch ( err ) { 530 window.console.log( err ); 531 } 532 }, 533 HTMLAttributes = function() { 534 var input = $( this ), 535 options = {}, 536 prefix = 'data-mask-', 537 mask = input.attr( 'data-mask' ); 538 539 if ( input.attr( prefix + 'reverse' ) ) { 540 options.reverse = true; 541 } 542 543 if ( input.attr( prefix + 'clearifnotmatch' ) ) { 544 options.clearIfNotMatch = true; 545 } 546 547 if ( input.attr( prefix + 'selectonfocus' ) === 'true' ) { 548 options.selectOnFocus = true; 549 } 550 551 if ( input.attr( prefix + 'placeholder' ) ) { 552 options.placeholder = input.attr( prefix + 'placeholder' ); 553 } 554 555 if ( notSameMaskObject( input, mask, options ) ) { 556 return input.data( 'mask', new Mask( this, mask, options ) ); 557 } 558 }, 559 eventSupported = function( eventName ) { 560 var el = document.createElement( 'div' ), 561 isSupported; 562 563 eventName = 'on' + eventName; 564 isSupported = eventName in el; 565 566 if ( ! isSupported ) { 567 el.setAttribute( eventName, 'return;' ); 568 isSupported = typeof el[ eventName ] === 'function'; 569 } 570 el = null; 571 572 return isSupported; 573 }; 574 575 $.maskWatchers = {}; 576 577 $.fn.mask = function( mask, options ) { 578 var selector = this.selector, 579 maskGlobals = $.jMaskGlobals, 580 interval = maskGlobals.watchInterval, 581 watchInputs, 582 maskFunction; 583 options = options || {}; 584 585 watchInputs = options.watchInputs || maskGlobals.watchInputs; 586 maskFunction = function() { 587 if ( notSameMaskObject( this, mask, options ) ) { 588 return $( this ).data( 'mask', new Mask( this, mask, options ) ); 589 } 590 }; 591 592 $( this ).each( maskFunction ); 593 594 if ( selector && selector !== '' && watchInputs ) { 595 clearInterval( $.maskWatchers[ selector ] ); 596 $.maskWatchers[ selector ] = setInterval( function() { 597 $( document ).find( selector ).each( maskFunction ); 598 }, interval ); 599 } 600 return this; 601 }; 602 603 $.fn.masked = function( val ) { 604 return this.data( 'mask' ).getMaskedVal( val ); 605 }; 606 607 $.fn.unmask = function() { 608 clearInterval( $.maskWatchers[ this.selector ] ); 609 delete $.maskWatchers[ this.selector ]; 610 return this.each( function() { 611 var dataMask = $( this ).data( 'mask' ); 612 if ( dataMask ) { 613 dataMask.remove().removeData( 'mask' ); 614 } 615 } ); 616 }; 617 618 $.fn.cleanVal = function() { 619 return this.data( 'mask' ).getCleanVal(); 620 }; 621 622 $.applyDataMask = function( selector ) { 623 var $selector; 624 selector = selector || $.jMaskGlobals.maskElements; 625 $selector = selector instanceof $ ? selector : $( selector ); 626 $selector.filter( $.jMaskGlobals.dataMaskAttr ).each( HTMLAttributes ); 627 }; 628 629 globals = { 630 maskElements: 'input,td,span,div', 631 dataMaskAttr: '*[data-mask]', 632 dataMask: true, 633 watchInterval: 300, 634 watchInputs: true, 635 keyStrokeCompensation: 10, 636 // old versions of chrome dont work great with input event 637 useInput: ! /Chrome\/[2-4][0-9]|SamsungBrowser/.test( window.navigator.userAgent ) && eventSupported( 'input' ), 638 watchDataMask: false, 639 byPassKeys: [ 9, 16, 17, 18, 36, 37, 38, 39, 40, 91 ], 640 translation: { 641 0: { pattern: /\d/ }, 642 9: { pattern: /\d/, optional: true }, 643 '#': { pattern: /\d/, recursive: true }, 644 A: { pattern: /[a-zA-Z0-9]/ }, 645 S: { pattern: /[a-zA-Z]/ } 646 } 647 }; 648 649 $.jMaskGlobals = $.jMaskGlobals || {}; 650 globals = $.jMaskGlobals = $.extend( true, {}, globals, $.jMaskGlobals ); 651 652 // looking for inputs with data-mask attribute 653 if ( globals.dataMask ) { 654 $.applyDataMask(); 655 } 656 657 setInterval( function() { 658 if ( $.jMaskGlobals.watchDataMask ) { 659 $.applyDataMask(); 660 } 661 }, globals.watchInterval ); 662 }, 663 window.jQuery, 664 window.Zepto 665) );
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.