numeral.js 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. /*! @preserve
  2. * numeral.js
  3. * version : 2.0.6
  4. * author : Adam Draper
  5. * license : MIT
  6. * http://adamwdraper.github.com/Numeral-js/
  7. */
  8. (function (global, factory) {
  9. if (typeof define === 'function' && define.amd) {
  10. define(factory);
  11. } else if (typeof module === 'object' && module.exports) {
  12. module.exports = factory();
  13. } else {
  14. global.numeral = factory();
  15. }
  16. }(this, function () {
  17. /************************************
  18. Variables
  19. ************************************/
  20. var numeral,
  21. _,
  22. VERSION = '2.0.6',
  23. formats = {},
  24. locales = {},
  25. defaults = {
  26. currentLocale: 'en',
  27. zeroFormat: null,
  28. nullFormat: null,
  29. defaultFormat: '0,0',
  30. scalePercentBy100: true
  31. },
  32. options = {
  33. currentLocale: defaults.currentLocale,
  34. zeroFormat: defaults.zeroFormat,
  35. nullFormat: defaults.nullFormat,
  36. defaultFormat: defaults.defaultFormat,
  37. scalePercentBy100: defaults.scalePercentBy100
  38. };
  39. /************************************
  40. Constructors
  41. ************************************/
  42. // Numeral prototype object
  43. function Numeral(input, number) {
  44. this._input = input;
  45. this._value = number;
  46. }
  47. numeral = function(input) {
  48. var value,
  49. kind,
  50. unformatFunction,
  51. regexp;
  52. if (numeral.isNumeral(input)) {
  53. value = input.value();
  54. } else if (input === 0 || typeof input === 'undefined') {
  55. value = 0;
  56. } else if (input === null || _.isNaN(input)) {
  57. value = null;
  58. } else if (typeof input === 'string') {
  59. if (options.zeroFormat && input === options.zeroFormat) {
  60. value = 0;
  61. } else if (options.nullFormat && input === options.nullFormat || !input.replace(/[^0-9]+/g, '').length) {
  62. value = null;
  63. } else {
  64. for (kind in formats) {
  65. regexp = typeof formats[kind].regexps.unformat === 'function' ? formats[kind].regexps.unformat() : formats[kind].regexps.unformat;
  66. if (regexp && input.match(regexp)) {
  67. unformatFunction = formats[kind].unformat;
  68. break;
  69. }
  70. }
  71. unformatFunction = unformatFunction || numeral._.stringToNumber;
  72. value = unformatFunction(input);
  73. }
  74. } else {
  75. value = Number(input)|| null;
  76. }
  77. return new Numeral(input, value);
  78. };
  79. // version number
  80. numeral.version = VERSION;
  81. // compare numeral object
  82. numeral.isNumeral = function(obj) {
  83. return obj instanceof Numeral;
  84. };
  85. // helper functions
  86. numeral._ = _ = {
  87. // formats numbers separators, decimals places, signs, abbreviations
  88. numberToFormat: function(value, format, roundingFunction) {
  89. var locale = locales[numeral.options.currentLocale],
  90. negP = false,
  91. optDec = false,
  92. leadingCount = 0,
  93. abbr = '',
  94. trillion = 1000000000000,
  95. billion = 1000000000,
  96. million = 1000000,
  97. thousand = 1000,
  98. decimal = '',
  99. neg = false,
  100. abbrForce, // force abbreviation
  101. abs,
  102. min,
  103. max,
  104. power,
  105. int,
  106. precision,
  107. signed,
  108. thousands,
  109. output;
  110. // make sure we never format a null value
  111. value = value || 0;
  112. abs = Math.abs(value);
  113. // see if we should use parentheses for negative number or if we should prefix with a sign
  114. // if both are present we default to parentheses
  115. if (numeral._.includes(format, '(')) {
  116. negP = true;
  117. format = format.replace(/[\(|\)]/g, '');
  118. } else if (numeral._.includes(format, '+') || numeral._.includes(format, '-')) {
  119. signed = numeral._.includes(format, '+') ? format.indexOf('+') : value < 0 ? format.indexOf('-') : -1;
  120. format = format.replace(/[\+|\-]/g, '');
  121. }
  122. // see if abbreviation is wanted
  123. if (numeral._.includes(format, 'a')) {
  124. abbrForce = format.match(/a(k|m|b|t)?/);
  125. abbrForce = abbrForce ? abbrForce[1] : false;
  126. // check for space before abbreviation
  127. if (numeral._.includes(format, ' a')) {
  128. abbr = ' ';
  129. }
  130. format = format.replace(new RegExp(abbr + 'a[kmbt]?'), '');
  131. if (abs >= trillion && !abbrForce || abbrForce === 't') {
  132. // trillion
  133. abbr += locale.abbreviations.trillion;
  134. value = value / trillion;
  135. } else if (abs < trillion && abs >= billion && !abbrForce || abbrForce === 'b') {
  136. // billion
  137. abbr += locale.abbreviations.billion;
  138. value = value / billion;
  139. } else if (abs < billion && abs >= million && !abbrForce || abbrForce === 'm') {
  140. // million
  141. abbr += locale.abbreviations.million;
  142. value = value / million;
  143. } else if (abs < million && abs >= thousand && !abbrForce || abbrForce === 'k') {
  144. // thousand
  145. abbr += locale.abbreviations.thousand;
  146. value = value / thousand;
  147. }
  148. }
  149. // check for optional decimals
  150. if (numeral._.includes(format, '[.]')) {
  151. optDec = true;
  152. format = format.replace('[.]', '.');
  153. }
  154. // break number and format
  155. int = value.toString().split('.')[0];
  156. precision = format.split('.')[1];
  157. thousands = format.indexOf(',');
  158. leadingCount = (format.split('.')[0].split(',')[0].match(/0/g) || []).length;
  159. if (precision) {
  160. if (numeral._.includes(precision, '[')) {
  161. precision = precision.replace(']', '');
  162. precision = precision.split('[');
  163. decimal = numeral._.toFixed(value, (precision[0].length + precision[1].length), roundingFunction, precision[1].length);
  164. } else {
  165. decimal = numeral._.toFixed(value, precision.length, roundingFunction);
  166. }
  167. int = decimal.split('.')[0];
  168. if (numeral._.includes(decimal, '.')) {
  169. decimal = locale.delimiters.decimal + decimal.split('.')[1];
  170. } else {
  171. decimal = '';
  172. }
  173. if (optDec && Number(decimal.slice(1)) === 0) {
  174. decimal = '';
  175. }
  176. } else {
  177. int = numeral._.toFixed(value, 0, roundingFunction);
  178. }
  179. // check abbreviation again after rounding
  180. if (abbr && !abbrForce && Number(int) >= 1000 && abbr !== locale.abbreviations.trillion) {
  181. int = String(Number(int) / 1000);
  182. switch (abbr) {
  183. case locale.abbreviations.thousand:
  184. abbr = locale.abbreviations.million;
  185. break;
  186. case locale.abbreviations.million:
  187. abbr = locale.abbreviations.billion;
  188. break;
  189. case locale.abbreviations.billion:
  190. abbr = locale.abbreviations.trillion;
  191. break;
  192. }
  193. }
  194. // format number
  195. if (numeral._.includes(int, '-')) {
  196. int = int.slice(1);
  197. neg = true;
  198. }
  199. if (int.length < leadingCount) {
  200. for (var i = leadingCount - int.length; i > 0; i--) {
  201. int = '0' + int;
  202. }
  203. }
  204. if (thousands > -1) {
  205. int = int.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + locale.delimiters.thousands);
  206. }
  207. if (format.indexOf('.') === 0) {
  208. int = '';
  209. }
  210. output = int + decimal + (abbr ? abbr : '');
  211. if (negP) {
  212. output = (negP && neg ? '(' : '') + output + (negP && neg ? ')' : '');
  213. } else {
  214. if (signed >= 0) {
  215. output = signed === 0 ? (neg ? '-' : '+') + output : output + (neg ? '-' : '+');
  216. } else if (neg) {
  217. output = '-' + output;
  218. }
  219. }
  220. return output;
  221. },
  222. // unformats numbers separators, decimals places, signs, abbreviations
  223. stringToNumber: function(string) {
  224. var locale = locales[options.currentLocale],
  225. stringOriginal = string,
  226. abbreviations = {
  227. thousand: 3,
  228. million: 6,
  229. billion: 9,
  230. trillion: 12
  231. },
  232. abbreviation,
  233. value,
  234. i,
  235. regexp;
  236. if (options.zeroFormat && string === options.zeroFormat) {
  237. value = 0;
  238. } else if (options.nullFormat && string === options.nullFormat || !string.replace(/[^0-9]+/g, '').length) {
  239. value = null;
  240. } else {
  241. value = 1;
  242. if (locale.delimiters.decimal !== '.') {
  243. string = string.replace(/\./g, '').replace(locale.delimiters.decimal, '.');
  244. }
  245. for (abbreviation in abbreviations) {
  246. regexp = new RegExp('[^a-zA-Z]' + locale.abbreviations[abbreviation] + '(?:\\)|(\\' + locale.currency.symbol + ')?(?:\\))?)?$');
  247. if (stringOriginal.match(regexp)) {
  248. value *= Math.pow(10, abbreviations[abbreviation]);
  249. break;
  250. }
  251. }
  252. // check for negative number
  253. value *= (string.split('-').length + Math.min(string.split('(').length - 1, string.split(')').length - 1)) % 2 ? 1 : -1;
  254. // remove non numbers
  255. string = string.replace(/[^0-9\.]+/g, '');
  256. value *= Number(string);
  257. }
  258. return value;
  259. },
  260. isNaN: function(value) {
  261. return typeof value === 'number' && isNaN(value);
  262. },
  263. includes: function(string, search) {
  264. return string.indexOf(search) !== -1;
  265. },
  266. insert: function(string, subString, start) {
  267. return string.slice(0, start) + subString + string.slice(start);
  268. },
  269. reduce: function(array, callback /*, initialValue*/) {
  270. if (this === null) {
  271. throw new TypeError('Array.prototype.reduce called on null or undefined');
  272. }
  273. if (typeof callback !== 'function') {
  274. throw new TypeError(callback + ' is not a function');
  275. }
  276. var t = Object(array),
  277. len = t.length >>> 0,
  278. k = 0,
  279. value;
  280. if (arguments.length === 3) {
  281. value = arguments[2];
  282. } else {
  283. while (k < len && !(k in t)) {
  284. k++;
  285. }
  286. if (k >= len) {
  287. throw new TypeError('Reduce of empty array with no initial value');
  288. }
  289. value = t[k++];
  290. }
  291. for (; k < len; k++) {
  292. if (k in t) {
  293. value = callback(value, t[k], k, t);
  294. }
  295. }
  296. return value;
  297. },
  298. /**
  299. * Computes the multiplier necessary to make x >= 1,
  300. * effectively eliminating miscalculations caused by
  301. * finite precision.
  302. */
  303. multiplier: function (x) {
  304. var parts = x.toString().split('.');
  305. return parts.length < 2 ? 1 : Math.pow(10, parts[1].length);
  306. },
  307. /**
  308. * Given a variable number of arguments, returns the maximum
  309. * multiplier that must be used to normalize an operation involving
  310. * all of them.
  311. */
  312. correctionFactor: function () {
  313. var args = Array.prototype.slice.call(arguments);
  314. return args.reduce(function(accum, next) {
  315. var mn = _.multiplier(next);
  316. return accum > mn ? accum : mn;
  317. }, 1);
  318. },
  319. /**
  320. * Implementation of toFixed() that treats floats more like decimals
  321. *
  322. * Fixes binary rounding issues (eg. (0.615).toFixed(2) === '0.61') that present
  323. * problems for accounting- and finance-related software.
  324. */
  325. toFixed: function(value, maxDecimals, roundingFunction, optionals) {
  326. var splitValue = value.toString().split('.'),
  327. minDecimals = maxDecimals - (optionals || 0),
  328. boundedPrecision,
  329. optionalsRegExp,
  330. power,
  331. output;
  332. // Use the smallest precision value possible to avoid errors from floating point representation
  333. if (splitValue.length === 2) {
  334. boundedPrecision = Math.min(Math.max(splitValue[1].length, minDecimals), maxDecimals);
  335. } else {
  336. boundedPrecision = minDecimals;
  337. }
  338. power = Math.pow(10, boundedPrecision);
  339. // Multiply up by precision, round accurately, then divide and use native toFixed():
  340. output = (roundingFunction(value + 'e+' + boundedPrecision) / power).toFixed(boundedPrecision);
  341. if (optionals > maxDecimals - boundedPrecision) {
  342. optionalsRegExp = new RegExp('\\.?0{1,' + (optionals - (maxDecimals - boundedPrecision)) + '}$');
  343. output = output.replace(optionalsRegExp, '');
  344. }
  345. return output;
  346. }
  347. };
  348. // avaliable options
  349. numeral.options = options;
  350. // avaliable formats
  351. numeral.formats = formats;
  352. // avaliable formats
  353. numeral.locales = locales;
  354. // This function sets the current locale. If
  355. // no arguments are passed in, it will simply return the current global
  356. // locale key.
  357. numeral.locale = function(key) {
  358. if (key) {
  359. options.currentLocale = key.toLowerCase();
  360. }
  361. return options.currentLocale;
  362. };
  363. // This function provides access to the loaded locale data. If
  364. // no arguments are passed in, it will simply return the current
  365. // global locale object.
  366. numeral.localeData = function(key) {
  367. if (!key) {
  368. return locales[options.currentLocale];
  369. }
  370. key = key.toLowerCase();
  371. if (!locales[key]) {
  372. throw new Error('Unknown locale : ' + key);
  373. }
  374. return locales[key];
  375. };
  376. numeral.reset = function() {
  377. for (var property in defaults) {
  378. options[property] = defaults[property];
  379. }
  380. };
  381. numeral.zeroFormat = function(format) {
  382. options.zeroFormat = typeof(format) === 'string' ? format : null;
  383. };
  384. numeral.nullFormat = function (format) {
  385. options.nullFormat = typeof(format) === 'string' ? format : null;
  386. };
  387. numeral.defaultFormat = function(format) {
  388. options.defaultFormat = typeof(format) === 'string' ? format : '0.0';
  389. };
  390. numeral.register = function(type, name, format) {
  391. name = name.toLowerCase();
  392. if (this[type + 's'][name]) {
  393. throw new TypeError(name + ' ' + type + ' already registered.');
  394. }
  395. this[type + 's'][name] = format;
  396. return format;
  397. };
  398. numeral.validate = function(val, culture) {
  399. var _decimalSep,
  400. _thousandSep,
  401. _currSymbol,
  402. _valArray,
  403. _abbrObj,
  404. _thousandRegEx,
  405. localeData,
  406. temp;
  407. //coerce val to string
  408. if (typeof val !== 'string') {
  409. val += '';
  410. if (console.warn) {
  411. console.warn('Numeral.js: Value is not string. It has been co-erced to: ', val);
  412. }
  413. }
  414. //trim whitespaces from either sides
  415. val = val.trim();
  416. //if val is just digits return true
  417. if (!!val.match(/^\d+$/)) {
  418. return true;
  419. }
  420. //if val is empty return false
  421. if (val === '') {
  422. return false;
  423. }
  424. //get the decimal and thousands separator from numeral.localeData
  425. try {
  426. //check if the culture is understood by numeral. if not, default it to current locale
  427. localeData = numeral.localeData(culture);
  428. } catch (e) {
  429. localeData = numeral.localeData(numeral.locale());
  430. }
  431. //setup the delimiters and currency symbol based on culture/locale
  432. _currSymbol = localeData.currency.symbol;
  433. _abbrObj = localeData.abbreviations;
  434. _decimalSep = localeData.delimiters.decimal;
  435. if (localeData.delimiters.thousands === '.') {
  436. _thousandSep = '\\.';
  437. } else {
  438. _thousandSep = localeData.delimiters.thousands;
  439. }
  440. // validating currency symbol
  441. temp = val.match(/^[^\d]+/);
  442. if (temp !== null) {
  443. val = val.substr(1);
  444. if (temp[0] !== _currSymbol) {
  445. return false;
  446. }
  447. }
  448. //validating abbreviation symbol
  449. temp = val.match(/[^\d]+$/);
  450. if (temp !== null) {
  451. val = val.slice(0, -1);
  452. if (temp[0] !== _abbrObj.thousand && temp[0] !== _abbrObj.million && temp[0] !== _abbrObj.billion && temp[0] !== _abbrObj.trillion) {
  453. return false;
  454. }
  455. }
  456. _thousandRegEx = new RegExp(_thousandSep + '{2}');
  457. if (!val.match(/[^\d.,]/g)) {
  458. _valArray = val.split(_decimalSep);
  459. if (_valArray.length > 2) {
  460. return false;
  461. } else {
  462. if (_valArray.length < 2) {
  463. return ( !! _valArray[0].match(/^\d+.*\d$/) && !_valArray[0].match(_thousandRegEx));
  464. } else {
  465. if (_valArray[0].length === 1) {
  466. return ( !! _valArray[0].match(/^\d+$/) && !_valArray[0].match(_thousandRegEx) && !! _valArray[1].match(/^\d+$/));
  467. } else {
  468. return ( !! _valArray[0].match(/^\d+.*\d$/) && !_valArray[0].match(_thousandRegEx) && !! _valArray[1].match(/^\d+$/));
  469. }
  470. }
  471. }
  472. }
  473. return false;
  474. };
  475. /************************************
  476. Numeral Prototype
  477. ************************************/
  478. numeral.fn = Numeral.prototype = {
  479. clone: function() {
  480. return numeral(this);
  481. },
  482. format: function(inputString, roundingFunction) {
  483. var value = this._value,
  484. format = inputString || options.defaultFormat,
  485. kind,
  486. output,
  487. formatFunction;
  488. // make sure we have a roundingFunction
  489. roundingFunction = roundingFunction || Math.round;
  490. // format based on value
  491. if (value === 0 && options.zeroFormat !== null) {
  492. output = options.zeroFormat;
  493. } else if (value === null && options.nullFormat !== null) {
  494. output = options.nullFormat;
  495. } else {
  496. for (kind in formats) {
  497. if (format.match(formats[kind].regexps.format)) {
  498. formatFunction = formats[kind].format;
  499. break;
  500. }
  501. }
  502. formatFunction = formatFunction || numeral._.numberToFormat;
  503. output = formatFunction(value, format, roundingFunction);
  504. }
  505. return output;
  506. },
  507. value: function() {
  508. return this._value;
  509. },
  510. input: function() {
  511. return this._input;
  512. },
  513. set: function(value) {
  514. this._value = Number(value);
  515. return this;
  516. },
  517. add: function(value) {
  518. var corrFactor = _.correctionFactor.call(null, this._value, value);
  519. function cback(accum, curr, currI, O) {
  520. return accum + Math.round(corrFactor * curr);
  521. }
  522. this._value = _.reduce([this._value, value], cback, 0) / corrFactor;
  523. return this;
  524. },
  525. subtract: function(value) {
  526. var corrFactor = _.correctionFactor.call(null, this._value, value);
  527. function cback(accum, curr, currI, O) {
  528. return accum - Math.round(corrFactor * curr);
  529. }
  530. this._value = _.reduce([value], cback, Math.round(this._value * corrFactor)) / corrFactor;
  531. return this;
  532. },
  533. multiply: function(value) {
  534. function cback(accum, curr, currI, O) {
  535. var corrFactor = _.correctionFactor(accum, curr);
  536. return Math.round(accum * corrFactor) * Math.round(curr * corrFactor) / Math.round(corrFactor * corrFactor);
  537. }
  538. this._value = _.reduce([this._value, value], cback, 1);
  539. return this;
  540. },
  541. divide: function(value) {
  542. function cback(accum, curr, currI, O) {
  543. var corrFactor = _.correctionFactor(accum, curr);
  544. return Math.round(accum * corrFactor) / Math.round(curr * corrFactor);
  545. }
  546. this._value = _.reduce([this._value, value], cback);
  547. return this;
  548. },
  549. difference: function(value) {
  550. return Math.abs(numeral(this._value).subtract(value).value());
  551. }
  552. };
  553. /************************************
  554. Default Locale && Format
  555. ************************************/
  556. numeral.register('locale', 'en', {
  557. delimiters: {
  558. thousands: ',',
  559. decimal: '.'
  560. },
  561. abbreviations: {
  562. thousand: 'k',
  563. million: 'm',
  564. billion: 'b',
  565. trillion: 't'
  566. },
  567. ordinal: function(number) {
  568. var b = number % 10;
  569. return (~~(number % 100 / 10) === 1) ? 'th' :
  570. (b === 1) ? 'st' :
  571. (b === 2) ? 'nd' :
  572. (b === 3) ? 'rd' : 'th';
  573. },
  574. currency: {
  575. symbol: '$'
  576. }
  577. });
  578. (function() {
  579. numeral.register('format', 'bps', {
  580. regexps: {
  581. format: /(BPS)/,
  582. unformat: /(BPS)/
  583. },
  584. format: function(value, format, roundingFunction) {
  585. var space = numeral._.includes(format, ' BPS') ? ' ' : '',
  586. output;
  587. value = value * 10000;
  588. // check for space before BPS
  589. format = format.replace(/\s?BPS/, '');
  590. output = numeral._.numberToFormat(value, format, roundingFunction);
  591. if (numeral._.includes(output, ')')) {
  592. output = output.split('');
  593. output.splice(-1, 0, space + 'BPS');
  594. output = output.join('');
  595. } else {
  596. output = output + space + 'BPS';
  597. }
  598. return output;
  599. },
  600. unformat: function(string) {
  601. return +(numeral._.stringToNumber(string) * 0.0001).toFixed(15);
  602. }
  603. });
  604. })();
  605. (function() {
  606. var decimal = {
  607. base: 1000,
  608. suffixes: ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
  609. },
  610. binary = {
  611. base: 1024,
  612. suffixes: ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
  613. };
  614. var allSuffixes = decimal.suffixes.concat(binary.suffixes.filter(function (item) {
  615. return decimal.suffixes.indexOf(item) < 0;
  616. }));
  617. var unformatRegex = allSuffixes.join('|');
  618. // Allow support for BPS (http://www.investopedia.com/terms/b/basispoint.asp)
  619. unformatRegex = '(' + unformatRegex.replace('B', 'B(?!PS)') + ')';
  620. numeral.register('format', 'bytes', {
  621. regexps: {
  622. format: /([0\s]i?b)/,
  623. unformat: new RegExp(unformatRegex)
  624. },
  625. format: function(value, format, roundingFunction) {
  626. var output,
  627. bytes = numeral._.includes(format, 'ib') ? binary : decimal,
  628. suffix = numeral._.includes(format, ' b') || numeral._.includes(format, ' ib') ? ' ' : '',
  629. power,
  630. min,
  631. max;
  632. // check for space before
  633. format = format.replace(/\s?i?b/, '');
  634. for (power = 0; power <= bytes.suffixes.length; power++) {
  635. min = Math.pow(bytes.base, power);
  636. max = Math.pow(bytes.base, power + 1);
  637. if (value === null || value === 0 || value >= min && value < max) {
  638. suffix += bytes.suffixes[power];
  639. if (min > 0) {
  640. value = value / min;
  641. }
  642. break;
  643. }
  644. }
  645. output = numeral._.numberToFormat(value, format, roundingFunction);
  646. return output + suffix;
  647. },
  648. unformat: function(string) {
  649. var value = numeral._.stringToNumber(string),
  650. power,
  651. bytesMultiplier;
  652. if (value) {
  653. for (power = decimal.suffixes.length - 1; power >= 0; power--) {
  654. if (numeral._.includes(string, decimal.suffixes[power])) {
  655. bytesMultiplier = Math.pow(decimal.base, power);
  656. break;
  657. }
  658. if (numeral._.includes(string, binary.suffixes[power])) {
  659. bytesMultiplier = Math.pow(binary.base, power);
  660. break;
  661. }
  662. }
  663. value *= (bytesMultiplier || 1);
  664. }
  665. return value;
  666. }
  667. });
  668. })();
  669. (function() {
  670. numeral.register('format', 'currency', {
  671. regexps: {
  672. format: /(\$)/
  673. },
  674. format: function(value, format, roundingFunction) {
  675. var locale = numeral.locales[numeral.options.currentLocale],
  676. symbols = {
  677. before: format.match(/^([\+|\-|\(|\s|\$]*)/)[0],
  678. after: format.match(/([\+|\-|\)|\s|\$]*)$/)[0]
  679. },
  680. output,
  681. symbol,
  682. i;
  683. // strip format of spaces and $
  684. format = format.replace(/\s?\$\s?/, '');
  685. // format the number
  686. output = numeral._.numberToFormat(value, format, roundingFunction);
  687. // update the before and after based on value
  688. if (value >= 0) {
  689. symbols.before = symbols.before.replace(/[\-\(]/, '');
  690. symbols.after = symbols.after.replace(/[\-\)]/, '');
  691. } else if (value < 0 && (!numeral._.includes(symbols.before, '-') && !numeral._.includes(symbols.before, '('))) {
  692. symbols.before = '-' + symbols.before;
  693. }
  694. // loop through each before symbol
  695. for (i = 0; i < symbols.before.length; i++) {
  696. symbol = symbols.before[i];
  697. switch (symbol) {
  698. case '$':
  699. output = numeral._.insert(output, locale.currency.symbol, i);
  700. break;
  701. case ' ':
  702. output = numeral._.insert(output, ' ', i + locale.currency.symbol.length - 1);
  703. break;
  704. }
  705. }
  706. // loop through each after symbol
  707. for (i = symbols.after.length - 1; i >= 0; i--) {
  708. symbol = symbols.after[i];
  709. switch (symbol) {
  710. case '$':
  711. output = i === symbols.after.length - 1 ? output + locale.currency.symbol : numeral._.insert(output, locale.currency.symbol, -(symbols.after.length - (1 + i)));
  712. break;
  713. case ' ':
  714. output = i === symbols.after.length - 1 ? output + ' ' : numeral._.insert(output, ' ', -(symbols.after.length - (1 + i) + locale.currency.symbol.length - 1));
  715. break;
  716. }
  717. }
  718. return output;
  719. }
  720. });
  721. })();
  722. (function() {
  723. numeral.register('format', 'exponential', {
  724. regexps: {
  725. format: /(e\+|e-)/,
  726. unformat: /(e\+|e-)/
  727. },
  728. format: function(value, format, roundingFunction) {
  729. var output,
  730. exponential = typeof value === 'number' && !numeral._.isNaN(value) ? value.toExponential() : '0e+0',
  731. parts = exponential.split('e');
  732. format = format.replace(/e[\+|\-]{1}0/, '');
  733. output = numeral._.numberToFormat(Number(parts[0]), format, roundingFunction);
  734. return output + 'e' + parts[1];
  735. },
  736. unformat: function(string) {
  737. var parts = numeral._.includes(string, 'e+') ? string.split('e+') : string.split('e-'),
  738. value = Number(parts[0]),
  739. power = Number(parts[1]);
  740. power = numeral._.includes(string, 'e-') ? power *= -1 : power;
  741. function cback(accum, curr, currI, O) {
  742. var corrFactor = numeral._.correctionFactor(accum, curr),
  743. num = (accum * corrFactor) * (curr * corrFactor) / (corrFactor * corrFactor);
  744. return num;
  745. }
  746. return numeral._.reduce([value, Math.pow(10, power)], cback, 1);
  747. }
  748. });
  749. })();
  750. (function() {
  751. numeral.register('format', 'ordinal', {
  752. regexps: {
  753. format: /(o)/
  754. },
  755. format: function(value, format, roundingFunction) {
  756. var locale = numeral.locales[numeral.options.currentLocale],
  757. output,
  758. ordinal = numeral._.includes(format, ' o') ? ' ' : '';
  759. // check for space before
  760. format = format.replace(/\s?o/, '');
  761. ordinal += locale.ordinal(value);
  762. output = numeral._.numberToFormat(value, format, roundingFunction);
  763. return output + ordinal;
  764. }
  765. });
  766. })();
  767. (function() {
  768. numeral.register('format', 'percentage', {
  769. regexps: {
  770. format: /(%)/,
  771. unformat: /(%)/
  772. },
  773. format: function(value, format, roundingFunction) {
  774. var space = numeral._.includes(format, ' %') ? ' ' : '',
  775. output;
  776. if (numeral.options.scalePercentBy100) {
  777. value = value * 100;
  778. }
  779. // check for space before %
  780. format = format.replace(/\s?\%/, '');
  781. output = numeral._.numberToFormat(value, format, roundingFunction);
  782. if (numeral._.includes(output, ')')) {
  783. output = output.split('');
  784. output.splice(-1, 0, space + '%');
  785. output = output.join('');
  786. } else {
  787. output = output + space + '%';
  788. }
  789. return output;
  790. },
  791. unformat: function(string) {
  792. var number = numeral._.stringToNumber(string);
  793. if (numeral.options.scalePercentBy100) {
  794. return number * 0.01;
  795. }
  796. return number;
  797. }
  798. });
  799. })();
  800. (function() {
  801. numeral.register('format', 'time', {
  802. regexps: {
  803. format: /(:)/,
  804. unformat: /(:)/
  805. },
  806. format: function(value, format, roundingFunction) {
  807. var hours = Math.floor(value / 60 / 60),
  808. minutes = Math.floor((value - (hours * 60 * 60)) / 60),
  809. seconds = Math.round(value - (hours * 60 * 60) - (minutes * 60));
  810. return hours + ':' + (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds);
  811. },
  812. unformat: function(string) {
  813. var timeArray = string.split(':'),
  814. seconds = 0;
  815. // turn hours and minutes into seconds and add them all up
  816. if (timeArray.length === 3) {
  817. // hours
  818. seconds = seconds + (Number(timeArray[0]) * 60 * 60);
  819. // minutes
  820. seconds = seconds + (Number(timeArray[1]) * 60);
  821. // seconds
  822. seconds = seconds + Number(timeArray[2]);
  823. } else if (timeArray.length === 2) {
  824. // minutes
  825. seconds = seconds + (Number(timeArray[0]) * 60);
  826. // seconds
  827. seconds = seconds + Number(timeArray[1]);
  828. }
  829. return Number(seconds);
  830. }
  831. });
  832. })();
  833. return numeral;
  834. }));