1(function ($) { 2 "use strict"; 3 if (!$.browser) { 4 $.browser = {}; 5 $.browser.mozilla = /mozilla/.test(navigator.userAgent.toLowerCase()) && !/webkit/.test(navigator.userAgent.toLowerCase()); 6 $.browser.webkit = /webkit/.test(navigator.userAgent.toLowerCase()); 7 $.browser.opera = /opera/.test(navigator.userAgent.toLowerCase()); 8 $.browser.msie = /msie/.test(navigator.userAgent.toLowerCase()); 9 $.browser.device = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()); 10 } 11 12 var defaultOptions = { 13 prefix: "", 14 suffix: "", 15 affixesStay: true, 16 thousands: ".", 17 decimal: ",", 18 precision: 2, 19 allowZero: false, 20 allowNegative: false, 21 doubleClickSelection: true, 22 allowEmpty: false, 23 bringCaretAtEndOnFocus: true 24 }, 25 methods = { 26 destroy: function () { 27 $(this).unbind(".maskMoney"); 28 29 if ($.browser.msie) { 30 this.onpaste = null; 31 } 32 return this; 33 }, 34 35 applyMask: function (value) { 36 var $input = $(this); 37 // data-* api 38 var settings = $input.data("settings"); 39 return maskValue(value, settings); 40 }, 41 42 mask: function (value) { 43 return this.each(function () { 44 var $this = $(this); 45 if (typeof value === "number") { 46 $this.val(value); 47 } 48 return $this.trigger("mask"); 49 }); 50 }, 51 52 unmasked: function () { 53 return this.map(function () { 54 var value = ($(this).val() || "0"), 55 isNegative = value.indexOf("-") !== -1, 56 decimalPart; 57 // get the last position of the array that is a number(coercion makes "" to be evaluated as false) 58 $(value.split(/\D/).reverse()).each(function (index, element) { 59 if (element) { 60 decimalPart = element; 61 return false; 62 } 63 }); 64 value = value.replace(/\D/g, ""); 65 value = value.replace(new RegExp(decimalPart + "$"), "." + decimalPart); 66 if (isNegative) { 67 value = "-" + value; 68 } 69 return parseFloat(value); 70 }); 71 }, 72 73 unmaskedWithOptions: function () { 74 return this.map(function () { 75 var value = ($(this).val() || "0"), 76 settings = $(this).data("settings") || defaultOptions, 77 regExp = new RegExp((settings.thousandsForUnmasked || settings.thousands), "g"); 78 value = value.replace(regExp, ""); 79 return parseFloat(value); 80 }); 81 }, 82 83 init: function (parameters) { 84 // the default options should not be shared with others 85 parameters = $.extend($.extend({}, defaultOptions), parameters); 86 87 return this.each(function () { 88 var $input = $(this), 89 settings, 90 onFocusValue; 91 92 // data-* api 93 settings = $.extend({}, parameters); 94 settings = $.extend(settings, $input.data()); 95 96 // Store settings for use with the applyMask method. 97 $input.data("settings", settings); 98 99 100 function getInputSelection() { 101 var el = $input.get(0), 102 start = 0, 103 end = 0, 104 normalizedValue, 105 range, 106 textInputRange, 107 len, 108 endRange; 109 110 if (typeof el.selectionStart === "number" && typeof el.selectionEnd === "
110number") { 111 start = el.selectionStart; 112 end = el.selectionEnd; 113 } else { 114 range = document.selection.createRange(); 115 116 if (range && range.parentElement() === el) { 117 len = el.value.length; 118 normalizedValue = el.value.replace(/\r\n/g, "\n"); 119 120 // Create a working TextRange that lives only in the input 121 textInputRange = el.createTextRange(); 122 textInputRange.moveToBookmark(range.getBookmark()); 123 124 // Check if the start and end of the selection are at the very end 125 // of the input, since moveStart/moveEnd doesn't return what we want 126 // in those cases 127 endRange = el.createTextRange(); 128 endRange.collapse(false); 129 130 if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { 131 start = end = len; 132 } else { 133 start = -textInputRange.moveStart("character", -len); 134 start += normalizedValue.slice(0, start).split("\n").length - 1; 135 136 if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) { 137 end = len; 138 } else { 139 end = -textInputRange.moveEnd("character", -len); 140 end += normalizedValue.slice(0, end).split("\n").length - 1; 141 } 142 } 143 } 144 } 145 146 return { 147 start: start, 148 end: end 149 }; 150 } // getInputSelection 151 152 function canInputMoreNumbers() { 153 var haventReachedMaxLength = !($input.val().length >= $input.attr("maxlength") && $input.attr("maxlength") >= 0), 154 selection = getInputSelection(), 155 start = selection.start, 156 end = selection.end, 157 haveNumberSelected = (selection.start !== selection.end && $input.val().substring(start, end).match(/\d/)) ? true : false, 158 startWithZero = ($input.val().substring(0, 1) === "0"); 159 return haventReachedMaxLength || haveNumberSelected || startWithZero; 160 } 161 162 function setCursorPosition(pos) { 163 // Do not set the position if 164 // the we're formatting on blur. 165 // This is because we do not want 166 // to refocus on the control after 167 // the blur. 168 if (!!settings.formatOnBlur) { 169 return; 170 } 171 172 $input.each(function (index, elem) { 173 if (elem.setSelectionRange) { 174 elem.focus(); 175 elem.setSelectionRange(pos, pos); 176 } else if (elem.createTextRange) { 177 var range = elem.createTextRange(); 178 range.collapse(true); 179 range.moveEnd("character", pos); 180 range.moveStart("character", pos); 181 range.select(); 182 } 183 }); 184 } 185 186 function maskAndPosition(startPos) { 187 var originalLen = $input.val().length, 188 newLen; 189 $input.val(maskValue($input.val(), settings)); 190 newLen = $input.val().length; 191 // If the we're using the reverse option, 192 // do not put the cursor at the end of 193 // the input. The reverse option allows 194 // the user to input text from left to right. 195 if (!settings.reverse) { 196 startPos = startPos - (originalLen - newLen); 197 } 198 setCursorPosition(startPos); 199 } 200 201 function mask() { 202 var value = $input.val(); 203 if (settings.allowEmpty && value === "") { 204 return; 205 } 206 var isNumber = !isNaN(value); 207 var decimalPointIndex = isNumber ? value.indexOf(".") : value.indexOf(settings.decimal); 208 if (settings.precision > 0) { 209 if (decimalPointIndex < 0) { 210 value += settings.decimal + new Array(settings.precision + 1).join(0); 211 } else { 212 // If the following decimal part dosen't have enough length against the precision, it needs to be filled with zeros. 213 var integerPart = value.slice(0, decimalPointIndex), 214 decimalPart = value.slice(decimalPointIndex + 1); 215 value = integerPart + settings.decimal + decimalPart + 216 new Array((settings.precision + 1) - decimalPart.length).join(0); 217 } 218 } else if (decimalPointIndex > 0) { 219 // if the precision is 0, discard the decimal part 220 value = value.slice(0, decimalPointIndex); 221 } 222 $input.val(maskValue(value, settings)); 223 } 224 225 function changeSign() { 226 var inputValue = $input.val(); 227 if (settings.allowNegative) { 228 if (inputValue !== "" && inputValue.charAt(0) === "-") { 229 return inputValue.replace("-", ""); 230 } else { 231 return "-" + inputValue; 232 } 233 } else { 234 return inputValue; 235 } 236 } 237 238 function preventDefault(e) { 239 if (e.preventDefault) { //standard browsers 240 e.preventDefault(); 241 } else { // old internet explorer 242 e.returnValue = false;
243 } 244 } 245 246 function fixMobile() { 247 if ($.browser.device) { 248 $input.attr("type", "tel"); 249 // $input.attr("type", "tel"); 250 } 251 } 252 253 function keypressEvent(e) { 254 e = e || window.event; 255 var key = e.which || e.charCode || e.keyCode, 256 decimalKeyCode = settings.decimal.charCodeAt(0); 257 //added to handle an IE "special" event 258 if (key === undefined) { 259 return false; 260 } 261 262 // any key except the numbers 0-9. if we're using settings.reverse, 263 // allow the user to input the decimal key 264 if ((key < 48 || key > 57) && (key !== decimalKeyCode || !settings.reverse)) { 265 return handleAllKeysExceptNumericalDigits(key, e); 266 } else if (!canInputMoreNumbers()) { 267 return false; 268 } else { 269 if (key === decimalKeyCode && shouldPreventDecimalKey()) { 270 return false; 271 } 272 if (settings.formatOnBlur) { 273 return true; 274 } 275 preventDefault(e); 276 applyMask(e); 277 return false; 278 } 279 } 280 281 function shouldPreventDecimalKey() { 282 // If all text is selected, we can accept the decimal 283 // key because it will replace everything. 284 if (isAllTextSelected()) { 285 return false; 286 } 287 288 return alreadyContainsDecimal(); 289 } 290 291 function isAllTextSelected() { 292 var length = $input.val().length; 293 var selection = getInputSelection(); 294 // This should if all text is selected or if the 295 // input is empty. 296 return selection.start === 0 && selection.end === length; 297 } 298 299 function alreadyContainsDecimal() { 300 return $input.val().indexOf(settings.decimal) > -1; 301 } 302 303 function applyMask(e) { 304 e = e || window.event; 305 var key = e.which || e.charCode || e.keyCode, 306 keyPressedChar = "", 307 selection, 308 startPos, 309 endPos, 310 value; 311 if (key >= 48 && key <= 57) { 312 keyPressedChar = String.fromCharCode(key); 313 } 314 selection = getInputSelection(); 315 startPos = selection.start; 316 endPos = selection.end; 317 value = $input.val(); 318 $input.val(value.substring(0, startPos) + keyPressedChar + value.substring(endPos, value.length)); 319 maskAndPosition(startPos + 1); 320 } 321 322 function handleAllKeysExceptNumericalDigits(key, e) { 323 // -(minus) key 324 if (key === 45) { 325 $input.val(changeSign()); 326 return false; 327 // +(plus) key 328 } else if (key === 43) { 329 $input.val($input.val().replace("-", "")); 330 return false; 331 // enter key or tab key 332 } else if (key === 13 || key === 9) { 333 return true; 334 } else if ($.browser.mozilla && (key === 37 || key === 39) && e.charCode === 0) { 335 // needed for left arrow key or right arrow key with firefox 336 // the charCode part is to avoid allowing "%"(e.charCode 0, e.keyCode 37) 337 return true; 338 } else { // any other key with keycode less than 48 and greater than 57 339 preventDefault(e); 340 return true; 341 } 342 } 343 344 function keydownEvent(e) { 345 e = e || window.event; 346 var key = e.which || e.charCode || e.keyCode, 347 selection, 348 startPos, 349 endPos, 350 value, 351 lastNumber; 352 //needed to handle an IE "special" event 353 if (key === undefined) { 354 return false;
355 } 356 357 selection = getInputSelection(); 358 startPos = selection.start; 359 endPos = selection.end; 360 361 if (key === 8 || key === 46 || key === 63272) { // backspace or delete key (with special case for safari) 362 preventDefault(e); 363 364 value = $input.val(); 365 366 // not a selection 367 if (startPos === endPos) { 368 // backspace 369 if (key === 8) { 370 if (settings.suffix === "") { 371 startPos -= 1; 372 } else { 373 // needed to find the position of the last number to be erased 374 lastNumber = value.split("").reverse().join("").search(/\d/); 375 startPos = value.length - lastNumber - 1; 376 endPos = startPos + 1; 377 } 378 //delete 379 } else { 380 endPos += 1; 381 } 382 } 383 384 $input.val(value.substring(0, startPos) + value.substring(endPos, value.length)); 385 386 maskAndPosition(startPos); 387 return false; 388 } else if (key === 9) { // tab key 389 return true; 390 } else { // any other key 391 return true; 392 } 393 } 394 395 function focusEvent() { 396 onFocusValue = $input.val(); 397 mask(); 398 var input = $input.get(0), 399 textRange; 400 401 if (!!settings.selectAllOnFocus) { 402 input.select(); 403 } else if (input.createTextRange && settings.bringCaretAtEndOnFocus) { 404 textRange = input.createTextRange(); 405 textRange.collapse(false); // set the cursor at the end of the input 406 textRange.select(); 407 } 408 } 409 410 function cutPasteEvent() { 411 setTimeout(function () { 412 mask(); 413 }, 0); 414 } 415 416 function getDefaultMask() { 417 var n = parseFloat("0") / Math.pow(10, settings.precision); 418 return (n.toFixed(settings.precision)).replace(new RegExp("\\.", "g"), settings.decimal); 419 } 420 421 function blurEvent(e) { 422 if ($.browser.msie) { 423 keypressEvent(e); 424 } 425 426 if (!!settings.formatOnBlur && $input.val() !== onFocusValue) { 427 applyMask(e); 428 } 429 430 if ($input.val() === "" && settings.allowEmpty) { 431 $input.val(""); 432 } else if ($input.val() === "" || $input.val() === setSymbol(getDefaultMask(), settings)) { 433 if (!settings.allowZero) { 434 $input.val(""); 435 } else if (!settings.affixesStay) { 436 $input.val(getDefaultMask()); 437 } else { 438 $input.val(setSymbol(getDefaultMask(), settings)); 439 } 440 } else { 441 if (!settings.affixesStay) { 442 var newValue = $input.val().replace(settings.prefix, "").replace(settings.suffix, ""); 443 $input.val(newValue); 444 } 445 } 446 if ($input.val() !== onFocusValue) { 447 $input.change(); 448 } 449 } 450 451 function clickEvent() { 452 var input = $input.get(0), 453 length; 454 if (!!settings.selectAllOnFocus) { 455 // selectAllOnFocus will be handled by 456 // the focus event. The focus event is 457 // also fired when the input is clicked. 458 return; 459 } else if (input.setSelectionRange && settings.bringCaretAtEndOnFocus) { 460 length = $input.val().length; 461 input.setSelectionRange(length, length); 462 } else { 463 $input.val($input.val()); 464 } 465 } 466 467 function doubleClickEvent() { 468 var input = $input.get(0), 469 start, 470 length; 471 if (input.setSelectionRange && settings.bringCaretAtEndOnFocus) { 472 length = $input.val().length; 473 start = settings.doubleClickSelection ? 0 : length; 474 input.setSelectionRange(start, length); 475 } else { 476 $input.val($input.val()); 477 } 478 } 479 480 fixMobile(); 481 $input.unbind(".maskMoney"); 482 $input.bind("keypress.maskMoney", keypressEvent); 483 $input.bind("keydown.maskMoney", keydownEvent); 484 $input.bind("blur.maskMoney", blurEvent); 485 $input.bind("focus.maskMoney", focusEvent); 486 $input.bind("click.maskMoney", clickEvent); 487 $input.bind("dblclick.maskMoney", doubleClickEvent); 488 $input.bind("cut.maskMoney", cutPasteEvent); 489 $input.bind("paste.maskMoney", cutPasteEvent); 490 $input.bind("mask.maskMoney", mask); 491 }); 492 } 493 }; 494 495 function setSymbol(value, settings) { 496 var operator = ""; 497 if (value.indexOf("-") > -1) { 498 value = value.replace("-", ""); 499 operator = "-"; 500 } 501 if (value.indexOf(settings.prefix) > -1) { 502 value = value.replace(settings.prefix, ""); 503 } 504 if (value.indexOf(settings.suffix) > -1) { 505 value = value.replace(settings.suffix, ""); 506 } 507 return operator + settings.prefix + value + settings.suffix; 508 } 509 510 function maskValue(value, settings) { 511 if (settings.allowEmpty && value === "") { 512 return ""; 513 } 514 if (!!settings.reverse) {
515 return maskValueReverse(value, settings); 516 } 517 return maskValueStandard(value, settings); 518 } 519 520 function maskValueStandard(value, settings) { 521 var negative = (value.indexOf("-") > -1 && settings.allowNegative) ? "-" : "", 522 onlyNumbers = value.replace(/[^0-9]/g, ""), 523 integerPart = onlyNumbers.slice(0, onlyNumbers.length - settings.precision), 524 newValue, 525 decimalPart, 526 leadingZeros; 527 528 newValue = buildIntegerPart(integerPart, negative, settings); 529 530 if (settings.precision > 0) { 531 if (!isNaN(value) && value.indexOf(".")) { 532 var precision = value.substr(value.indexOf(".") + 1); 533 onlyNumbers += new Array((settings.precision + 1) - precision.length).join(0); 534 integerPart = onlyNumbers.slice(0, onlyNumbers.length - settings.precision); 535 newValue = buildIntegerPart(integerPart, negative, settings); 536 } 537 538 decimalPart = onlyNumbers.slice(onlyNumbers.length - settings.precision); 539 leadingZeros = new Array((settings.precision + 1) - decimalPart.length).join(0); 540 newValue += settings.decimal + leadingZeros + decimalPart; 541 } 542 return setSymbol(newValue, settings); 543 } 544 545 function maskValueReverse(value, settings) { 546 var negative = (value.indexOf("-") > -1 && settings.allowNegative) ? "-" : "", 547 valueWithoutSymbol = value.replace(settings.prefix, "").replace(settings.suffix, ""), 548 integerPart = valueWithoutSymbol.split(settings.decimal)[0], 549 newValue, 550 decimalPart = ""; 551 552 if (integerPart === "") { 553 integerPart = "0"; 554 } 555 newValue = buildIntegerPart(integerPart, negative, settings); 556 557 if (settings.precision > 0) { 558 var arr = valueWithoutSymbol.split(settings.decimal); 559 if (arr.length > 1) { 560 decimalPart = arr[1]; 561 } 562 newValue += settings.decimal + decimalPart; 563 var rounded = Number.parseFloat((integerPart + "." + decimalPart)).toFixed(settings.precision); 564 var roundedDecimalPart = rounded.toString().split(settings.decimal)[1]; 565 newValue = newValue.split(settings.decimal)[0] + "." + roundedDecimalPart; 566 } 567 568 return setSymbol(newValue, settings); 569 } 570 571 function buildIntegerPart(integerPart, negative, settings) { 572 // remove initial zeros 573 integerPart = integerPart.replace(/^0*/g, ""); 574 575 // put settings.thousands every 3 chars 576 integerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, settings.thousands); 577 if (integerPart === "") { 578 integerPart = "0"; 579 } 580 return negative + integerPart; 581 } 582 583 $.fn.maskMoney = function (method) { 584 if (methods[method]) { 585 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 586 } else if (typeof method === "object" || !method) { 587 return methods.init.apply(this, arguments); 588 } else { 589 $.error("Method " + method + " does not exist on jQuery.maskMoney"); 590 } 591 }; 592})(window.jQuery || window.Zepto);
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.