1/** 2 * autoNumeric.js 3 * @author: Bob Knothe 4 * @author: Sokolov Yura 5 * @version: 1.9.45 - 2015-06-13 GMT 5:00 PM / 19:00 6 * 7 * Created by Robert J. Knothe on 2010-10-25. Please report any bugs to https://github.com/BobKnothe/autoNumeric 8 * Contributor by Sokolov Yura on 2010-11-07 9 * 10 * Copyright (c) 2011 Robert J. Knothe http://www.decorplanit.com/plugin/ 11 * 12 * The MIT License (http://www.opensource.org/licenses/mit-license.php) 13 * 14 * Permission is hereby granted, free of charge, to any person 15 * obtaining a copy of this software and associated documentation 16 * files (the "Software"), to deal in the Software without 17 * restriction, including without limitation the rights to use, 18 * copy, modify, merge, publish, distribute, sublicense, and/or sell 19 * copies of the Software, and to permit persons to whom the 20 * Software is furnished to do so, subject to the following 21 * conditions: 22 * 23 * The above copyright notice and this permission notice shall be 24 * included in all copies or substantial portions of the Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 28 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 30 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 31 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33 * OTHER DEALINGS IN THE SOFTWARE. 34 */ 35(function (factory) { 36 if (typeof define === "function" && define.noamd) { 37 /** AMD. Register as an anonymous module. */ 38 define(["jquery"], factory); 39 } else if (typeof module === "object" && module.exports) { 40 /** Node/CommonJS */ 41 module.exports = factory(require("jquery")); 42 } else { 43 /** Browser globals */ 44 factory(window.jQuery); 45 } 46}(function ($) { 47 "use strict"; 48 /*jslint browser: true*/ 49 /*global jQuery: false*/ 50 /*Cross browser routine for getting selected range/cursor position 51 */ 52 53 /** 54 * Cross browser routine for getting selected range/cursor position 55 */ 56 57 function getElementSelection(that) { 58 var position = {}; 59 if (that.selectionStart === undefined) { 60 that.focus(); 61 var select = document.selection.createRange(); 62 position.length = select.text.length; 63 select.moveStart('character', -that.value.length); 64 position.end = select.text.length; 65 position.start = position.end - position.length; 66 } else { 67 position.start = that.selectionStart; 68 position.end = that.selectionEnd; 69 position.length = position.end - position.start; 70 } 71 return position; 72 } 73 74 /** 75 * Cross browser routine for setting selected range/cursor position 76 */ 77 78 function setElementSelection(that, start, end) { 79 if (that.selectionStart === undefined) { 80 that.focus(); 81 var r = that.createTextRange(); 82 r.collapse(true); 83 r.moveEnd('character', end); 84 r.moveStart('character', start); 85 r.select(); 86 } else { 87 that.selectionStart = start; 88 that.selectionEnd = end; 89 } 90 } 91 92 /** 93 * run callbacks in parameters if any 94 * any parameter could be a callback: 95 * - a function, which invoked with jQuery element, parameters and this parameter name and returns parameter value 96 * - a name of function, attached to $(selector).autoNumeric.functionName(){} - which was called previously 97 */ 98 99 function runCallbacks($this, settings) { 100 /** 101 * loops through the settings object (option array) to find the following 102 * k = option name example k=aNum 103 * val = option value example val=0123456789 104 */ 105 $.each(settings, function (k, val) { 106 if (typeof val === 'function') { 107 settings[k] = val($this, settings, k); 108 } else if (typeof $this.autoNumeric[val] === 'function') { 109 /** 110 * calls the attached function from the html5 data example: data-a-sign="functionName" 111 */ 112 settings[k] = $this.autoNumeric[val]($this, settings, k); 113 } 114 }); 115 } 116 117 /** 118 * Converts the vMin, vMax & mDec string to numeric value 119 */ 120 121 function convertKeyToNumber(settings, key) {
122 if (typeof(settings[key]) === 'string') { 123 settings[key] *= 1; 124 } 125 } 126 127 /** 128 * Preparing user defined options for further usage 129 * merge them with defaults appropriately 130 */ 131 132 function autoCode($this, settings) { 133 runCallbacks($this, settings); 134 settings.tagList = ['b', 'caption', 'cite', 'code', 'dd', 'del', 'div', 'dfn', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ins', 'kdb', 'label', 'li', 'output', 'p', 'q', 's', 'sample', 'span', 'strong', 'td', 'th', 'u', 'var']; 135 var vmax = settings.vMax.toString().split('.'), 136 vmin = (!settings.vMin && settings.vMin !== 0) ? [] : settings.vMin.toString().split('.'); 137 convertKeyToNumber(settings, 'vMax'); 138 convertKeyToNumber(settings, 'vMin'); 139 convertKeyToNumber(settings, 'mDec'); /** set mDec if not defined by user */ 140 settings.mDec = (settings.mRound === 'CHF') ? '2' : settings.mDec; 141 settings.allowLeading = true; 142 settings.aNeg = settings.vMin < 0 ? '-' : ''; 143 vmax[0] = vmax[0].replace('-', ''); 144 vmin[0] = vmin[0].replace('-', ''); 145 settings.mInt = Math.max(vmax[0].length, vmin[0].length, 1); 146 if (settings.mDec === null) { 147 var vmaxLength = 0, 148 vminLength = 0; 149 if (vmax[1]) { 150 vmaxLength = vmax[1].length; 151 } 152 if (vmin[1]) { 153 vminLength = vmin[1].length; 154 } 155 settings.mDec = Math.max(vmaxLength, vminLength); 156 } /** set alternative decimal separator key */ 157 if (settings.altDec === null && settings.mDec > 0) { 158 if (settings.aDec === '.' && settings.aSep !== ',') { 159 settings.altDec = ','; 160 } else if (settings.aDec === ',' && settings.aSep !== '.') { 161 settings.altDec = '.'; 162 } 163 } 164 /** cache regexps for autoStrip */ 165 var aNegReg = settings.aNeg ? '([-\\' + settings.aNeg + ']?)' : '(-?)'; 166 settings.aNegRegAutoStrip = aNegReg; 167 settings.skipFirstAutoStrip = new RegExp(aNegReg + '[^-' + (settings.aNeg ? '\\' + settings.aNeg : '') + '\\' + settings.aDec + '\\d]' + '.*?(\\d|\\' + settings.aDec + '\\d)'); 168 settings.skipLastAutoStrip = new RegExp('(\\d\\' + settings.aDec + '?)[^\\' + settings.aDec + '\\d]\\D*$'); 169 var allowed = '-' + settings.aNum + '\\' + settings.aDec; 170 settings.allowedAutoStrip = new RegExp('[^' + allowed + ']', 'gi'); 171 settings.numRegAutoStrip = new RegExp(aNegReg + '(?:\\' + settings.aDec + '?(\\d+\\' + settings.aDec + '\\d+)|(\\d*(?:\\' + settings.aDec + '\\d*)?))'); 172 return settings; 173 } 174 175 /** 176 * strips all unwanted characters and leave only a number alert 177 */ 178 179 function autoStrip(s, settings, strip_zero) { 180 if (settings.aSign) { /** remove currency sign */ 181 while (s.indexOf(settings.aSign) > -1) { 182 s = s.replace(settings.aSign, ''); 183 } 184 } 185 s = s.replace(settings.skipFirstAutoStrip, '$1$2'); /** first replace anything before digits */ 186 s = s.replace(settings.skipLastAutoStrip, '$1'); /** then replace anything after digits */ 187 s = s.replace(settings.allowedAutoStrip, ''); /** then remove any uninterested characters */ 188 if (settings.altDec) { 189 s = s.replace(settings.altDec, settings.aDec); 190 } /** get only number string */ 191 var m = s.match(settings.numRegAutoStrip); 192 s = m ? [m[1], m[2], m[3]].join('') : ''; 193 if ((settings.lZero === 'allow' || settings.lZero === 'keep') && strip_zero !== 'strip') { 194 var parts = [], 195 nSign = ''; 196 parts = s.split(settings.aDec); 197 if (parts[0].indexOf('-') !== -1) { 198 nSign = '-'; 199 parts[0] = parts[0].replace('-', ''); 200 } 201 if (parts[0].length > settings.mInt && parts[0].charAt(0) === '0') { /** strip leading zero if need */ 202 parts[0] = parts[0].slice(1); 203 } 204 s = nSign + parts.join(settings.aDec); 205 } 206 if ((strip_zero && settings.lZero === 'deny') || (strip_zero && settings.lZero === 'allow' && settings.allowLeading === false)) { 207 var strip_reg = '^' + settings.aNegRegAutoStrip + '0*(\\d' + (strip_zero === 'leading' ? ')' : '|$)');
208 strip_reg = new RegExp(strip_reg); 209 s = s.replace(strip_reg, '$1$2'); 210 } 211 return s; 212 } 213 214 /** 215 * places or removes brackets on negative values 216 * works only when with pSign: 'p' 217 */ 218 219 function negativeBracket(s, settings) { 220 if (settings.pSign === 'p') { 221 var brackets = settings.nBracket.split(','); 222 if (!settings.hasFocus && !settings.removeBrackets) { 223 s = s.replace(settings.aNeg, ''); 224 s = brackets[0] + s + brackets[1]; 225 } else if ((settings.hasFocus && s.charAt(0) === brackets[0]) || (settings.removeBrackets && s.charAt(0) === brackets[0])) { 226 s = s.replace(brackets[0], settings.aNeg); 227 s = s.replace(brackets[1], ''); 228 } 229 } 230 return s; 231 } 232 233 /** 234 * function to handle numbers less than 0 that are stored in Exponential notation ex: .0000001 stored as 1e-7 235 */ 236 237 function checkValue(value, settings) { 238 if (value) { 239 var checkSmall = +value; 240 if (checkSmall < 0.000001 && checkSmall > -1) { 241 value = +value; 242 if (value < 0.000001 && value > 0) { 243 value = (value + 10).toString(); 244 value = value.substring(1); 245 } 246 if (value < 0 && value > -1) { 247 value = (value - 10).toString(); 248 value = '-' + value.substring(2); 249 } 250 value = value.toString(); 251 } else { 252 var parts = value.split('.'); 253 if (parts[1] !== undefined) { 254 if (+parts[1] === 0) { 255 value = parts[0]; 256 } else { 257 parts[1] = parts[1].replace(/0*$/, ''); 258 value = parts.join('.'); 259 } 260 } 261 } 262 } 263 return (settings.lZero === 'keep') ? value : value.replace(/^0*(\d)/, '$1'); 264 } 265 266 /** 267 * prepare number string to be converted to real number 268 */ 269 270 function fixNumber(s, aDec, aNeg) { 271 if (aDec && aDec !== '.') { 272 s = s.replace(aDec, '.'); 273 } 274 if (aNeg && aNeg !== '-') { 275 s = s.replace(aNeg, '-'); 276 } 277 if (!s.match(/\d/)) { 278 s += '0'; 279 } 280 return s; 281 } 282 283 /** 284 * prepare real number to be converted to our format 285 */ 286 287 function presentNumber(s, aDec, aNeg) { 288 if (aNeg && aNeg !== '-') { 289 s = s.replace('-', aNeg); 290 } 291 if (aDec && aDec !== '.') { 292 s = s.replace('.', aDec); 293 } 294 return s; 295 } 296 297 /** 298 * private function to check for empty value 299 */ 300 301 function checkEmpty(iv, settings, signOnEmpty) { 302 if (iv === '' || iv === settings.aNeg) { 303 if (settings.wEmpty === 'zero') { 304 return iv + '0'; 305 } 306 if (settings.wEmpty === 'sign' || signOnEmpty) { 307 return iv + settings.aSign; 308 } 309 return iv; 310 } 311 return null; 312 } 313 314 /** 315 * private function that formats our number 316 */ 317 318 function autoGroup(iv, settings) { 319 iv = autoStrip(iv, settings); 320 var testNeg = iv.replace(',', '.'), 321 empty = checkEmpty(iv, settings, true); 322 if (empty !== null) { 323 return empty; 324 } 325 var digitalGroup = ''; 326 if (settings.dGroup === 2) { 327 digitalGroup = /(\d)((\d)(\d{2}?)+)$/; 328 } else if (settings.dGroup === 4) { 329 digitalGroup = /(\d)((\d{4}?)+)$/; 330 } else { 331 digitalGroup = /(\d)((\d{3}?)+)$/; 332 } /** splits the string at the decimal string */ 333 var ivSplit = iv.split(settings.aDec); 334 if (settings.altDec && ivSplit.length === 1) { 335 ivSplit = iv.split(settings.altDec); 336 } /** assigns the whole number to the a variable (s) */ 337 var s = ivSplit[0]; 338 if (settings.aSep) { 339 while (digitalGroup.test(s)) { /** re-inserts the thousand separator via a regular expression */ 340 s = s.replace(digitalGroup, '$1' + settings.aSep + '$2'); 341 } 342 } 343 if (settings.mDec !== 0 && ivSplit.length > 1) { 344 if (ivSplit[1].length > settings.mDec) { 345 ivSplit[1] = ivSplit[1].substring(0, settings.mDec); 346 } /** joins the whole number with the decimal value */ 347 iv = s + settings.aDec + ivSplit[1]; 348 } else { /** if whole numbers only */ 349 iv = s; 350 } 351 if (settings.aSign) { 352 var has_aNeg = iv.indexOf(settings.aNeg) !== -1; 353 iv = iv.replace(settings.aNeg, ''); 354 iv = settings.pSign === 'p' ? settings.aSign + iv : iv + settings.aSign; 355 if (has_aNeg) { 356 iv = settings.aNeg + iv; 357 } 358 } 359 if (testNeg < 0 && settings.nBracket !== null) { /** removes the negative sign and places brackets */ 360 iv = negativeBracket(iv, settings); 361 } 362 return iv; 363 } 364 365 /** 366 * round number after setting by pasting or $().autoNumericSet()
367 * private function for round the number 368 * please note this handled as text - JavaScript math function can return inaccurate values 369 * also this offers multiple rounding methods that are not easily accomplished in JavaScript 370 */ 371 372 function autoRound(iv, settings) { /** value to string */ 373 iv = (iv === '') ? '0' : iv.toString(); 374 convertKeyToNumber(settings, 'mDec'); /** set mDec to number needed when mDec set by 'update method */ 375 if (settings.mRound === 'CHF') { 376 iv = (Math.round(iv * 20) / 20).toString(); 377 } 378 var ivRounded = '', 379 i = 0, 380 nSign = '', 381 rDec = (typeof(settings.aPad) === 'boolean' || settings.aPad === null) ? (settings.aPad ? settings.mDec : 0) : +settings.aPad; 382 var truncateZeros = function (ivRounded) { /** truncate not needed zeros */ 383 var regex = (rDec === 0) ? (/(\.(?:\d*[1-9])?)0*$/) : rDec === 1 ? (/(\.\d(?:\d*[1-9])?)0*$/) : new RegExp('(\\.\\d{' + rDec + '}(?:\\d*[1-9])?)0*$'); 384 ivRounded = ivRounded.replace(regex, '$1'); /** If there are no decimal places, we don't need a decimal point at the end */ 385 if (rDec === 0) { 386 ivRounded = ivRounded.replace(/\.$/, ''); 387 } 388 return ivRounded; 389 }; 390 if (iv.charAt(0) === '-') { /** Checks if the iv (input Value)is a negative value */ 391 nSign = '-'; 392 iv = iv.replace('-', ''); /** removes the negative sign will be added back later if required */ 393 } 394 if (!iv.match(/^\d/)) { /** append a zero if first character is not a digit (then it is likely to be a dot)*/ 395 iv = '0' + iv; 396 } 397 if (nSign === '-' && +iv === 0) { /** determines if the value is zero - if zero no negative sign */ 398 nSign = ''; 399 } 400 if ((+iv > 0 && settings.lZero !== 'keep') || (iv.length > 0 && settings.lZero === 'allow')) { /** trims leading zero's if needed */ 401 iv = iv.replace(/^0*(\d)/, '$1'); 402 } 403 var dPos = iv.lastIndexOf('.'), 404 /** virtual decimal position */ 405 vdPos = (dPos === -1) ? iv.length - 1 : dPos, 406 /** checks decimal places to determine if rounding is required */ 407 cDec = (iv.length - 1) - vdPos; /** check if no rounding is required */ 408 if (cDec <= settings.mDec) { 409 ivRounded = iv; /** check if we need to pad with zeros */ 410 if (cDec < rDec) { 411 if (dPos === -1) { 412 ivRounded += settings.aDec; 413 } 414 var zeros = '000000'; 415 while (cDec < rDec) { 416 zeros = zeros.substring(0, rDec - cDec); 417 ivRounded += zeros; 418 cDec += zeros.length; 419 } 420 } else if (cDec > rDec) { 421 ivRounded = truncateZeros(ivRounded); 422 } else if (cDec === 0 && rDec === 0) { 423 ivRounded = ivRounded.replace(/\.$/, ''); 424 } 425 if (settings.mRound !== 'CHF') { 426 return (+ivRounded === 0) ? ivRounded : nSign + ivRounded; 427 } 428 if (settings.mRound === 'CHF') { 429 dPos = ivRounded.lastIndexOf('.'); 430 iv = ivRounded; 431 } 432 433 } /** rounded length of the string after rounding */ 434 var rLength = dPos + settings.mDec, 435 tRound = +iv.charAt(rLength + 1), 436 ivArray = iv.substring(0, rLength + 1).split(''), 437 odd = (iv.charAt(rLength) === '.') ? (iv.charAt(rLength - 1) % 2)
437: (iv.charAt(rLength) % 2), 438 onePass = true; 439 if (odd !== 1) { 440 odd = (odd === 0 && (iv.substring(rLength + 2, iv.length) > 0)) ? 1 : 0; 441 } 442 /*jslint white: true*/ 443 if ((tRound > 4 && settings.mRound === 'S') || /** Round half up symmetric */ 444 (tRound > 4 && settings.mRound === 'A' && nSign === '') || /** Round half up asymmetric positive values */ 445 (tRound > 5 && settings.mRound === 'A' && nSign === '-') || /** Round half up asymmetric negative values */ 446 (tRound > 5 && settings.mRound === 's') || /** Round half down symmetric */ 447 (tRound > 5 && settings.mRound === 'a' && nSign === '') || /** Round half down asymmetric positive values */ 448 (tRound > 4 && settings.mRound === 'a' && nSign === '-') || /** Round half down asymmetric negative values */ 449 (tRound > 5 && settings.mRound === 'B') || /** Round half even "Banker's Rounding" */ 450 (tRound === 5 && settings.mRound === 'B' && odd === 1) || /** Round half even "Banker's Rounding" */ 451 (tRound > 0 && settings.mRound === 'C' && nSign === '') || /** Round to ceiling toward positive infinite */ 452 (tRound > 0 && settings.mRound === 'F' && nSign === '-') || /** Round to floor toward negative infinite */ 453 (tRound > 0 && settings.mRound === 'U') || /** round up away from zero */ 454 (settings.mRound === 'CHF')) { /** Round Swiss FRanc */ 455 /*jslint white: false*/ 456 for (i = (ivArray.length - 1); i >= 0; i -= 1) { /** Round up the last digit if required, and continue until no more 9's are found */ 457 if (ivArray[i] !== '.') { 458 if (settings.mRound === 'CHF' && ivArray[i] <= 2 && onePass) { 459 ivArray[i] = 0; 460 onePass = false; 461 break; 462 } 463 if (settings.mRound === 'CHF' && ivArray[i] <= 7 && onePass) { 464 ivArray[i] = 5; 465 onePass = false; 466 break; 467 } 468 if (settings.mRound === 'CHF' && onePass) { 469 ivArray[i] = 10; 470 onePass = false; 471 } else { 472 ivArray[i] = +ivArray[i] + 1; 473 } 474 if (ivArray[i] < 10) { 475 break; 476 } 477 if (i > 0) { 478 ivArray[i] = '0'; 479 } 480 } 481 } 482 } 483 ivArray = ivArray.slice(0, rLength + 1); /** Reconstruct the string, converting any 10's to 0's */ 484 ivRounded = truncateZeros(ivArray.join('')); /** return rounded value */ 485 return (+ivRounded === 0) ? ivRounded : nSign + ivRounded; 486 } 487 488 /** 489 * truncate decimal part of a number 490 */ 491 492 function truncateDecimal(s, settings, paste) { 493 var aDec = settings.aDec, 494 mDec = settings.mDec; 495 s = (paste === 'paste') ? autoRound(s, settings) : s; 496 if (aDec && mDec) { 497 var parts = s.split(aDec); 498 /** truncate decimal part to satisfying length 499 * cause we would round it anyway */ 500 if (parts[1] && parts[1].length > mDec) { 501 if (mDec > 0) { 502 parts[1] = parts[1].substring(0, mDec); 503 s = parts.join(aDec); 504 } else { 505 s = parts[0]; 506 } 507 } 508 } 509 return s; 510 } 511 512 /** 513 * checking that number satisfy format conditions 514 * and lays between settings.vMin and settings.vMax 515 * and the string length does not exceed the digits in settings.vMin and settings.vMax 516 */ 517 518 function autoCheck(s, settings) { 519 s = autoStrip(s, settings); 520 s = truncateDecimal(s, settings); 521 s = fixNumber(s, settings.aDec, settings.aNeg); 522 var value = +s; 523 return value >= settings.vMin && value <= settings.vMax; 524 } 525 526 /** 527 * Holder object for field properties 528 */ 529 530 function AutoNumericHolder(that, settings) { 531 this.settings = settings; 532 this.that = that; 533 this.$that = $(that); 534 this.formatted = false;
535 this.settingsClone = autoCode(this.$that, this.settings); 536 this.value = that.value; 537 } 538 AutoNumericHolder.prototype = { 539 init: function (e) { 540 this.value = this.that.value; 541 this.settingsClone = autoCode(this.$that, this.settings); 542 this.ctrlKey = e.ctrlKey; 543 this.cmdKey = e.metaKey; 544 this.shiftKey = e.shiftKey; 545 this.selection = getElementSelection(this.that); /** keypress event overwrites meaningful value of e.keyCode */ 546 if (e.type === 'keydown' || e.type === 'keyup') { 547 this.kdCode = e.keyCode; 548 } 549 this.which = e.which; 550 this.processed = false; 551 this.formatted = false; 552 }, 553 setSelection: function (start, end, setReal) { 554 start = Math.max(start, 0); 555 end = Math.min(end, this.that.value.length); 556 this.selection = { 557 start: start, 558 end: end, 559 length: end - start 560 }; 561 if (setReal === undefined || setReal) { 562 setElementSelection(this.that, start, end); 563 } 564 }, 565 setPosition: function (pos, setReal) { 566 this.setSelection(pos, pos, setReal); 567 }, 568 getBeforeAfter: function () { 569 var value = this.value, 570 left = value.substring(0, this.selection.start), 571 right = value.substring(this.selection.end, value.length); 572 return [left, right]; 573 }, 574 getBeforeAfterStriped: function () { 575 var parts = this.getBeforeAfter(); 576 parts[0] = autoStrip(parts[0], this.settingsClone); 577 parts[1] = autoStrip(parts[1], this.settingsClone); 578 return parts; 579 }, 580 581 /** 582 * strip parts from excess characters and leading zeroes 583 */ 584 normalizeParts: function (left, right) { 585 var settingsClone = this.settingsClone; 586 right = autoStrip(right, settingsClone); /** if right is not empty and first character is not aDec, */ 587 /** we could strip all zeros, otherwise only leading */ 588 var strip = right.match(/^\d/) ? true : 'leading'; 589 left = autoStrip(left, settingsClone, strip); /** prevents multiple leading zeros from being entered */ 590 if ((left === '' || left === settingsClone.aNeg) && settingsClone.lZero === 'deny') { 591 if (right > '') { 592 right = right.replace(/^0*(\d)/, '$1'); 593 } 594 } 595 var new_value = left + right; /** insert zero if has leading dot */ 596 if (settingsClone.aDec) { 597 var m = new_value.match(new RegExp('^' + settingsClone.aNegRegAutoStrip + '\\' + settingsClone.aDec)); 598 if (m) { 599 left = left.replace(m[1], m[1] + '0'); 600 new_value = left + right; 601 } 602 } /** insert zero if number is empty and io.wEmpty == 'zero' */ 603 if (settingsClone.wEmpty === 'zero' && (new_value === settingsClone.aNeg || new_value === '')) { 604 left += '0'; 605 } 606 return [left, right]; 607 }, 608 609 /** 610 * set part of number to value keeping position of cursor 611 */ 612 setValueParts: function (left, right, paste) { 613 var settingsClone = this.settingsClone, 614 parts = this.normalizeParts(left, right), 615 new_value = parts.join(''), 616 position = parts[0].length; 617 if (autoCheck(new_value, settingsClone)) { 618 new_value = truncateDecimal(new_value, settingsClone, paste); 619 if (position > new_value.length) { 620 position = new_value.length; 621 } 622 this.value = new_value; 623 this.setPosition(position, false); 624 return true; 625 } 626 return false; 627 }, 628 629 /** 630 * helper function for expandSelectionOnSign 631 * returns sign position of a formatted value 632 */ 633 signPosition: function () { 634 var settingsClone = this.settingsClone, 635 aSign = settingsClone.aSign, 636 that = this.that; 637 if (aSign) { 638 var aSignLen = aSign.length; 639 if (settingsClone.pSign === 'p') { 640 var hasNeg = settingsClone.aNeg && that.value && that.value.charAt(0) === settingsClone.aNeg; 641 return hasNeg ? [1, aSignLen + 1] : [0, aSignLen]; 642 } 643 var valueLen = that.value.length; 644 return [valueLen - aSignLen, valueLen]; 645 } 646 return [1000, -1]; 647 }, 648 649 /** 650 * expands selection to cover whole sign 651 * prevents partial deletion/copying/overwriting of a sign 652 */ 653 expandSelectionOnSign: function (setReal) { 654 var sign_position = this.signPosition(), 655 selection = this.selection; 656 if (selection.start < sign_position[1] && selection.end > sign_position[0]) { /** if selection catches something except sign and catches only space from sign */ 657 if ((selection.start < sign_position[0] || selection.end > sign_position[1]) && this.value.substring(Math.max(selection.start, sign_position[0]), Math.min(selection.end, sign_position[1])).match(/^\s*$/)) { /** then select without empty space */ 658 if (selection.start < sign_position[0]) { 659 this.setSelection(selection.start, sign_position[0], setReal); 660 } else { 661 this.setSelection(sign_position[1], selection.end, setReal); 662 } 663 } else { /** else select with whole sign */ 664 this.setSelection(Math.min(selection.start, sign_position[0]), Math.max(selection.end, sign_position[1]), setReal); 665 } 666 } 667 }, 668 669 /**
670 * try to strip pasted value to digits 671 */ 672 checkPaste: function () { 673 if (this.valuePartsBeforePaste !== undefined) { 674 var parts = this.getBeforeAfter(), 675 676 oldParts = this.valuePartsBeforePaste; 677 delete this.valuePartsBeforePaste; /** try to strip pasted value first */ 678 parts[0] = parts[0].substr(0, oldParts[0].length) + autoStrip(parts[0].substr(oldParts[0].length), this.settingsClone); 679 if (!this.setValueParts(parts[0], parts[1], 'paste')) { 680 this.value = oldParts.join(''); 681 this.setPosition(oldParts[0].length, false); 682 } 683 } 684 }, 685 686 /** 687 * process pasting, cursor moving and skipping of not interesting keys 688 * if returns true, further processing is not performed 689 */ 690 skipAllways: function (e) { 691 var kdCode = this.kdCode, 692 which = this.which, 693 ctrlKey = this.ctrlKey, 694 cmdKey = this.cmdKey, 695 shiftKey = this.shiftKey; /** catch the ctrl up on ctrl-v */ 696 if (((ctrlKey || cmdKey) && e.type === 'keyup' && this.valuePartsBeforePaste !== undefined) || (shiftKey && kdCode === 45)) { 697 this.checkPaste(); 698 return false; 699 } 700 /** codes are taken from http://www.cambiaresearch.com/c4/702b8cd1-e5b0-42e6-83ac-25f0306e3e25/Javascript-Char-Codes-Key-Codes.aspx 701 * skip Fx keys, windows keys, other special keys 702 * Thanks Ney Estrabelli for the FF for Mac meta key support "keycode 224" 703 */ 704 if ((kdCode >= 112 && kdCode <= 123) || (kdCode >= 91 && kdCode <= 93) || (kdCode >= 9 && kdCode <= 31) || (kdCode < 8 && (which === 0 || which === kdCode)) || kdCode === 144 || kdCode === 145 || kdCode === 45 || kdCode === 224) { 705 return true; 706 } 707 if ((ctrlKey || cmdKey) && kdCode === 65) { /** if select all (a=65)*/ 708 return true; 709 } 710 if ((ctrlKey || cmdKey) && (kdCode === 67 || kdCode === 86 || kdCode === 88)) { /** if copy (c=67) paste (v=86) or cut (x=88) */ 711 if (e.type === 'keydown') { 712 this.expandSelectionOnSign(); 713 } 714 if (kdCode === 86 || kdCode === 45) { /** try to prevent wrong paste */ 715 if (e.type === 'keydown' || e.type === 'keypress') { 716 if (this.valuePartsBeforePaste === undefined) { 717 this.valuePartsBeforePaste = this.getBeforeAfter(); 718 } 719 } else { 720 this.checkPaste(); 721 } 722 } 723 return e.type === 'keydown' || e.type === 'keypress' || kdCode === 67; 724 } 725 if (ctrlKey || cmdKey) { 726 return true; 727 } 728 if (kdCode === 37 || kdCode === 39) { /** jump over thousand separator */ 729 var aSep = this.settingsClone.aSep, 730 start = this.selection.start, 731 value = this.that.value; 732 if (e.type === 'keydown' && aSep && !this.shiftKey) { 733 if (kdCode === 37 && value.charAt(start - 2) === aSep) { 734 this.setPosition(start - 1); 735 } else if (kdCode === 39 && value.charAt(start + 1) === aSep) { 736 this.setPosition(start + 1); 737 } 738 } 739 return true; 740 } 741 if (kdCode >= 34 && kdCode <= 40) { 742 return true; 743 } 744 return false; 745 }, 746 747 /** 748 * process deletion of characters 749 * returns true if processing performed 750 */ 751 processAllways: function () { 752 var parts; /** process backspace or delete */ 753 if (this.kdCode === 8 || this.kdCode === 46) { 754 if (!this.selection.length) { 755 parts = this.getBeforeAfterStriped(); 756 if (this.kdCode === 8) { 757 parts[0] = parts[0].substring(0, parts[0].length - 1); 758 } else { 759 parts[1] = parts[1].substring(1, parts[1].length); 760 } 761 this.setValueParts(parts[0], parts[1]); 762 } else { 763 this.expandSelectionOnSign(false); 764 parts = this.getBeforeAfterStriped(); 765 this.setValueParts(parts[0], parts[1]); 766 } 767 return true; 768 } 769 return false;
770 }, 771 772 /** 773 * process insertion of characters 774 * returns true if processing performed 775 */ 776 processKeypress: function () { 777 var settingsClone = this.settingsClone, 778 cCode = String.fromCharCode(this.which), 779 parts = this.getBeforeAfterStriped(), 780 left = parts[0], 781 right = parts[1]; /** start rules when the decimal character key is pressed */ 782 /** always use numeric pad dot to insert decimal separator */ 783 if (cCode === settingsClone.aDec || (settingsClone.altDec && cCode === settingsClone.altDec) || ((cCode === '.' || cCode === ',') && this.kdCode === 110)) { /** do not allow decimal character if no decimal part allowed */ 784 if (!settingsClone.mDec || !settingsClone.aDec) { 785 return true; 786 } /** do not allow decimal character before aNeg character */ 787 if (settingsClone.aNeg && right.indexOf(settingsClone.aNeg) > -1) { 788 return true; 789 } /** do not allow decimal character if other decimal character present */ 790 if (left.indexOf(settingsClone.aDec) > -1) { 791 return true; 792 } 793 if (right.indexOf(settingsClone.aDec) > 0) { 794 return true; 795 } 796 if (right.indexOf(settingsClone.aDec) === 0) { 797 right = right.substr(1); 798 } 799 this.setValueParts(left + settingsClone.aDec, right); 800 return true; 801 } 802 /** 803 * start rule on negative sign & prevent minus if not allowed 804 */ 805 if (cCode === '-' || cCode === '+') { 806 if (!settingsClone.aNeg) { 807 return true; 808 } /** caret is always after minus */ 809 if (left === '' && right.indexOf(settingsClone.aNeg) > -1) { 810 left = settingsClone.aNeg; 811 right = right.substring(1, right.length); 812 } /** change sign of number, remove part if should */ 813 if (left.charAt(0) === settingsClone.aNeg) { 814 left = left.substring(1, left.length); 815 } else { 816 left = (cCode === '-') ? settingsClone.aNeg + left : left; 817 } 818 this.setValueParts(left, right); 819 return true; 820 } /** digits */ 821 if (cCode >= '0' && cCode <= '9') { /** if try to insert digit before minus */ 822 if (settingsClone.aNeg && left === '' && right.indexOf(settingsClone.aNeg) > -1) { 823 left = settingsClone.aNeg; 824 right = right.substring(1, right.length); 825 } 826 if (settingsClone.vMax <= 0 && settingsClone.vMin < settingsClone.vMax && this.value.indexOf(settingsClone.aNeg) === -1 && cCode !== '0') { 827 left = settingsClone.aNeg + left; 828 } 829 this.setValueParts(left + cCode, right); 830 return true; 831 } /** prevent any other character */ 832 return true; 833 }, 834 835 /** 836 * formatting of just processed value with keeping of cursor position 837 */ 838 formatQuick: function () { 839 var settingsClone = this.settingsClone, 840 parts = this.getBeforeAfterStriped(), 841 leftLength = this.value;
842 if ((settingsClone.aSep === '' || (settingsClone.aSep !== '' && leftLength.indexOf(settingsClone.aSep) === -1)) && (settingsClone.aSign === '' || (settingsClone.aSign !== '' && leftLength.indexOf(settingsClone.aSign) === -1))) { 843 var subParts = [], 844 nSign = ''; 845 subParts = leftLength.split(settingsClone.aDec); 846 if (subParts[0].indexOf('-') > -1) { 847 nSign = '-'; 848 subParts[0] = subParts[0].replace('-', ''); 849 parts[0] = parts[0].replace('-', ''); 850 } 851 if (subParts[0].length > settingsClone.mInt && parts[0].charAt(0) === '0') { /** strip leading zero if need */ 852 parts[0] = parts[0].slice(1); 853 } 854 parts[0] = nSign + parts[0]; 855 } 856 var value = autoGroup(this.value, this.settingsClone), 857 position = value.length; 858 if (value) { 859 /** prepare regexp which searches for cursor position from unformatted left part */ 860 var left_ar = parts[0].split(''), 861 i = 0; 862 for (i; i < left_ar.length; i += 1) { /** thanks Peter Kovari */ 863 if (!left_ar[i].match('\\d')) { 864 left_ar[i] = '\\' + left_ar[i]; 865 } 866 } 867 var leftReg = new RegExp('^.*?' + left_ar.join('.*?')); 868 /** search cursor position in formatted value */ 869 var newLeft = value.match(leftReg); 870 if (newLeft) { 871 position = newLeft[0].length; 872 /** if we are just before sign which is in prefix position */ 873 if (((position === 0 && value.charAt(0) !== settingsClone.aNeg) || (position === 1 && value.charAt(0) === settingsClone.aNeg)) && settingsClone.aSign && settingsClone.pSign === 'p') { 874 /** place caret after prefix sign */ 875 position = this.settingsClone.aSign.length + (value.charAt(0) === '-' ? 1 : 0); 876 } 877 } else if (settingsClone.aSign && settingsClone.pSign === 's') { 878 /** if we could not find a place for cursor and have a sign as a suffix */ 879 /** place carret before suffix currency sign */ 880 position -= settingsClone.aSign.length; 881 } 882 } 883 this.that.value = value; 884 this.setPosition(position); 885 this.formatted = true; 886 } 887 }; 888 889 /** 890 * thanks to Anthony & Evan C 891 */ 892 893 function autoGet(obj) { 894 if (typeof obj === 'string') { 895 obj = obj.replace(/\[/g, "\\[").replace(/\]/g, "\\]"); 896 obj = '#' + obj.replace(/(:|\.)/g, '\\$1'); 897 /** obj = '#' + obj.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); */ 898 /** possible modification to replace the above 2 lines */ 899 } 900 return $(obj); 901 } 902 903 /** 904 * function to attach data to the element 905 * and imitate the holder 906 */ 907 908 function getHolder($that, settings, update) { 909 var data = $that.data('autoNumeric'); 910 if (!data) { 911 data = {}; 912 $that.data('autoNumeric', data); 913 } 914 var holder = data.holder; 915 if ((holder === undefined && settings) || update) { 916 holder = new AutoNumericHolder($that.get(0), settings); 917 data.holder = holder; 918 } 919 return holder; 920 } 921 922 var methods = { 923 924 /** 925 * Method to initiate autoNumeric and attached the settings (default and options passed as a parameter 926 * $(someSelector).autoNumeric('init'); // initiate autoNumeric with defaults 927 * $(someSelector).autoNumeric('init', {option}); // initiate autoNumeric with options 928 * $(someSelector).autoNumeric(); // initiate autoNumeric with defaults 929 * $(someSelector).autoNumeric({option}); // initiate autoNumeric with options 930 * options passes as a parameter example '{aSep: '.', aDec: ',', aSign: '⬠'} 931 */ 932 init: function (options) { 933 return this.each(function () { 934 var $this = $(this), 935 settings = $this.data('autoNumeric'), 936 /** attempt to grab 'autoNumeric' settings, if they don't exist returns "undefined". */ 937 tagData = $this.data(), 938 /** attempt to grab HTML5 data, if they don't exist we'll get "undefined".*/ 939 $input = $this.is('input[type=text], input[type=hidden], input[type=tel], input
939:not([type])'); 940 if (typeof settings !== 'object') { /** If we couldn't grab settings, create them from defaults and passed options. */ 941 settings = $.extend({}, $.fn.autoNumeric.defaults, tagData, options, { 942 aNum: '0123456789', 943 hasFocus: false, 944 removeBrackets: false, 945 runOnce: false, 946 tagList: ['b', 'caption', 'cite', 'code', 'dd', 'del', 'div', 'dfn', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ins', 'kdb', 'label', 'li', 'output', 'p', 'q', 's', 'sample', 'span', 'strong', 'td', 'th', 'u', 'var'] 947 }); /** Merge defaults, tagData and options */ 948 if (settings.aDec === settings.aSep) { 949 $.error("autoNumeric will not function properly when the decimal character aDec: '" + settings.aDec + "' and thousand separator aSep: '" + settings.aSep + "' are the same character"); 950 } 951 $this.data('autoNumeric', settings); /** Save our new settings */ 952 } else { 953 return this; 954 } 955 var holder = getHolder($this, settings); 956 if (!$input && $this.prop('tagName').toLowerCase() === 'input') { /** checks for non-supported input types */ 957 $.error('The input type "' + $this.prop('type') + '" is not supported by autoNumeric()'); 958 959 } 960 if ($.inArray($this.prop('tagName').toLowerCase(), settings.tagList) === -1 && $this.prop('tagName').toLowerCase() !== 'input') { 961 $.error("The <" + $this.prop('tagName').toLowerCase() + "> is not supported by autoNumeric()"); 962 963 } 964 if (settings.runOnce === false && settings.aForm) { /** routine to format default value on page load */ 965 if ($input) { 966 var setValue = true; 967 if ($this[0].value === '' && settings.wEmpty === 'empty') { 968 $this[0].value = ''; 969 setValue = false; 970 } 971 if ($this[0].value === '' && settings.wEmpty === 'sign') { 972 $this[0].value = settings.aSign; 973 setValue = false; 974 } 975 /** checks for page reload from back button 976 * also checks for ASP.net form post back 977 * the following HTML data attribute is REQUIRED (data-an-default="same value as the value attribute") 978 * example: <asp:TextBox runat="server" id="someID" value="1234.56" data-an-default="1234.56"> 979 */ 980 if (setValue && $this.val() !== '' && ((settings.anDefault === null && $this[0].value === $this.prop('defaultValue')) || (settings.anDefault !== null && settings.anDefault.toString() === $this.val()))) { 981 $this.autoNumeric('set', $this.val()); 982 } 983 } 984 if ($.inArray($this.prop('tagName').toLowerCase(), settings.tagList) !== -1 && $this.text() !== '') { 985 $this.autoNumeric('set', $this.text()); 986 } 987 } 988 settings.runOnce = true; 989 if ($this.is('input[type=text], input[type=hidden], input[type=tel], input:not([type])')) { /**added hidden type */ 990 $this.on('keydown.autoNumeric', function (e) { 991 holder = getHolder($this); 992 if (holder.settings.aDec === holder.settings.aSep) { 993 $.error("autoNumeric will not function properly when the decimal character aDec: '" + holder.settings.aDec + "' and thousand separator aSep: '" + holder.settings.aSep + "' are the same character"); 994 } 995 if (holder.that.readOnly) { 996 holder.processed = true; 997 return true; 998 } 999 /** The below streamed code / comment allows the "enter" keydown to throw a change() event */ 1000 /** if (e.keyCode === 13 && holder.inVal !== $this.val()){ 1001 $this.change(); 1002 holder.inVal = $this.val(); 1003 }*/ 1004 holder.init(e); 1005 if (holder.skipAllways(e)) { 1006 holder.processed = true; 1007 return true; 1008 } 1009 if (holder.processAllways()) { 1010 holder.processed = true; 1011 holder.formatQuick(); 1012 e.preventDefault(); 1013 return false;
1014 } 1015 holder.formatted = false; 1016 return true; 1017 }); 1018 $this.on('keypress.autoNumeric', function (e) { 1019 holder = getHolder($this); 1020 var processed = holder.processed; 1021 holder.init(e); 1022 if (holder.skipAllways(e)) { 1023 return true; 1024 } 1025 if (processed) { 1026 e.preventDefault(); 1027 return false; 1028 } 1029 if (holder.processAllways() || holder.processKeypress()) { 1030 holder.formatQuick(); 1031 e.preventDefault(); 1032 return false; 1033 } 1034 holder.formatted = false; 1035 }); 1036 $this.on('keyup.autoNumeric', function (e) { 1037 holder = getHolder($this); 1038 holder.init(e); 1039 var skip = holder.skipAllways(e); 1040 holder.kdCode = 0; 1041 delete holder.valuePartsBeforePaste; 1042 if ($this[0].value === holder.settings.aSign) { /** added to properly place the caret when only the currency is present */ 1043 if (holder.settings.pSign === 's') { 1044 setElementSelection(this, 0, 0); 1045 } else { 1046 setElementSelection(this, holder.settings.aSign.length, holder.settings.aSign.length); 1047 } 1048 } 1049 if (skip) { 1050 return true; 1051 } 1052 if (this.value === '') { 1053 return true; 1054 } 1055 if (!holder.formatted) { 1056 holder.formatQuick(); 1057 } 1058 }); 1059 $this.on('focusin.autoNumeric', function () { 1060 holder = getHolder($this); 1061 var $settings = holder.settingsClone; 1062 $settings.hasFocus = true; 1063 if ($settings.nBracket !== null) { 1064 var checkVal = $this.val(); 1065 $this.val(negativeBracket(checkVal, $settings)); 1066 } 1067 holder.inVal = $this.val(); 1068 var onEmpty = checkEmpty(holder.inVal, $settings, true); 1069 if (onEmpty !== null && onEmpty !== '') { 1070 $this.val(onEmpty); 1071 } 1072 }); 1073 $this.on('focusout.autoNumeric', function () { 1074 holder = getHolder($this); 1075 var $settings = holder.settingsClone, 1076 value = $this.val(), 1077 origValue = value; 1078 $settings.hasFocus = false; 1079 var strip_zero = ''; /** added to control leading zero */ 1080 if ($settings.lZero === 'allow') { /** added to control leading zero */ 1081 $settings.allowLeading = false; 1082 strip_zero = 'leading'; 1083 } 1084 if (value !== '') { 1085 value = autoStrip(value, $settings, strip_zero); 1086 if (checkEmpty(value, $settings) === null && autoCheck(value, $settings, $this[0])) { 1087 value = fixNumber(value, $settings.aDec, $settings.aNeg); 1088 value = autoRound(value, $settings); 1089 value = presentNumber(value, $settings.aDec, $settings.aNeg); 1090 } else { 1091 value = ''; 1092 } 1093 } 1094 var groupedValue = checkEmpty(value, $settings, false); 1095 if (groupedValue === null) { 1096 groupedValue = autoGroup(value, $settings); 1097 } 1098 if (groupedValue !== holder.inVal || groupedValue !== origValue) { 1099 $this.val(groupedValue); 1100 $this.change(); 1101 delete holder.inVal; 1102 } 1103 }); 1104 } 1105 }); 1106 }, 1107 1108 /** 1109 * method to remove settings and stop autoNumeric() - does not remove the formatting 1110 * $(someSelector).autoNumeric('destroy'); // destroy autoNumeric 1111 * no parameters accepted 1112 */ 1113 destroy: function () { 1114 return $(this).each(function () { 1115 var $this = $(this); 1116 $this.removeData('autoNumeric'); 1117 $this.off('autoNumeric'); 1118 }); 1119 }, 1120 1121 /** 1122 * method to update settings - can be call as many times 1123 * $(someSelector).autoNumeric('update', {options}); // updates the settings 1124 * options passes as a parameter example '{aSep: '.', aDec: ',', aSign: '⬠'} 1125 */ 1126 update: function (options) { 1127 return $(this).each(function () { 1128 var $this = autoGet($(this)), 1129 settings = $this.data('autoNumeric'); 1130 if (typeof settings !== 'object') { 1131 $.error("You must initialize autoNumeric('init', {options}) prior to calling the 'update' method"); 1132 } 1133 var strip = $this.autoNumeric('get'); 1134 settings = $.extend(settings, options); 1135 getHolder($this, settings, true); 1136 if (settings.aDec === settings.aSep) { 1137 $.error("autoNumeric will not function properly when the decimal character aDec: '" + settings.aDec + "' and thousand separator aSep: '" + settings.aSep + "' are the same character"); 1138 } 1139 $this.data('autoNumeric', settings); 1140 if ($this.val() !== '' || $this.text() !== '') { 1141 return $this.autoNumeric('set', strip); 1142 } 1143 return; 1144 }); 1145 }, 1146 1147 /** 1148 * method to format value sent as a parameter "" 1149 * $(someSelector).autoNumeric('set', 'value'}); // formats the value being passed 1150 * value passed as a string - can be a integer '1234' or double '1234.56789' 1151 * must contain only numbers and one decimal (period) character 1152 */ 1153 set: function (valueIn) { 1154 if (valueIn === null || isNaN(valueIn)) { 1155 return; 1156 } 1157 return $(this).each(function () { 1158 var $this = autoGet($(this)), 1159 settings = $this.data('autoNumeric'), 1160 value = valueIn.toString(), 1161 testValue = valueIn.toString(), 1162 $input = $this.is('input[type=text], input[type=hidden], input[type=tel], input
1162:not([type])'); 1163 if (typeof settings !== 'object') { 1164 $.error("You must initialize autoNumeric('init', {options}) prior to calling the 'set' method"); 1165 } 1166 /** allows locale decimal separator to be a comma */ 1167 if ((testValue === $this.attr('value') || testValue === $this.text()) && settings.runOnce === false) { 1168 value = value.replace(',', '.'); 1169 } 1170 if (!$.isNumeric(+value)) { 1171 $.error("The value (" + value + ") being 'set' is not numeric and has caused a error to be thrown"); 1172 } 1173 value = checkValue(value, settings); 1174 settings.setEvent = true; 1175 value.toString(); 1176 if (value !== '') { 1177 value = autoRound(value, settings); 1178 } 1179 value = presentNumber(value, settings.aDec, settings.aNeg); 1180 if (!autoCheck(value, settings)) { 1181 value = autoRound('', settings); 1182 } 1183 value = autoGroup(value, settings); 1184 if ($input) { 1185 return $this.val(value); 1186 } 1187 if ($.inArray($this.prop('tagName').toLowerCase(), settings.tagList) !== -1) { 1188 return $this.text(value); 1189 } 1190 return false; 1191 }); 1192 }, 1193 1194 /** 1195 * method to get the unformatted that accepts up to one parameter 1196 * $(someSelector).autoNumeric('get'); no parameters accepted 1197 * values returned as ISO numeric string "1234.56" where the decimal character is a period 1198 * only the first element in the selector is returned 1199 */ 1200 get: function () { 1201 var $this = autoGet($(this)), 1202 settings = $this.data('autoNumeric'); 1203 if (typeof settings !== 'object') { 1204 $.error("You must initialize autoNumeric('init', {options}) prior to calling the 'get' method"); 1205 } 1206 var getValue = ''; 1207 /** determine the element type then use .eq(0) selector to grab the value of the first element in selector */ 1208 if ($this.is('input[type=text], input[type=hidden], input[type=tel], input:not([type])')) { /**added hidden type */ 1209 getValue = $this.eq(0).val(); 1210 } else if ($.inArray($this.prop('tagName').toLowerCase(), settings.tagList) !== -1) { 1211 getValue = $this.eq(0).text(); 1212 } else { 1213 $.error("The <" + $this.prop('tagName').toLowerCase() + "> is not supported by autoNumeric()"); 1214 } 1215 if ((getValue === '' && settings.wEmpty === 'empty') || (getValue === settings.aSign && (settings.wEmpty === 'sign' || settings.wEmpty === 'empty'))) { 1216 return ''; 1217 } 1218 if (getValue !== '' && settings.nBracket !== null) { 1219 settings.removeBrackets = true; 1220 getValue = negativeBracket(getValue, settings); 1221 settings.removeBrackets = false; 1222 } 1223 if (settings.runOnce || settings.aForm === false) { 1224 getValue = autoStrip(getValue, settings); 1225 } 1226 getValue = fixNumber(getValue, settings.aDec, settings.aNeg); 1227 if (+getValue === 0 && settings.lZero !== 'keep') { 1228 getValue = '0'; 1229 } 1230 if (settings.lZero === 'keep') { 1231 return getValue; 1232 } 1233 getValue = checkValue(getValue, settings); 1234 return getValue; /** returned Numeric String */ 1235 }, 1236 1237 /** 1238 * The 'getString' method used jQuerys .serialize() method that creates a text string in standard URL-encoded notation 1239 * it then loops through the string and un-formats the inputs with autoNumeric 1240 * $(someSelector).autoNumeric('getString'); no parameter accepted 1241 * values returned as ISO numeric string "1234.56" where the decimal character is a period 1242 */ 1243 getString: function () { 1244 var isAutoNumeric = false, 1245 $this = autoGet($(this)), 1246 formFields = $this.serialize(), 1247 formParts = formFields.split('&'), 1248 formIndex = $('form').index($this), 1249 allFormElements = $('form:eq(' + formIndex + ')'), 1250 aiIndex = [], 1251 /* all input index */ 1252 scIndex = [], 1253 /* successful control index */ 1254 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 1255 /* from jQuery serialize method */ 1256 rsubmittable = /^(?:input|select|textarea|keygen)/i, 1257 /* from jQuery serialize method */ 1258 rcheckableType = /^(?:checkbox|radio)$/i, 1259 rnonAutoNumericTypes = /^(?:button|checkbox|color|date|datetime|datetime-local|email|file|image|month|number|password|radio|range|reset|search|submit|time|url|week)/i, 1260 count = 0; 1261 /*jslint unparam: true*/ 1262 /* index of successful elements */ 1263 $.each(allFormElements[0], function (i, field) { 1264 if (field.name !== '' && rsubmittable.test(field.localName) && !rsubmitterTypes.test(field.type) && !field.disabled && (field.checked || !rcheckableType.test(field.type))) { 1265 scIndex.push(count); 1266 count = count + 1; 1267 } else { 1268 scIndex.push(-1); 1269 } 1270 }); 1271 /* index of all inputs tags except checkbox */ 1272 count = 0; 1273 $.each(allFormElements[0], function (i, field) { 1274 if (field.localName === 'input' && (field.type === '' || field.type === 'text' || field.type === 'hidden' || field.type === 'tel')) { 1275 aiIndex.push(count); 1276 count = count + 1; 1277 } else { 1278 aiIndex.push(-1); 1279 if (field.localName === 'input' && rnonAutoNumericTypes.test(field.type)) { 1280 count = count + 1; 1281 } 1282 } 1283 }); 1284 $.each(formParts, function (i, miniParts) { 1285 miniParts = formParts[i].split('='); 1286 var scElement = $.inArray(i, scIndex); 1287 if (scElement > -1 && aiIndex[scElement] > -1) { 1288 var testInput = $('form:eq(' + formIndex + ') input:eq(' + aiIndex[scElement] + ')'), 1289 settings = testInput.data('autoNumeric'); 1290 if (typeof settings === 'object') { 1291 if (miniParts[1] !== null) { 1292 miniParts[1] = $('form:eq(' + formIndex + ') input:eq(' + aiIndex[scElement] + ')').autoNumeric('get').toString(); 1293 formParts[i] = miniParts.join('='); 1294 isAutoNumeric = true; 1295 } 1296 } 1297 } 1298 }); 1299 /*jslint unparam: false*/ 1300 if (!isAutoNumeric) { 1301 $.error("You must initialize autoNumeric('init', {options}) prior to calling the 'getString' method"); 1302 } 1303 return formParts.join('&'); 1304 }, 1305 1306 /** 1307 * The 'getString' method used jQuerys .serializeArray() method that creates array or objects that can be encoded as a JSON string 1308 * it then loops through the string and un-formats the inputs with autoNumeric 1309 * $(someSelector).autoNumeric('getArray'); no parameter accepted 1310 * values returned as ISO numeric string "1234.56" where the decimal character is a period 1311 */ 1312 getArray: function () { 1313 var isAutoNumeric = false, 1314 $this = autoGet($(this)), 1315 formFields = $this.serializeArray(), 1316 formIndex = $('form').index($this), 1317 allFormElements = $('form:eq(' + formIndex + ')'), 1318 aiIndex = [], 1319 /* all input index */ 1320 scIndex = [], 1321 /* successful control index */ 1322 rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, 1323 /* from jQuery serialize method */ 1324 rsubmittable = /^(?:input|select|textarea|keygen)/i, 1325 /* from jQuery serialize method */ 1326 rcheckableType = /^(?:checkbox|radio)$/i, 1327 rnonAutoNumericTypes = /^(?:button|checkbox|color|date|datetime|datetime-local|email|file|image|month|number|password|radio|range|reset|search|submit|time|url|week)/i, 1328 count = 0; 1329 /*jslint unparam: true*/ 1330 /* index of successful elements */ 1331 $.each(allFormElements[0], function (i, field) { 1332 if (field.name !== '' && rsubmittable.test(field.localName) && !rsubmitterTypes.test(field.type) && !field.disabled && (field.checked || !rcheckableType.test(field.type))) { 1333 scIndex.push(count); 1334 count = count + 1; 1335 } else { 1336 scIndex.push(-1); 1337 } 1338 }); 1339 /* index of all inputs tags */ 1340 count = 0; 1341 $.each(allFormElements[0], function (i, field) { 1342 if (field.localName === 'input' && (field.type === '' || field.type === 'text' || field.type === 'hidden' || field.type === 'tel')) { 1343 aiIndex.push(count); 1344 count = count + 1; 1345 } else { 1346 aiIndex.push(-1); 1347 if (field.localName === 'input' && rnonAutoNumericTypes.test(field.type)) { 1348 count = count + 1; 1349 } 1350 } 1351 }); 1352 $.each(formFields, function (i, field) { 1353 var scElement = $.inArray(i, scIndex); 1354 if (scElement > -1 && aiIndex[scElement] > -1) { 1355 var testInput = $('form:eq(' + formIndex + ') input:eq(' + aiIndex[scElement] + ')'), 1356 settings = testInput.data('autoNumeric'); 1357 if (typeof settings === 'object') { 1358 field.value = $('form:eq(' + formIndex + ') input:eq(' + aiIndex[scElement] + ')').autoNumeric('get').toString(); 1359 isAutoNumeric = true; 1360 } 1361 } 1362 }); 1363 /*jslint unparam: false*/ 1364 if (!isAutoNumeric) { 1365 $.error("None of the successful form inputs are initialized by autoNumeric."); 1366 } 1367 return formFields; 1368 }, 1369 1370 /** 1371 * The 'getSteetings returns the object with autoNumeric settings for those who need to look under the hood 1372 * $(someSelector).autoNumeric('getSettings'); // no parameters accepted 1373 * $(someSelector).autoNumeric('getSettings').aDec; // return the aDec setting as a string - ant valid setting can be used 1374 */ 1375 getSettings: function () { 1376 var $this = autoGet($(this)); 1377 return $this.eq(0).data('autoNumeric'); 1378 } 1379 }; 1380 1381 /** 1382 * autoNumeric function 1383 */ 1384 $.fn.autoNumeric = function (method) { 1385 if (methods[method]) { 1386 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 1387 } 1388 if (typeof method === 'object' || !method) { 1389 return methods.init.apply(this, arguments); 1390 } 1391 $.error('Method "' + method + '" is not supported by autoNumeric()'); 1392 }; 1393 1394 /** 1395 * Defaults are public - these can be overridden by the following: 1396 * HTML5 data attributes 1397 * Options passed by the 'init' or 'update' methods 1398 * Use jQuery's $.extend method - great way to pass ASP.NET current culture settings 1399 */ 1400 $.fn.autoNumeric.defaults = { 1401 /** allowed thousand separator characters 1402 * comma = ',' 1403 * period "full stop" = '.' 1404 * apostrophe is escaped = '\'' 1405 * space = ' ' 1406 * none = '' 1407 * NOTE: do not use numeric characters 1408 */ 1409 aSep: ',', 1410 /** digital grouping for the thousand separator used in Format 1411 * dGroup: '2', results in 99,99,99,999 common in India for values less than 1 billion and greater than -1 billion 1412 * dGroup: '3', results in 999,999,999 default 1413 * dGroup: '4', results in 9999,9999,9999 used in some Asian countries 1414 */ 1415 dGroup: '3', 1416 /** allowed decimal separator characters 1417 * period "full stop" = '.' 1418 * comma = ',' 1419 */ 1420 aDec: '.', 1421 /** allow to declare alternative decimal separator which is automatically replaced by aDec
1422 * developed for countries the use a comma ',' as the decimal character 1423 * and have keyboards\numeric pads that have a period 'full stop' as the decimal characters (Spain is an example) 1424 */ 1425 altDec: null, 1426 /** allowed currency symbol 1427 * Must be in quotes aSign: '$', a space is allowed aSign: '$ ' 1428 */ 1429 aSign: '', 1430 /** placement of currency sign 1431 * for prefix pSign: 'p', 1432 * for suffix pSign: 's', 1433 */ 1434 pSign: 'p', 1435 /** maximum possible value 1436 * value must be enclosed in quotes and use the period for the decimal point 1437 * value must be larger than vMin 1438 */ 1439 vMax: '9999999999999.99', 1440 /** minimum possible value 1441 * value must be enclosed in quotes and use the period for the decimal point 1442 * value must be smaller than vMax 1443 */ 1444 vMin: '-9999999999999.99', 1445 /** max number of decimal places = used to override decimal places set by the vMin & vMax values 1446 * value must be enclosed in quotes example mDec: '3', 1447 * This can also set the value via a call back function mDec: 'css:# 1448 */ 1449 mDec: null, 1450 /** method used for rounding 1451 * mRound: 'S', Round-Half-Up Symmetric (default) 1452 * mRound: 'A', Round-Half-Up Asymmetric 1453 * mRound: 's', Round-Half-Down Symmetric (lower case s) 1454 * mRound: 'a', Round-Half-Down Asymmetric (lower case a) 1455 * mRound: 'B', Round-Half-Even "Bankers Rounding" 1456 * mRound: 'U', Round Up "Round-Away-From-Zero" 1457 * mRound: 'D', Round Down "Round-Toward-Zero" - same as truncate 1458 * mRound: 'C', Round to Ceiling "Toward Positive Infinity" 1459 * mRound: 'F', Round to Floor "Toward Negative Infinity" 1460 */ 1461 mRound: 'S', 1462 /** controls decimal padding 1463 * aPad: true - always Pad decimals with zeros 1464 * aPad: false - does not pad with zeros. 1465 * aPad: `some number` - pad decimals with zero to number different from mDec 1466 * thanks to Jonas Johansson for the suggestion 1467 */ 1468 aPad: true, 1469 /** places brackets on negative value -$ 999.99 to (999.99) 1470 * visible only when the field does NOT have focus the left and right symbols should be enclosed in quotes and seperated by a comma 1471 * nBracket: null, nBracket: '(,)', nBracket: '[,]', nBracket: '<,>' or nBracket: '{,}' 1472 */ 1473 nBracket: null, 1474 /** Displayed on empty string 1475 * wEmpty: 'empty', - input can be blank 1476 * wEmpty: 'zero', - displays zero 1477 * wEmpty: 'sign', - displays the currency sign 1478 */ 1479 wEmpty: 'empty', 1480 /** controls leading zero behavior 1481 * lZero: 'allow', - allows leading zeros to be entered. Zeros will be truncated when entering additional digits. On focusout zeros will be deleted. 1482 * lZero: 'deny', - allows only one leading zero on values less than one 1483 * lZero: 'keep', - allows leading zeros to be entered. on fousout zeros will be retained. 1484 */ 1485 lZero: 'allow', 1486 /** determine if the select all keyboard command will select 1487 * the complete input text or only the input numeric value 1488 * if the currency symbol is between the numeric value and the negative sign only the numeric value will sellected 1489 */ 1490 sNumber: true, 1491 /** determine if the default value will be formatted on page ready. 1492 * true = automatically formats the default value on page ready 1493 * false = will not format the default value 1494 */ 1495 aForm: true, 1496 /** helper option for ASP.NET postback 1497 * should be the value of the unformatted default value 1498 * examples: 1499 * no default value='' {anDefault: ''} 1500 * value=1234.56 {anDefault: '1234.56'} 1501 */ 1502 anDefault: null 1503 }; 1504}));
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.