1/* 2 * jQuery UI Mask @VERSION 3 * 4 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) 5 * Dual licensed under the MIT (MIT-LICENSE.txt) 6 * and GPL (GPL-LICENSE.txt) licenses. 7 * 8 * Based on the jquery.maskedinput.js plugin by Josh Bush (digitalbush.com) 9 * 10 * http://docs.jquery.com/UI/Mask 11 * 12 * Depends: 13 * ui.core.js 14 */ 15(function($) { 16 17var pasteEventName = ($.browser.msie ? 'paste' : 'input') + ".mask"; 18 19$.widget("ui.mask", { 20 21 _init: function() { 22 23 var options = this.options, self = this; 24 25 $.extend(this, { caret: function(begin, end){ return $.ui.mask.caret(self.element, begin, end); } }); 26 27 if(!options.mask || !options.mask.length){ return; } //no mask pattern defined. no point in continuing. 28 if(!options.placeholder || !options.placeholder.length){ 29 options.placeholder = '_'; //in case the user decided to nix a placeholder. 30 } 31 32 this._prepareBuffer(); 33 this._bindEvents(); 34 this._checkVal((this.element.val().length && options.allowPartials)); //Perform initial check for existing values 35 }, 36 37 destroy: function() { 38 this.element 39 .unbind('.mask') 40 .removeData('mask'); 41 }, 42 43 value: function() { 44 var input = this.element, 45 self = this, 46 res = $.map(self.buffer, function(c, i){ return self.tests[i] ? c : null; }).join(''), 47 r = new RegExp('\\'+this.options.placeholder, 'gi'); 48 return res.replace(r, ''); 49 }, 50 51 formatted: function(){ 52 var r = new RegExp('\\'+this.options.placeholder, 'gi'), 53 res = this.element.val(); 54 return res.replace(r, ''); 55 }, 56 57 apply: function(){ 58 this.element.trigger('apply.mask'); 59 }, 60 61 _setData: function(key, value) { 62 63 $.widget.prototype._setData.apply(this, arguments); 64 var options = this.options; 65 66 switch (key) { 67 case 'mask': 68 //no mask pattern defined. no point in continuing. 69 if(!options.mask || !options.mask.length){ 70 this.element.unbind('.mask') 71 break; 72 } 73 case 'placeholder': 74 if(!options.placeholder || !options.placeholder.length){ 75 options.placeholder = '_'; //in case the user decided to nix a placeholder. 76 } 77 this.element.val(''); 78 this._prepareBuffer(); 79 !this.eventsBound && this._bindEvents(); 80 break; 81 } 82 83 }, 84 85 _prepareBuffer: function(){ 86 87 this._escapeMask(); 88 89 var self = this, 90 input = this.element, 91 options = this.options, 92 mask = options.mask, 93 defs = $.ui.mask.definitions, 94 tests = [], 95 partialPosition = mask.length, 96 firstNonMaskPos = null, 97 len = mask.length; 98 99 //if we're applying the mask to an element which is not an input, it won't have a val() method. fake one for our purposes. 100 if(!input.is(':input')) input.val = input.html; 101 102 $.each(mask.split(""), function(i, c) { 103 if (c == '?') { 104 len--; 105 partialPosition = i; 106 } 107 else if (defs[c]){ 108 tests.push(new RegExp(defs[c])); 109 if(firstNonMaskPos==null) 110 firstNonMaskPos = tests.length - 1; 111 } 112 else{ 113 tests.push(null); 114 } 115 }); 116 117 $.extend(this, { 118 buffer: $.map(mask.split(""), function(c, i){ 119 if (c != '?'){ 120 return defs[c] ? options.placeholder : c; 121 } 122 }), 123 tests: tests, 124 firstNonMaskPos: firstNonMaskPos, 125 partialPosition: partialPosition 126 }); 127 128 this.buffer = $.map(this.buffer, function(c, i){ 129 if(c == "\t"){ 130 return self.maskEscaped[i]; 131 } 132 return c; 133 }); 134 135 this.options.mask = mask = this.maskEscaped; 136 }, 137 138 _bindEvents: function(){ 139 140 var self = this, 141 input = this.element, 142 ignore = false, //Variable for ignoring control keys 143 focusText = input.val(); 144 145 function keydownEvent(e) { 146 e = e || window.event; 147 var pos = self.caret(), 148 k = e.keyCode,
149 keyCode = $.ui.keyCode; 150 151 ignore = (k < keyCode.SHIFT || (k > keyCode.SHIFT && k < keyCode.SPACE) || (k > keyCode.SPACE && k < 41)); 152 153 //delete selection before proceeding 154 if ((pos.begin - pos.end) != 0 && (!ignore || k == keyCode.BACKSPACE || k == keyCode.DELETE)) 155 self._clearBuffer(pos.begin, pos.end); 156 157 //backspace, delete, and escape get special treatment 158 if (k == keyCode.BACKSPACE || k == keyCode.DELETE) {//backspace/delete 159 self._shiftL(pos.begin + ((k == keyCode.DELETE || (k == keyCode.BACKSPACE && pos.begin!=pos.end)) ? 0 : -1), Math.abs(pos.begin - pos.end)); 160 return false; 161 } 162 else if (k == keyCode.ESCAPE) {//escape 163 input.val(focusText); 164 self.caret(0, self._checkVal()); 165 return false; 166 } 167 }; 168 169 function keypressEvent(e) { 170 171 e = e || window.event; 172 173 var k = e.charCode || e.keyCode || e.which, 174 keyCode = $.ui.keyCode, 175 len = self.options.mask.length; 176 177 if (ignore) { 178 ignore = false; 179 //Fixes Mac FF bug on backspace 180 return (e.keyCode == keyCode.BACKSPACE) ? false : null; 181 } 182 183 var pos = self.caret(); 184 185 if (e.ctrlKey || e.altKey || e.metaKey) {//Ignore 186 return true; 187 } 188 else if ((k >= keyCode.SPACE && k <= 125) || k > 186) {//typeable characters 189 var p = self._seekNext(pos.begin - 1); 190 if (p < len) { 191 var c = String.fromCharCode(k); 192 if (self.tests[p] && self.tests[p].test(c)) { 193 self._shiftR(p); 194 self.buffer[p] = c; 195 self._writeBuffer(); 196 var next = self._seekNext(p); 197 self.caret(next); 198 self.options.completed && next == len && self.options.completed.call(input); 199 } 200 } 201 } 202 return false; 203 }; 204 205 if (!input.attr("readonly")){ 206 input 207 .bind("focus.mask", function() { 208 focusText = input.val(); 209 var pos = 0;//self._checkVal(); 210 self._writeBuffer(); 211 setTimeout(function() { 212 if (pos == self.options.mask.length) 213 self.caret(0, pos); 214 else 215 self.caret(pos); 216 }, 0); 217 }) 218 .bind("blur.mask", function() { 219 //self._checkVal(); 220 if (input.val() != focusText) 221 input.change(); 222 }) 223 .bind('apply.mask', function(){ //changing the value of an input without keyboard input requires re-applying the mask. 224 focusText = input.val(); 225 var pos = self._checkVal(); 226 self._writeBuffer(); 227 }) 228 .bind("keydown.mask", keydownEvent) 229 .bind("keypress.mask", keypressEvent) 230 .bind(pasteEventName, function() { 231 setTimeout(function() { self.caret(self._checkVal(true)); }, 0); 232 }); 233 this.eventsBound = true; 234 } 235 }, 236 237 _writeBuffer: function(){ 238 return this.element.val(this.buffer.join('')).val(); 239 }, 240 241 _clearBuffer: function(start, end){ 242 var len = this.options.mask.length; 243 for (var i = start; i < end && i < len; i++) { 244 if (this.tests[i]) 245 this.buffer[i] = this.options.placeholder; 246 } 247 }, 248 249 _seekNext: function(pos){ 250 var len = this.options.mask.length; 251 while (++pos <= len && !this.tests[pos]); 252 return pos; 253 }, 254 255 _shiftR: function(pos){ 256 var len = this.options.mask.length; 257 for (var i = pos, c = this.options.placeholder; i < len; i++) { 258 if (this.tests[i]) { 259 var j = this._seekNext(i); 260 var t = this.buffer[i]; 261 this.buffer[i] = c; 262 if (j < len && this.tests[j].test(t)){ 263 c = t; 264 } 265 else{ 266 break; 267 } 268 } 269 } 270 }, 271 272 _shiftL: function(pos, length){ 273 274 while (!this.tests[pos] && --pos >= 0); 275 276 var originalPos = pos, 277 len = this.options.mask.length, 278 placeholder = this.options.placeholder; 279 280 for(var i = pos; i < len && (i >= 0 || length > 1); i++) { 281 if (this.tests[i]) { 282 this.buffer[i] = placeholder; 283 var j = this._seekNext(i); 284 if (j < len && this.tests[i].test(this.buffer[j])) { 285 this.buffer[pos] = this.buffer[j]; 286 this.buffer[j] = placeholder; 287 pos++; 288 while(!this.tests[pos]) pos++; 289 } 290 } 291 } 292 this._writeBuffer(); 293 this.caret(Math.max(this.firstNonMaskPos, originalPos)); 294 }, 295 296 _checkVal: function(allow){ 297 //try to place characters where they belong 298 var input = this.element, 299 test = input.val(), 300 len = this.options.mask.length, 301 lastMatch = -1; 302 303 for (var i = 0, pos = 0; i < len; i++) { 304 if (this.tests[i]) { 305 this.buffer[i] = this.options.placeholder; 306 while (pos++ < test.length) { 307 var c = test.charAt(pos - 1); 308 if (this.tests[i].test(c)) { 309 this.buffer[i] = c; 310 lastMatch = i; 311 break; 312 } 313 } 314 if (pos > test.length) 315 break; 316 } 317 else if (this.buffer[i] == test[pos] && i != this.partialPosition) { 318 pos++; 319 lastMatch = i; 320 } 321 } 322 if (!allow && lastMatch + 1 < this.partialPosition) { 323 if(!this.options.allowPartials || !this.value().length){ 324 input.val(""); 325 this._clearBuffer(0, len); 326 } 327 else //if we're allowing partial input/inital values, and the element we're masking isnt an input, then we need to allow the mask to apply. 328 if(!input.is(':input')) this._writeBuffer(); 329 330 } 331 else if (allow || lastMatch + 1 >= this.partialPosition) { 332 this._writeBuffer(); 333 if (!allow) input.val(input.val().substring(0, lastMatch + 1)); 334 } 335 return (this.partialPosition ? i : this.firstNonMaskPos);
336 }, 337 338 _escapeMask: function(){ 339 var mask = this.options.mask, 340 literals = [], 341 replacements = []; 342 343 for(var i = 0; i < mask.length; i++){ 344 var c, temp = mask[i] || mask.charAt(i); 345 if(temp != "\\" || mask[i-1] == "\\"){ 346 if(mask[i-1] == "\\"){ 347 c = "\t"; 348 replacements[literals.length] = temp; 349 } 350 else{ 351 c = temp; 352 } 353 literals[literals.length] = c; 354 } 355 } 356 357 this.options.mask = literals.join(''); 358 359 for(var i = 0; i < literals.length; i++){ 360 if(replacements[i] !== undefined){ 361 literals[i] = replacements[i]; 362 } 363 } 364 365 this.maskEscaped = literals.join(''); 366 } 367 368}); 369 370$.extend($.ui.mask, { 371 version: "@VERSION", 372 getter: "value formatted", 373 defaults: { 374 mask: '', 375 placeholder: '_', 376 completed: null, 377 allowPartials: false 378 }, 379 definitions: { //Predefined character definitions 380 '#': "[\\d]", 381 'a': "[A-Za-z]", 382 '*': "[A-Za-z0-9]" 383 }, 384 caret: function(element, begin, end) { //Helper Function for Caret positioning 385 var input = element[0]; 386 if (typeof begin == 'number') { 387 end = (typeof end == 'number') ? end : begin; 388 if (input.setSelectionRange) { 389 input.focus(); 390 input.setSelectionRange(begin, end); 391 } else if (input.createTextRange) { 392 var range = input.createTextRange(); 393 range.collapse(true); 394 range.moveEnd('character', end); 395 range.moveStart('character', begin); 396 range.select(); 397 } 398 return element; 399 } else { 400 if (input.setSelectionRange) { 401 begin = input.selectionStart; 402 end = input.selectionEnd; 403 } 404 else if (document.selection && document.selection.createRange) { 405 var range = document.selection.createRange(); 406 begin = 0 - range.duplicate().moveStart('character', -100000); 407 end = begin + range.text.length; 408 } 409 return { begin: begin, end: end }; 410 } 411 } 412}); 413 414})(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.