1/*! 2 * jQuery UI Mask @VERSION 3 * 4 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 * Dual licensed under the MIT or GPL Version 2 licenses. 6 * http://jquery.org/license 7 * 8 * Depends: 9 * jquery.ui.core.js 10 * jquery.ui.widget.js 11 * 12 */ 13(function( $, undefined ) { 14 15var keyCode = $.ui.keyCode; 16 17$.widget( "ui.mask", { 18 version: "@VERSION", 19 defaultElement: "<input>", 20 options: { 21 clearEmpty: true, 22 definitions: { 23 "9": /[0-9]/, 24 "a": /[A-Za-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]/, 25 "*": /[A-Za-z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]/ 26 }, 27 mask: null, 28 placeholder: "_" 29 }, 30 31 _create: function() { 32 this._parseMask(); 33 this.refresh(); 34 this.element.addClass( "ui-mask" ); 35 this._on( this._events ); 36 }, 37 38 _destroy: function() { 39 this.element.removeClass( "ui-mask" ); 40 }, 41 42 refresh: function() { 43 this._parseValue(); 44 this._paint(); 45 }, 46 47 valid: function() { 48 return this.isValid; 49 }, 50 51 // returns (or sets) the value without the mask 52 value: function( value ) { 53 if ( value !== undefined ) { 54 this.element.val( value ); 55 this.refresh(); 56 } else { 57 return this._getValue( true ); 58 } 59 }, 60 61 _setOption: function( key, value ) { 62 this._super( key, value ); 63 if ( key === "mask" ) { 64 this._parseMask(); 65 this._parseValue(); 66 } 67 }, 68 _setOptions: function( options ) { 69 this._super( options ); 70 this._paint(); 71 }, 72 73 // helper function to get or set position of text cursor (caret) 74 _caret: function( begin, end ) { 75 var range, 76 elem = this.element, 77 dom = elem[0]; 78 79 // if begin is defined, we are setting a range 80 if ( begin !== undefined ) { 81 end = ( end === undefined ) ? begin : end; 82 if ( dom.setSelectionRange ) { 83 dom.setSelectionRange( begin, end ); 84 } else if ( dom.createTextRange ) { 85 range = dom.createTextRange(); 86 range.collapse( true ); 87 range.moveEnd( "character", end ); 88 range.moveStart( "character", begin ); 89 range.select(); 90 } 91 } else { 92 93 // begin is undefined, we are reading the range 94 if ( dom.setSelectionRange ) { 95 begin = dom.selectionStart; 96 end = dom.selectionEnd; 97 } else if ( document.selection && document.selection.createRange ) { 98 range = document.selection.createRange(); 99 100 // the moveStart returns the number of characters it moved as a negative number 101 begin = 0 - range.duplicate().moveStart( "character", -100000 ); 102 end = begin + range.text.length; 103 } 104 return { 105 begin: begin, 106 end: end 107 }; 108 } 109 }, 110 _caretSelect: function( bufferPosition ) { 111 var bufferObject = this.buffer[ bufferPosition ]; 112 if ( bufferObject && bufferObject.length > 1 ) { 113 this._caret( bufferObject.start, bufferObject.start + bufferObject.length ); 114 } else { 115 this._caret( bufferPosition ); 116 } 117 }, 118 _getValue: function( raw, focused ) { 119 var bufferPosition, bufferObject, counter, 120 bufferLength = this.buffer.length, 121 value = "", 122 lastValue = 0; 123 124 this.isEmpty = this.isValid = true; 125 for ( bufferPosition = 0; bufferPosition < bufferLength; bufferPosition += bufferObject.length ) { 126 bufferObject = this.buffer[ bufferPosition ]; 127 if ( bufferObject.literal ) { 128 if ( !raw && ( bufferPosition < this.optionalPosition || this.isValid ) ) { 129 value += bufferObject.literal; 130 } 131 } else if ( bufferObject.value ) { 132 lastValue = bufferObject.start + bufferObject.length; 133 this.isEmpty = false; 134 value += bufferObject.value; 135 for ( counter = bufferObject.value.length; counter < bufferObject.length; counter++ ) { 136 value += this.options.placeholder; 137 } 138 } else { 139 if ( !raw ) { 140 for ( counter = bufferObject.length ; counter; counter-- ) { 141 value += this.options.placeholder; 142 } 143 } 144 if ( bufferPosition < this.optionalPosition ) { 145 this.isValid = false; 146 } 147 } 148 } 149 150 // don't display the "optional" portion until the input is "valid" or there are 151 // values past the optional position 152 if ( this.options.clearEmpty && this.isEmpty && focused === false ) { 153 return ""; 154 } 155 156 // strip the optional parts off if we haven't gotten there yet, or there are no values past it 157 // and we aren't focused 158 if ( lastValue <= this.optionalPosition && !( this.isValid && focused ) ) { 159 value = value.substr( 0, this.optionalPosition ); 160 } 161 return value; 162 }, 163 _events: { 164 focus: function() { 165 this.lastUnsavedValue = this.element.val(); 166 this._paint( true ); 167 this._caretSelect( this._seekRight( this._parseValue() ) ); 168 169 this._justFocused = true; 170 this._delay(function(){ 171 this._justFocused = false;
172 }, 100); 173 }, 174 click: function() { 175 // Normally, the call to handle this in the focus event handler would be 176 // sufficient, but Chrome fires the focus events before positioning the 177 // cursor based on where the user clicked (and then fires the click event). 178 179 // We only want to move the caret on clicks that resulted in focus 180 if ( this._justFocused ) { 181 this._caretSelect( this._seekRight( this._parseValue() ) ); 182 this._justFocused = false; 183 } 184 }, 185 blur: function() { 186 this._justFocused = false; 187 188 // because we are constantly setting the value of the input, the change event 189 // never fires - we re-introduce the change event here 190 this._parseValue(); 191 this._paint( false ); 192 if ( this.element.val() !== this.lastUnsavedValue ) { 193 this.element.change(); 194 } 195 }, 196 keydown: function( event ) { 197 var bufferObject, 198 key = event.keyCode, 199 position = this._caret(); 200 201 if ( event.shiftKey || event.metaKey || event.altKey || event.ctrlKey ) { 202 return; 203 } 204 205 206 switch ( key ) { 207 case keyCode.ESCAPE: 208 this.element.val( this.lastUnsavedValue ); 209 this._caretSelect( 0, this._parseValue() ); 210 event.preventDefault(); 211 return; 212 213 case keyCode.BACKSPACE: 214 case keyCode.DELETE: 215 event.preventDefault(); 216 217 // if the caret is not "selecting" values, we need to find the proper 218 // character in the buffer to delete/backspace over. 219 if ( position.begin === position.end || this._isEmpty( position.begin, position.end ) ) { 220 if ( key === keyCode.DELETE ) { 221 position.begin = position.end = this._seekRight( position.begin - 1 ); 222 } else { 223 position.begin = position.end = this._seekLeft( position.begin ); 224 } 225 226 // nothing to backspace 227 if ( position.begin < 0 ) { 228 this._caret( this._seekRight( -1 ) ); 229 return; 230 } 231 } 232 this._removeValues( position.begin, position.end ); 233 this._paint(); 234 this._caretSelect( position.begin ); 235 return; 236 237 case keyCode.LEFT: 238 case keyCode.RIGHT: 239 bufferObject = this.buffer[ position.begin ]; 240 if ( bufferObject && bufferObject.length > 1 ) { 241 bufferObject.value = this._validValue( bufferObject, bufferObject.value ); 242 this._paint(); 243 event.preventDefault(); 244 } 245 if ( key === keyCode.LEFT ) { 246 position = this._seekLeft( bufferObject ? bufferObject.start : position.begin ); 247 } else { 248 position = this._seekRight( bufferObject ? 249 bufferObject.start + bufferObject.length - 1 : 250 position.end ); 251 } 252 this._caretSelect( position ); 253 event.preventDefault(); 254 return; 255 } 256 }, 257 keypress: function( event ) { 258 var tempValue, valid, 259 key = event.which, 260 position = this._caret(), 261 bufferPosition = this._seekRight( position.begin - 1 ), 262 bufferObject = this.buffer[ bufferPosition ]; 263 264 // ignore keypresses with special keys, or control characters 265 if ( event.metaKey || event.altKey || event.ctrlKey || key < 32 ) { 266 return; 267 } 268 if ( position.begin !== position.end ) { 269 this._removeValues( position.begin, position.end ); 270 } 271 if ( bufferObject ) { 272 tempValue = String.fromCharCode( key ); 273 if ( bufferObject.length > 1 && bufferObject.value ) { 274 tempValue = bufferObject.value.substr( 0, bufferPosition - bufferObject.start ) + 275 tempValue + 276 bufferObject.value.substr( bufferPosition - bufferObject.start + 1 ); 277 tempValue = tempValue.substr( 0, bufferObject.length ); 278 } 279 valid = this._validValue( bufferObject, tempValue ); 280 if ( valid ) { 281 this._shiftRight( position.begin ); 282 bufferObject.value = tempValue; 283 position = this._seekRight( bufferPosition ); 284 if ( position <= bufferObject.start + bufferObject.length ) { 285 this._paint(); 286 this._caret( position ); 287 } else { 288 bufferObject.value = valid; 289 this._paint(); 290 this._caretSelect( position ); 291 } 292 } 293 } 294 event.preventDefault(); 295 }, 296 paste: "_paste", 297 input: "_paste" 298 }, 299 _isEmpty: function( begin, end ) { 300 var index; 301 if ( begin === undefined ) { 302 begin = 0; 303 end = this.buffer.length - 1; 304 } else if ( end === undefined ) { 305 end = begin; 306 } 307 for ( index = begin; index <= end; index++ ) { 308 if ( this.buffer[ index ] && this.buffer[ index ].value ) { 309 return false;
310 } 311 } 312 return true; 313 }, 314 _paste: function() { 315 this._delay( function() { 316 var position = this._parseValue(); 317 this._paint(); 318 this._caret( this._seekRight( position ) ); 319 }, 0 ); 320 }, 321 _paint: function( focused ) { 322 if ( focused === undefined ) { 323 focused = this.element[ 0 ] === document.activeElement; 324 } 325 this.element.val( this._getValue( false, focused ) ); 326 }, 327 _addBuffer: function( bufferObject ) { 328 var x, 329 begin = bufferObject.start, 330 end = bufferObject.start + bufferObject.length; 331 332 for ( x = begin; x < end; x++ ) { 333 if ( this.buffer[ x ] !== undefined ) { 334 return false; 335 } 336 } 337 338 for ( x = begin; x < end; x++ ) { 339 this.buffer[ x ] = bufferObject; 340 } 341 342 return true; 343 }, 344 _removeCharacter: function( mask, index ) { 345 var x, bufferObject; 346 347 for ( x = index ; x < mask.length - 1 ; x++ ) { 348 bufferObject = this.buffer[ x + 1 ]; 349 this.buffer[ x ] = bufferObject; 350 if ( bufferObject !== undefined ) { 351 bufferObject.start = bufferObject.start - 1; 352 x += bufferObject.length - 1; 353 } 354 } 355 this.buffer.splice( x, 1 ); 356 357 if ( this.optionalPosition > index ) { 358 this.optionalPosition--; 359 } 360 361 return mask.substring( 0, index ) + mask.substring( index + 1 ); 362 }, 363 _parseMask: function() { 364 var key, x, optionalPosition, 365 index = -1, 366 options = this.options, 367 mask = options.mask, 368 reservedChars = [ "a", "9", "*", "?", "<", ">", "\\" ]; 369 370 this.buffer = []; 371 if ( !mask ) { 372 return; 373 } 374 375 // search for escaped reserved characters 376 for ( index = 0 ; index < mask.length - 1 ; index++ ) { 377 if ( mask.charAt( index ) === "\\" && 378 $.inArray( mask.charAt( index + 1 ), reservedChars ) !== -1 ) { 379 // remove escape character 380 mask = mask.substring( 0, index ) + mask.substring( index + 1 ); 381 382 this._addBuffer({ 383 start: index, 384 literal: mask.charAt( index ), 385 length: 1 386 }); 387 } 388 } 389 // locate unescaped optional markers ; use attention to the first, remove all others 390 optionalPosition = -1; 391 this.optionalPosition = undefined; 392 while ( ( optionalPosition = mask.indexOf( "?", optionalPosition + 1 ) ) > -1 ) { 393 if ( this.buffer[ optionalPosition ] === undefined ) { 394 if ( this.optionalPosition === undefined ) { 395 this.optionalPosition = optionalPosition; 396 } 397 398 // remove the ? from the mask 399 mask = this._removeCharacter( mask, optionalPosition ); 400 } 401 } 402 if ( this.optionalPosition === undefined ) { 403 this.optionalPosition = mask.length; 404 } 405 406 // search for strictly definied "masks" 407 for ( x = 0 ; x < mask.length ; x++ ) { 408 if ( mask.charAt(x) === "<" ) { 409 index = x; 410 for ( ; x < mask.length ; x++ ) { 411 if ( mask.charAt(x) === ">" ) { 412 key = mask.substring( index + 1 , x ); 413 if ( options.definitions[key] !== undefined ) { 414 if (this._addBuffer({ 415 start: index + 1, 416 length: key.length, 417 valid: options.definitions[ key ] 418 })) { 419 mask = this._removeCharacter( mask, x ); 420 mask = this._removeCharacter( mask, index ); 421 for ( x = index ; x < index + key.length ; x++ ) { 422 mask[x] = " "; 423 } 424 } 425 } 426 break; 427 } 428 } 429 } 430 } 431 432 // search for definied "masks" 433 index = -1; 434 for ( key in options.definitions ) { 435 while ( ( index = mask.indexOf( key, index + 1 ) ) > -1 ) { 436 this._addBuffer({ 437 start: index, 438 length: key.length, 439 valid: options.definitions[ key ] 440 }); 441 } 442 } 443 444 // anything we didn't find is a literal 445 for ( index = 0 ; index < mask.length ; index++ ) { 446 this._addBuffer({ 447 start: index, 448 literal: mask.charAt( index ), 449 length: 1 450 }); 451 } 452 }, 453 454 // parses the .val() and places it into the buffer 455 // returns the last filled in value position 456 _parseValue: function() { 457 var bufferPosition, bufferObject, character, 458 valuePosition = 0, 459 lastFilledPosition = -1, 460 value = this.element.val(), 461 bufferLength = this.buffer.length; 462 463 // remove all current values from the buffer 464 this._removeValues( 0, bufferLength ); 465 466 // seek through the buffer pulling characters from the value 467 for ( bufferPosition = 0; bufferPosition < bufferLength; bufferPosition += bufferObject.length ) { 468 bufferObject = this.buffer[ bufferPosition ]; 469 470 while ( valuePosition < value.length ) { 471 character = value.substr( valuePosition, bufferObject.length ); 472 if ( bufferObject.literal ) {
473 if ( this._validValue( bufferObject, character ) ) { 474 valuePosition++; 475 } 476 477 // when parsing a literal from a raw .val() if it doesn't match, 478 // assume that the literal is missing from the val() 479 break; 480 } 481 valuePosition++; 482 character = this._validValue( bufferObject, character ); 483 if ( character ) { 484 bufferObject.value = character; 485 lastFilledPosition = bufferPosition + bufferObject.length - 1; 486 valuePosition += bufferObject.length - 1; 487 break; 488 } 489 } 490 491 // allow "default values" to be passed back from the buffer functions 492 if ( !bufferObject.value && (character = this._validValue( bufferObject, "" )) ) { 493 bufferObject.value = character; 494 } 495 } 496 return lastFilledPosition; 497 }, 498 _removeValues: function( begin, end ) { 499 var position, bufferObject; 500 for ( position = begin; position <= end; position++ ) { 501 bufferObject = this.buffer[ position ]; 502 if ( bufferObject && bufferObject.value ) { 503 delete bufferObject.value; 504 } 505 } 506 this._shiftLeft( begin, end + 1 ); 507 return this; 508 }, 509 510 // _seekLeft and _seekRight will tell the next non-literal position in the buffer 511 _seekLeft: function( position ) { 512 while ( --position >= 0 ) { 513 if ( this.buffer[ position ] && !this.buffer[ position ].literal ) { 514 return position; 515 } 516 } 517 return -1; 518 }, 519 _seekRight: function( position ) { 520 var length = this.buffer.length; 521 while ( ++position < length ) { 522 if ( this.buffer[ position ] && !this.buffer[ position ].literal ) { 523 return position; 524 } 525 } 526 527 return length; 528 }, 529 530 // _shiftLeft and _shiftRight will move values in the buffer over to the left/right 531 _shiftLeft: function( begin, end ) { 532 var bufferPosition, 533 bufferObject, 534 destPosition, 535 destObject, 536 bufferLength = this.buffer.length; 537 538 for ( destPosition = begin, bufferPosition = this._seekRight( end - 1 ); 539 destPosition < bufferLength; 540 destPosition += destObject.length ) { 541 destObject = this.buffer[ destPosition ]; 542 bufferObject = this.buffer[ bufferPosition ]; 543 544 // we don't want to shift values into multi character fields 545 if ( destObject.valid && destObject.length === 1 ) { 546 if ( bufferPosition < bufferLength ) { 547 if ( this._validValue( destObject, bufferObject.value ) ) { 548 destObject.value = bufferObject.value; 549 delete bufferObject.value; 550 bufferPosition = this._seekRight( bufferPosition ); 551 } else { 552 553 // once we find a value that doesn't fit anymore, we stop this shift 554 break; 555 } 556 } 557 } 558 } 559 }, 560 _shiftRight: function ( bufferPosition ) { 561 var bufferObject, 562 temp, 563 shiftingValue = false, 564 bufferLength = this.buffer.length; 565 566 bufferPosition--; 567 while ( ( bufferPosition = this._seekRight( bufferPosition ) ) < bufferLength ) 568 { 569 bufferObject = this.buffer[ bufferPosition ]; 570 if ( shiftingValue === false ) { 571 shiftingValue = bufferObject.value; 572 } else { 573 574 // we don't want to shift values into multi character fields 575 if ( bufferObject.length === 1 && this._validValue( bufferObject, shiftingValue ) ) { 576 temp = bufferObject.value; 577 bufferObject.value = shiftingValue; 578 shiftingValue = temp; 579 } else { 580 return; 581 } 582 } 583 } 584 }, 585 586 // returns the value if valid, otherwise returns false 587 _validValue: function( bufferObject, value ) { 588 if ( bufferObject.valid ) { 589 if ( $.isFunction( bufferObject.valid ) ) { 590 return bufferObject.valid( value || "" ) || false; 591 } 592 return bufferObject.valid.test( value ) && value; 593 } 594 return ( bufferObject.literal === value ) && value; 595 } 596}); 597 598}( 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.