jquery.number.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. /**
  2. * jQuery number plug-in 2.1.5
  3. * Copyright 2012, Digital Fusion
  4. * Licensed under the MIT license.
  5. * http://opensource.teamdf.com/license/
  6. *
  7. * A jQuery plugin which implements a permutation of phpjs.org's number_format to provide
  8. * simple number formatting, insertion, and as-you-type masking of a number.
  9. *
  10. * @author Sam Sehnert
  11. * @docs http://www.teamdf.com/web/jquery-number-format-redux/196/
  12. */
  13. (function($){
  14. "use strict";
  15. /**
  16. * Method for selecting a range of characters in an input/textarea.
  17. *
  18. * @param int rangeStart : Where we want the selection to start.
  19. * @param int rangeEnd : Where we want the selection to end.
  20. *
  21. * @return void;
  22. */
  23. function setSelectionRange( rangeStart, rangeEnd )
  24. {
  25. // Check which way we need to define the text range.
  26. if( this.createTextRange )
  27. {
  28. var range = this.createTextRange();
  29. range.collapse( true );
  30. range.moveStart( 'character', rangeStart );
  31. range.moveEnd( 'character', rangeEnd-rangeStart );
  32. range.select();
  33. }
  34. // Alternate setSelectionRange method for supporting browsers.
  35. else if( this.setSelectionRange )
  36. {
  37. this.focus();
  38. this.setSelectionRange( rangeStart, rangeEnd );
  39. }
  40. }
  41. /**
  42. * Get the selection position for the given part.
  43. *
  44. * @param string part : Options, 'Start' or 'End'. The selection position to get.
  45. *
  46. * @return int : The index position of the selection part.
  47. */
  48. function getSelection( part )
  49. {
  50. var pos = this.value.length;
  51. // Work out the selection part.
  52. part = ( part.toLowerCase() == 'start' ? 'Start' : 'End' );
  53. if( document.selection ){
  54. // The current selection
  55. var range = document.selection.createRange(), stored_range, selectionStart, selectionEnd;
  56. // We'll use this as a 'dummy'
  57. stored_range = range.duplicate();
  58. // Select all text
  59. //stored_range.moveToElementText( this );
  60. stored_range.expand('textedit');
  61. // Now move 'dummy' end point to end point of original range
  62. stored_range.setEndPoint( 'EndToEnd', range );
  63. // Now we can calculate start and end points
  64. selectionStart = stored_range.text.length - range.text.length;
  65. selectionEnd = selectionStart + range.text.length;
  66. return part == 'Start' ? selectionStart : selectionEnd;
  67. }
  68. else if(typeof(this['selection'+part])!="undefined")
  69. {
  70. pos = this['selection'+part];
  71. }
  72. return pos;
  73. }
  74. /**
  75. * Substitutions for keydown keycodes.
  76. * Allows conversion from e.which to ascii characters.
  77. */
  78. var _keydown = {
  79. codes : {
  80. 46 : 127,
  81. 188 : 44,
  82. 109 : 45,
  83. 190 : 46,
  84. 191 : 47,
  85. 192 : 96,
  86. 220 : 92,
  87. 222 : 39,
  88. 221 : 93,
  89. 219 : 91,
  90. 173 : 45,
  91. 187 : 61, //IE Key codes
  92. 186 : 59, //IE Key codes
  93. 189 : 45, //IE Key codes
  94. 110 : 46 //IE Key codes
  95. },
  96. shifts : {
  97. 96 : "~",
  98. 49 : "!",
  99. 50 : "@",
  100. 51 : "#",
  101. 52 : "$",
  102. 53 : "%",
  103. 54 : "^",
  104. 55 : "&",
  105. 56 : "*",
  106. 57 : "(",
  107. 48 : ")",
  108. 45 : "_",
  109. 61 : "+",
  110. 91 : "{",
  111. 93 : "}",
  112. 92 : "|",
  113. 59 : ":",
  114. 39 : "\"",
  115. 44 : "<",
  116. 46 : ">",
  117. 47 : "?"
  118. }
  119. };
  120. /**
  121. * jQuery number formatter plugin. This will allow you to format numbers on an element.
  122. *
  123. * @params proxied for format_number method.
  124. *
  125. * @return : The jQuery collection the method was called with.
  126. */
  127. $.fn.number = function( number, decimals, dec_point, thousands_sep ){
  128. // Enter the default thousands separator, and the decimal placeholder.
  129. thousands_sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep;
  130. dec_point = (typeof dec_point === 'undefined') ? '.' : dec_point;
  131. decimals = (typeof decimals === 'undefined' ) ? 0 : decimals;
  132. // Work out the unicode character for the decimal placeholder.
  133. var u_dec = ('\\u'+('0000'+(dec_point.charCodeAt(0).toString(16))).slice(-4)),
  134. regex_dec_num = new RegExp('[^'+u_dec+'0-9]','g'),
  135. regex_dec = new RegExp(u_dec,'g');
  136. // If we've specified to take the number from the target element,
  137. // we loop over the collection, and get the number.
  138. if( number === true )
  139. {
  140. // If this element is a number, then we add a keyup
  141. if( this.is('input:text') )
  142. {
  143. // Return the jquery collection.
  144. return this.on({
  145. /**
  146. * Handles keyup events, re-formatting numbers.
  147. *
  148. * Uses 'data' object to keep track of important information.
  149. *
  150. * data.c
  151. * This variable keeps track of where the caret *should* be. It works out the position as
  152. * the number of characters from the end of the string. E.g., '1^,234.56' where ^ denotes the caret,
  153. * would be index -7 (e.g., 7 characters from the end of the string). At the end of both the key down
  154. * and key up events, we'll re-position the caret to wherever data.c tells us the cursor should be.
  155. * This gives us a mechanism for incrementing the cursor position when we come across decimals, commas
  156. * etc. This figure typically doesn't increment for each keypress when to the left of the decimal,
  157. * but does when to the right of the decimal.
  158. *
  159. * @param object e : the keyup event object.s
  160. *
  161. * @return void;
  162. */
  163. 'keydown.format' : function(e){
  164. // Define variables used in the code below.
  165. var $this = $(this),
  166. data = $this.data('numFormat'),
  167. code = (e.keyCode ? e.keyCode : e.which),
  168. chara = '', //unescape(e.originalEvent.keyIdentifier.replace('U+','%u')),
  169. start = getSelection.apply(this,['start']),
  170. end = getSelection.apply(this,['end']),
  171. val = '',
  172. setPos = false;
  173. // Webkit (Chrome & Safari) on windows screws up the keyIdentifier detection
  174. // for numpad characters. I've disabled this for now, because while keyCode munging
  175. // below is hackish and ugly, it actually works cross browser & platform.
  176. // if( typeof e.originalEvent.keyIdentifier !== 'undefined' )
  177. // {
  178. // chara = unescape(e.originalEvent.keyIdentifier.replace('U+','%u'));
  179. // }
  180. // else
  181. // {
  182. if (_keydown.codes.hasOwnProperty(code)) {
  183. code = _keydown.codes[code];
  184. }
  185. if (!e.shiftKey && (code >= 65 && code <= 90)){
  186. code += 32;
  187. } else if (!e.shiftKey && (code >= 69 && code <= 105)){
  188. code -= 48;
  189. } else if (e.shiftKey && _keydown.shifts.hasOwnProperty(code)){
  190. //get shifted keyCode value
  191. chara = _keydown.shifts[code];
  192. }
  193. if( chara == '' ) chara = String.fromCharCode(code);
  194. // }
  195. // Stop executing if the user didn't type a number key, a decimal character, backspace, or delete.
  196. if( code != 8 && code != 45 && code != 127 && chara != dec_point && !chara.match(/[0-9]/) )
  197. {
  198. // We need the original keycode now...
  199. var key = (e.keyCode ? e.keyCode : e.which);
  200. if( // Allow control keys to go through... (delete, backspace, tab, enter, escape etc)
  201. key == 46 || key == 8 || key == 127 || key == 9 || key == 27 || key == 13 ||
  202. // Allow: Ctrl+A, Ctrl+R, Ctrl+P, Ctrl+S, Ctrl+F, Ctrl+H, Ctrl+B, Ctrl+J, Ctrl+T, Ctrl+Z, Ctrl++, Ctrl+-, Ctrl+0
  203. ( (key == 65 || key == 82 || key == 80 || key == 83 || key == 70 || key == 72 || key == 66 || key == 74 || key == 84 || key == 90|| key == 61 || key == 173 || key == 48) && ( e.ctrlKey || e.metaKey ) === true ) ||
  204. // Allow: Ctrl+V, Ctrl+C, Ctrl+X
  205. ( (key == 86 || key == 67 || key == 88) && ( e.ctrlKey || e.metaKey ) === true ) ||
  206. // Allow: home, end, left, right
  207. ( (key >= 35 && key <= 39) ) ||
  208. // Allow: F1-F12
  209. ( (key >= 112 && key <= 123) )
  210. ){
  211. return;
  212. }
  213. // But prevent all other keys.
  214. e.preventDefault();
  215. return false;
  216. }
  217. // The whole lot has been selected, or if the field is empty...
  218. if( start == 0 && end == this.value.length ) //|| $this.val() == 0 )
  219. {
  220. if( code == 8 ) // Backspace
  221. {
  222. // Blank out the field, but only if the data object has already been instantiated.
  223. start = end = 1;
  224. this.value = '';
  225. // Reset the cursor position.
  226. data.init = (decimals>0?-1:0);
  227. data.c = (decimals>0?-(decimals+1):0);
  228. setSelectionRange.apply(this, [0,0]);
  229. }
  230. else if( chara == dec_point )
  231. {
  232. start = end = 1;
  233. this.value = '0'+ dec_point + (new Array(decimals+1).join('0'));
  234. // Reset the cursor position.
  235. data.init = (decimals>0?1:0);
  236. data.c = (decimals>0?-(decimals+1):0);
  237. }
  238. else if( code == 45 ) // Negative sign
  239. {
  240. start = end = 2;
  241. this.value = '-0'+dec_point + (new Array(decimals+1).join('0'));
  242. // Reset the cursor position.
  243. data.init = (decimals>0?1:0);
  244. data.c = (decimals>0?-(decimals+1):0);
  245. setSelectionRange.apply(this, [2,2]);
  246. }
  247. else
  248. {
  249. // Reset the cursor position.
  250. data.init = (decimals>0?-1:0);
  251. data.c = (decimals>0?-(decimals):0);
  252. }
  253. }
  254. // Otherwise, we need to reset the caret position
  255. // based on the users selection.
  256. else
  257. {
  258. data.c = end-this.value.length;
  259. }
  260. // Track if partial selection was used
  261. data.isPartialSelection = start == end ? false : true;
  262. // If the start position is before the decimal point,
  263. // and the user has typed a decimal point, we need to move the caret
  264. // past the decimal place.
  265. if( decimals > 0 && chara == dec_point && start == this.value.length-decimals-1 )
  266. {
  267. data.c++;
  268. data.init = Math.max(0,data.init);
  269. e.preventDefault();
  270. // Set the selection position.
  271. setPos = this.value.length+data.c;
  272. }
  273. // Ignore negative sign unless at beginning of number (and it's not already present)
  274. else if( code == 45 && (start != 0 || this.value.indexOf('-') == 0) )
  275. {
  276. e.preventDefault();
  277. }
  278. // If the user is just typing the decimal place,
  279. // we simply ignore it.
  280. else if( chara == dec_point )
  281. {
  282. data.init = Math.max(0,data.init);
  283. e.preventDefault();
  284. }
  285. // If hitting the delete key, and the cursor is before a decimal place,
  286. // we simply move the cursor to the other side of the decimal place.
  287. else if( decimals > 0 && code == 127 && start == this.value.length-decimals-1 )
  288. {
  289. // Just prevent default but don't actually move the caret here because it's done in the keyup event
  290. e.preventDefault();
  291. }
  292. // If hitting the backspace key, and the cursor is behind a decimal place,
  293. // we simply move the cursor to the other side of the decimal place.
  294. else if( decimals > 0 && code == 8 && start == this.value.length-decimals )
  295. {
  296. e.preventDefault();
  297. data.c--;
  298. // Set the selection position.
  299. setPos = this.value.length+data.c;
  300. }
  301. // If hitting the delete key, and the cursor is to the right of the decimal
  302. // we replace the character after the caret with a 0.
  303. else if( decimals > 0 && code == 127 && start > this.value.length-decimals-1 )
  304. {
  305. if( this.value === '' ) return;
  306. // If the character following is not already a 0,
  307. // replace it with one.
  308. if( this.value.slice(start, start+1) != '0' )
  309. {
  310. val = this.value.slice(0, start) + '0' + this.value.slice(start+1);
  311. // The regex replacement below removes negative sign from numbers...
  312. // not sure why they're necessary here when none of the other cases use them
  313. //$this.val(val.replace(regex_dec_num,'').replace(regex_dec,dec_point));
  314. $this.val(val);
  315. }
  316. e.preventDefault();
  317. // Set the selection position.
  318. setPos = this.value.length+data.c;
  319. }
  320. // If hitting the backspace key, and the cursor is to the right of the decimal
  321. // (but not directly to the right) we replace the character preceding the
  322. // caret with a 0.
  323. else if( decimals > 0 && code == 8 && start > this.value.length-decimals )
  324. {
  325. if( this.value === '' ) return;
  326. // If the character preceding is not already a 0,
  327. // replace it with one.
  328. if( this.value.slice(start-1, start) != '0' )
  329. {
  330. val = this.value.slice(0, start-1) + '0' + this.value.slice(start);
  331. // The regex replacement below removes negative sign from numbers...
  332. // not sure why they're necessary here when none of the other cases use them
  333. //$this.val(val.replace(regex_dec_num,'').replace(regex_dec,dec_point));
  334. $this.val(val);
  335. }
  336. e.preventDefault();
  337. data.c--;
  338. // Set the selection position.
  339. setPos = this.value.length+data.c;
  340. }
  341. // If the delete key was pressed, and the character immediately
  342. // after the caret is a thousands_separator character, simply
  343. // step over it.
  344. else if( code == 127 && this.value.slice(start, start+1) == thousands_sep )
  345. {
  346. // Just prevent default but don't actually move the caret here because it's done in the keyup event
  347. e.preventDefault();
  348. }
  349. // If the backspace key was pressed, and the character immediately
  350. // before the caret is a thousands_separator character, simply
  351. // step over it.
  352. else if( code == 8 && this.value.slice(start-1, start) == thousands_sep )
  353. {
  354. e.preventDefault();
  355. data.c--;
  356. // Set the selection position.
  357. setPos = this.value.length+data.c;
  358. }
  359. // If the caret is to the right of the decimal place, and the user is entering a
  360. // number, remove the following character before putting in the new one.
  361. else if(
  362. decimals > 0 &&
  363. start == end &&
  364. this.value.length > decimals+1 &&
  365. start > this.value.length-decimals-1 && isFinite(+chara) &&
  366. !e.metaKey && !e.ctrlKey && !e.altKey && chara.length === 1
  367. )
  368. {
  369. // If the character preceding is not already a 0,
  370. // replace it with one.
  371. if( end === this.value.length )
  372. {
  373. val = this.value.slice(0, start-1);
  374. }
  375. else
  376. {
  377. val = this.value.slice(0, start)+this.value.slice(start+1);
  378. }
  379. // Reset the position.
  380. this.value = val;
  381. setPos = start;
  382. }
  383. // If we need to re-position the characters.
  384. if( setPos !== false )
  385. {
  386. //console.log('Setpos keydown: ', setPos );
  387. setSelectionRange.apply(this, [setPos, setPos]);
  388. }
  389. // Store the data on the element.
  390. $this.data('numFormat', data);
  391. },
  392. /**
  393. * Handles keyup events, re-formatting numbers.
  394. *
  395. * @param object e : the keyup event object.s
  396. *
  397. * @return void;
  398. */
  399. 'keyup.format' : function(e){
  400. // Store these variables for use below.
  401. var $this = $(this),
  402. data = $this.data('numFormat'),
  403. code = (e.keyCode ? e.keyCode : e.which),
  404. start = getSelection.apply(this,['start']),
  405. end = getSelection.apply(this,['end']),
  406. setPos;
  407. // Check for negative characters being entered at the start of the string.
  408. // If there's any kind of selection, just ignore the input.
  409. if( start === 0 && end === 0 && ( code === 189 || code === 109 ) )
  410. {
  411. $this.val('-'+$this.val());
  412. start = 1;
  413. data.c = 1-this.value.length;
  414. data.init = 1;
  415. $this.data('numFormat', data);
  416. setPos = this.value.length+data.c;
  417. setSelectionRange.apply(this, [setPos, setPos]);
  418. }
  419. // Stop executing if the user didn't type a number key, a decimal, or a comma.
  420. if( this.value === '' || (code < 48 || code > 57) && (code < 96 || code > 105 ) && code !== 8 && code !== 46 && code !== 110 ) return;
  421. // Re-format the textarea.
  422. $this.val($this.val());
  423. if( decimals > 0 )
  424. {
  425. // If we haven't marked this item as 'initialized'
  426. // then do so now. It means we should place the caret just
  427. // before the decimal. This will never be un-initialized before
  428. // the decimal character itself is entered.
  429. if( data.init < 1 )
  430. {
  431. start = this.value.length-decimals-( data.init < 0 ? 1 : 0 );
  432. data.c = start-this.value.length;
  433. data.init = 1;
  434. $this.data('numFormat', data);
  435. }
  436. // Increase the cursor position if the caret is to the right
  437. // of the decimal place, and the character pressed isn't the backspace key.
  438. else if( start > this.value.length-decimals && code != 8 )
  439. {
  440. data.c++;
  441. // Store the data, now that it's changed.
  442. $this.data('numFormat', data);
  443. }
  444. }
  445. // Move caret to the right after delete key pressed
  446. if (code == 46 && !data.isPartialSelection)
  447. {
  448. data.c++;
  449. // Store the data, now that it's changed.
  450. $this.data('numFormat', data);
  451. }
  452. //console.log( 'Setting pos: ', start, decimals, this.value.length + data.c, this.value.length, data.c );
  453. // Set the selection position.
  454. setPos = this.value.length+data.c;
  455. setSelectionRange.apply(this, [setPos, setPos]);
  456. },
  457. /**
  458. * Reformat when pasting into the field.
  459. *
  460. * @param object e : jQuery event object.
  461. *
  462. * @return false : prevent default action.
  463. */
  464. 'paste.format' : function(e){
  465. // Defint $this. It's used twice!.
  466. var $this = $(this),
  467. original = e.originalEvent,
  468. val = null;
  469. // Get the text content stream.
  470. if (window.clipboardData && window.clipboardData.getData) { // IE
  471. val = window.clipboardData.getData('Text');
  472. } else if (original.clipboardData && original.clipboardData.getData) {
  473. val = original.clipboardData.getData('text/plain');
  474. }
  475. // Do the reformat operation.
  476. $this.val(val);
  477. // Stop the actual content from being pasted.
  478. e.preventDefault();
  479. return false;
  480. }
  481. })
  482. // Loop each element (which isn't blank) and do the format.
  483. .each(function(){
  484. var $this = $(this).data('numFormat',{
  485. c : -(decimals+1),
  486. decimals : decimals,
  487. thousands_sep : thousands_sep,
  488. dec_point : dec_point,
  489. regex_dec_num : regex_dec_num,
  490. regex_dec : regex_dec,
  491. init : this.value.indexOf('.') ? true : false
  492. });
  493. // Return if the element is empty.
  494. if( this.value === '' ) return;
  495. // Otherwise... format!!
  496. $this.val($this.val());
  497. });
  498. }
  499. else
  500. {
  501. // return the collection.
  502. return this.each(function(){
  503. var $this = $(this), num = +$this.text().replace(regex_dec_num,'').replace(regex_dec,'.');
  504. $this.number( !isFinite(num) ? 0 : +num, decimals, dec_point, thousands_sep );
  505. });
  506. }
  507. }
  508. // Add this number to the element as text.
  509. return this.text( $.number.apply(window,arguments) );
  510. };
  511. //
  512. // Create .val() hooks to get and set formatted numbers in inputs.
  513. //
  514. // We check if any hooks already exist, and cache
  515. // them in case we need to re-use them later on.
  516. var origHookGet = null, origHookSet = null;
  517. // Check if a text valHook already exists.
  518. if( $.isPlainObject( $.valHooks.text ) )
  519. {
  520. // Preserve the original valhook function
  521. // we'll call this for values we're not
  522. // explicitly handling.
  523. if( $.isFunction( $.valHooks.text.get ) ) origHookGet = $.valHooks.text.get;
  524. if( $.isFunction( $.valHooks.text.set ) ) origHookSet = $.valHooks.text.set;
  525. }
  526. else
  527. {
  528. // Define an object for the new valhook.
  529. $.valHooks.text = {};
  530. }
  531. /**
  532. * Define the valHook to return normalised field data against an input
  533. * which has been tagged by the number formatter.
  534. *
  535. * @param object el : The raw DOM element that we're getting the value from.
  536. *
  537. * @return mixed : Returns the value that was written to the element as a
  538. * javascript number, or undefined to let jQuery handle it normally.
  539. */
  540. $.valHooks.text.get = function( el ){
  541. // Get the element, and its data.
  542. var $this = $(el), num, negative,
  543. data = $this.data('numFormat');
  544. // Does this element have our data field?
  545. if( !data )
  546. {
  547. // Check if the valhook function already existed
  548. if( $.isFunction( origHookGet ) )
  549. {
  550. // There was, so go ahead and call it
  551. return origHookGet(el);
  552. }
  553. else
  554. {
  555. // No previous function, return undefined to have jQuery
  556. // take care of retrieving the value
  557. return undefined;
  558. }
  559. }
  560. else
  561. {
  562. // Remove formatting, and return as number.
  563. if( el.value === '' ) return '';
  564. // Convert to a number.
  565. num = +(el.value
  566. .replace( data.regex_dec_num, '' )
  567. .replace( data.regex_dec, '.' ));
  568. // If we've got a finite number, return it.
  569. // Otherwise, simply return 0.
  570. // Return as a string... thats what we're
  571. // used to with .val()
  572. return (el.value.indexOf('-') === 0 ? '-' : '')+( isFinite( num ) ? num : 0 );
  573. }
  574. };
  575. /**
  576. * A valhook which formats a number when run against an input
  577. * which has been tagged by the number formatter.
  578. *
  579. * @param object el : The raw DOM element (input element).
  580. * @param float : The number to set into the value field.
  581. *
  582. * @return mixed : Returns the value that was written to the element,
  583. * or undefined to let jQuery handle it normally.
  584. */
  585. $.valHooks.text.set = function( el, val )
  586. {
  587. // Get the element, and its data.
  588. var $this = $(el),
  589. data = $this.data('numFormat');
  590. // Does this element have our data field?
  591. if( !data )
  592. {
  593. // Check if the valhook function already exists
  594. if( $.isFunction( origHookSet ) )
  595. {
  596. // There was, so go ahead and call it
  597. return origHookSet(el,val);
  598. }
  599. else
  600. {
  601. // No previous function, return undefined to have jQuery
  602. // take care of retrieving the value
  603. return undefined;
  604. }
  605. }
  606. else
  607. {
  608. var num = $.number( val, data.decimals, data.dec_point, data.thousands_sep );
  609. // Make sure empties are set with correct signs.
  610. // if(val.indexOf('-') === 0 && +num === 0)
  611. // {
  612. // num = '-'+num;
  613. // }
  614. return $.isFunction(origHookSet) ? origHookSet(el, num) : el.value = num;
  615. }
  616. };
  617. /**
  618. * The (modified) excellent number formatting method from PHPJS.org.
  619. * http://phpjs.org/functions/number_format/
  620. *
  621. * @modified by Sam Sehnert (teamdf.com)
  622. * - don't redefine dec_point, thousands_sep... just overwrite with defaults.
  623. * - don't redefine decimals, just overwrite as numeric.
  624. * - Generate regex for normalizing pre-formatted numbers.
  625. *
  626. * @param float number : The number you wish to format, or TRUE to use the text contents
  627. * of the element as the number. Please note that this won't work for
  628. * elements which have child nodes with text content.
  629. * @param int decimals : The number of decimal places that should be displayed. Defaults to 0.
  630. * @param string dec_point : The character to use as a decimal point. Defaults to '.'.
  631. * @param string thousands_sep : The character to use as a thousands separator. Defaults to ','.
  632. *
  633. * @return string : The formatted number as a string.
  634. */
  635. $.number = function( number, decimals, dec_point, thousands_sep ){
  636. // Set the default values here, instead so we can use them in the replace below.
  637. thousands_sep = (typeof thousands_sep === 'undefined') ? ( new Number(1000).toLocaleString() !== '1000' ? new Number(1000).toLocaleString().charAt(1) : '' ) : thousands_sep;
  638. dec_point = (typeof dec_point === 'undefined') ? new Number(0.1).toLocaleString().charAt(1) : dec_point;
  639. decimals = !isFinite(+decimals) ? 0 : Math.abs(decimals);
  640. // Work out the unicode representation for the decimal place and thousand sep.
  641. var u_dec = ('\\u'+('0000'+(dec_point.charCodeAt(0).toString(16))).slice(-4));
  642. var u_sep = ('\\u'+('0000'+(thousands_sep.charCodeAt(0).toString(16))).slice(-4));
  643. // Fix the number, so that it's an actual number.
  644. number = (number + '')
  645. .replace('\.', dec_point) // because the number if passed in as a float (having . as decimal point per definition) we need to replace this with the passed in decimal point character
  646. .replace(new RegExp(u_sep,'g'),'')
  647. .replace(new RegExp(u_dec,'g'),'.')
  648. .replace(new RegExp('[^0-9+\-Ee.]','g'),'');
  649. var n = !isFinite(+number) ? 0 : +number,
  650. s = '',
  651. toFixedFix = function (n, decimals) {
  652. return '' + (+(Math.round(('' + n).indexOf('e') > 0 ? n : n + 'e+' + decimals) + 'e-' + decimals));
  653. };
  654. // Fix for IE parseFloat(0.55).toFixed(0) = 0;
  655. s = (decimals ? toFixedFix(n, decimals) : '' + Math.round(n)).split('.');
  656. if (s[0].length > 3) {
  657. s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, thousands_sep);
  658. }
  659. if ((s[1] || '').length < decimals) {
  660. s[1] = s[1] || '';
  661. s[1] += new Array(decimals - s[1].length + 1).join('0');
  662. }
  663. return s.join(dec_point);
  664. }
  665. })(jQuery);